From 4bed3a6906e31f581a2b7e96637b3bebc0054326 Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Fri, 16 Aug 2024 08:39:51 -0700 Subject: [PATCH 1/6] Add a basic prettierrc config --- .prettierrc.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000000..6de870e7fe0 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "es5" +} From ab1515833229ca2970d6cac3cbda3753149919d1 Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Fri, 16 Aug 2024 09:29:13 -0700 Subject: [PATCH 2/6] Extend tools/cross/format.py to handle JS too --- .github/workflows/lint.yml | 34 +++++++ .prettierignore | 1 + package.json | 3 +- tools/cross/format.py | 184 +++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .prettierignore create mode 100644 tools/cross/format.py diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000000..29cce9f9836 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,34 @@ +name: Lint + +on: + pull_request: + push: + branches: + - main + +jobs: + lint: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + show-progress: false + - name: Setup Linux + run: | + export DEBIAN_FRONTEND=noninteractive + wget https://apt.llvm.org/llvm.sh + sed -i '/apt-get install/d' llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 18 + sudo apt-get install -y --no-install-recommends clang-format-18 + - name: Install pnpm + uses: pnpm/action-setup@v4 + # The pnpm version will be determined by the `packageManager` field in `.npmrc` + - name: Install project deps with pnpm + run: | + pnpm i + - name: Lint + run: | + python3 ./tools/cross/format.py --check + env: + CLANG_FORMAT: clang-format-18 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..73498bef083 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +samples/nodejs-compat-streams-split2/split2.js diff --git a/package.json b/package.json index 0a000e9ae49..6a8ebb6a933 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "name": "@cloudflare/workerd-root", "private": true, "scripts": { - "lint": "eslint types/src" + "lint": "eslint types/src", + "format": "prettier" }, "dependencies": { "capnp-ts": "^0.7.0", diff --git a/tools/cross/format.py b/tools/cross/format.py new file mode 100644 index 00000000000..1ba2e27fa25 --- /dev/null +++ b/tools/cross/format.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +import logging +import os +import re +import subprocess +from argparse import ArgumentParser, Namespace +from typing import List, Optional, Tuple, Set, Callable +from dataclasses import dataclass + + +CLANG_FORMAT = os.environ.get("CLANG_FORMAT", "clang-format") +PRETTIER = os.environ.get("PRETTIER", "node_modules/.bin/prettier") + + +def parse_args() -> Namespace: + parser = ArgumentParser() + parser.add_argument( + "--check", + help="only check for files requiring formatting; don't actually format them", + action="store_true", + default=False, + ) + subparsers = parser.add_subparsers(dest="subcommand") + git_parser = subparsers.add_parser( + "git", help="Apply format to changes tracked by git" + ) + git_parser.add_argument( + "--source", + help="consider files modified in the specified commit-ish; if not specified, defaults to all changes in the working directory", + type=str, + required=False, + default=None, + ) + git_parser.add_argument( + "--target", + help="consider files modified since the specified commit-ish; defaults to HEAD", + type=str, + required=False, + default="HEAD", + ) + git_parser.add_argument( + "--staged", + help="consider files with staged modifications only", + action="store_true", + default=False, + ) + options = parser.parse_args() + if ( + options.subcommand == "git" + and options.staged + and (options.source is not None or options.target != "HEAD") + ): + logging.error( + "--staged cannot be used with --source or --target; use --staged with --source=HEAD" + ) + exit(1) + return options + + +def check_clang_format() -> bool: + try: + # Run clang-format with --version to check its version + output = subprocess.check_output([CLANG_FORMAT, "--version"], encoding="utf-8") + major, _, _ = re.search(r"version\s*(\d+)\.(\d+)\.(\d+)", output).groups() + if int(major) < 18: + logging.error("clang-format version must be at least 18.0.0") + exit(1) + except FileNotFoundError: + # Clang-format is not in the PATH + logging.error("clang-format not found in the PATH") + exit(1) + + +def filter_files_by_exts(files: List[str], dir_path: str, exts: Tuple[str, ...]) -> List[str]: + return [file for file in files + if file.startswith(dir_path + "/") and file.endswith(exts)] + + +def clang_format(files: List[str], check: bool = False) -> bool: + if check: + result = subprocess.run( + [CLANG_FORMAT, "--verbose", "--dry-run", "--Werror"] + files) + return result.returncode == 0 + else: + subprocess.run([CLANG_FORMAT, "--verbose", "-i"] + files) + return True + + +def prettier(files: List[str], check: bool = False) -> bool: + if check: + result = subprocess.run([PRETTIER, "--check"] + files) + return result.returncode == 0 + else: + subprocess.run([PRETTIER, "--write"] + files) + return True + + +def git_get_modified_files( + target: str, source: Optional[str], staged: bool +) -> List[str]: + if staged: + files_in_diff = subprocess.check_output( + ["git", "diff", "--diff-filter=d", "--name-only", "--cached"], + encoding="utf-8", + ).splitlines() + return files_in_diff + else: + merge_base = subprocess.check_output( + ["git", "merge-base", target, source or "HEAD"], encoding="utf-8" + ).strip() + files_in_diff = subprocess.check_output( + ["git", "diff", "--diff-filter=d", "--name-only", merge_base] + + ([source] if source else []), + encoding="utf-8", + ).splitlines() + return files_in_diff + + +def git_get_all_files() -> List[str]: + return subprocess.check_output( + ["git", "ls-files", "--cached", "--others", "--exclude-standard"], + encoding="utf-8" + ).splitlines() + + +@dataclass +class FormatConfig: + directory: str + extensions: Tuple[str, ...] + formatter: Callable[[List[str], bool], bool] + + +FORMATTERS = [ + # TODO: Re-enable once C++ PR is ready: https://github.com/cloudflare/workerd/pull/2505 + #FormatConfig( + # directory='src/workerd', + # extensions=('.c++', '.h'), + # formatter=clang_format + #), + FormatConfig( + directory='src', + extensions=('.js', '.ts', '.cjs', '.ejs', '.mjs'), + formatter=prettier + ), + FormatConfig( + directory='src', + extensions=('.json', ), + formatter=prettier + ), + # TODO: lint bazel files +] + + +def format(config: FormatConfig, files: List[str], check: bool) -> bool: + matching_files = filter_files_by_exts(files, config.directory, config.extensions) + + if not matching_files: + return True + + return config.formatter(matching_files, check) + + +def main(): + options = parse_args() + check_clang_format() + if options.subcommand == "git": + files = set(git_get_modified_files( + options.target, options.source, options.staged + )) + else: + files = git_get_all_files() + + all_ok = True + + for config in FORMATTERS: + all_ok &= format(config, files, options.check) + + if not all_ok: + logging.error("Code has linting issues. Fix with python ./tools/cross/format.py") + exit(1) + +if __name__ == "__main__": + main() From 0523bf8b36a937348f1bb79eceda2463a5c220b5 Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Tue, 20 Aug 2024 10:44:16 -0700 Subject: [PATCH 3/6] Bulk reformat JS, TS, JSON files --- .../worker.js | 1 + src/cloudflare/.eslintrc.json | 62 +- src/cloudflare/ai.ts | 6 +- src/cloudflare/internal/ai-api.ts | 108 +- src/cloudflare/internal/d1-api.ts | 212 +- src/cloudflare/internal/images-api.ts | 38 +- src/cloudflare/internal/images.d.ts | 36 +- src/cloudflare/internal/sockets.d.ts | 31 +- .../internal/test/ai/ai-api-test.js | 176 +- src/cloudflare/internal/test/ai/ai-mock.js | 98 +- .../internal/test/d1/d1-api-test.js | 88 +- src/cloudflare/internal/test/d1/d1-mock.js | 64 +- .../internal/test/images/images-api-test.js | 38 +- .../test/images/images-upstream-mock.js | 28 +- .../test/vectorize/vectorize-api-test.js | 84 +- .../internal/test/vectorize/vectorize-mock.js | 82 +- src/cloudflare/internal/vectorize-api.ts | 91 +- src/cloudflare/internal/vectorize.d.ts | 12 +- src/cloudflare/internal/workers.d.ts | 3 +- src/cloudflare/sockets.ts | 3 +- src/cloudflare/tsconfig.json | 2 +- src/cloudflare/vectorize.ts | 22 +- src/node/.eslintrc.json | 10 +- src/node/_stream_duplex.js | 4 + src/node/_stream_readable.js | 4 + src/node/_stream_writable.js | 4 + src/node/crypto.ts | 48 +- src/node/diagnostics_channel.ts | 252 +- src/node/internal/async_hooks.d.ts | 18 +- src/node/internal/buffer.d.ts | 62 +- src/node/internal/constants.ts | 2 +- src/node/internal/crypto.d.ts | 155 +- src/node/internal/crypto_dh.ts | 144 +- src/node/internal/crypto_hash.ts | 150 +- src/node/internal/crypto_hkdf.ts | 76 +- src/node/internal/crypto_keys.ts | 243 +- src/node/internal/crypto_pbkdf2.ts | 73 +- src/node/internal/crypto_random.ts | 284 +- src/node/internal/crypto_scrypt.ts | 96 +- src/node/internal/crypto_spkac.ts | 34 +- src/node/internal/crypto_util.ts | 60 +- src/node/internal/crypto_x509.ts | 59 +- src/node/internal/debuglog.ts | 42 +- src/node/internal/diagnostics_channel.d.ts | 34 +- src/node/internal/events.ts | 489 +- src/node/internal/internal_assert.ts | 343 +- src/node/internal/internal_assertionerror.ts | 199 +- src/node/internal/internal_buffer.ts | 1811 +- src/node/internal/internal_comparisons.ts | 318 +- src/node/internal/internal_diffs.ts | 128 +- src/node/internal/internal_errors.ts | 202 +- src/node/internal/internal_inspect.ts | 1241 +- src/node/internal/internal_path.ts | 225 +- src/node/internal/internal_stringdecoder.ts | 50 +- src/node/internal/internal_types.ts | 5 +- src/node/internal/internal_utils.ts | 100 +- src/node/internal/internal_zlib.ts | 33 +- src/node/internal/mock.js | 51 +- src/node/internal/process.ts | 106 +- src/node/internal/streams_adapters.js | 357 +- src/node/internal/streams_compose.js | 38 +- src/node/internal/streams_duplex.js | 185 +- src/node/internal/streams_legacy.js | 20 +- src/node/internal/streams_pipeline.js | 89 +- src/node/internal/streams_promises.js | 19 +- src/node/internal/streams_readable.js | 466 +- src/node/internal/streams_transform.d.ts | 356 +- src/node/internal/streams_transform.js | 38 +- src/node/internal/streams_util.js | 282 +- src/node/internal/streams_writable.js | 159 +- src/node/internal/util.d.ts | 23 +- src/node/internal/validators.ts | 120 +- src/node/internal/web_crypto.d.ts | 2 +- src/node/path.ts | 5 +- src/node/stream.js | 4 +- src/node/stream/consumers.js | 9 +- src/node/stream/web.js | 20 +- src/node/tsconfig.json | 6 +- src/node/util.ts | 89 +- src/node/zlib.ts | 7 +- src/pyodide/internal/builtin_wrappers.ts | 12 +- src/pyodide/internal/jaeger.ts | 2 +- src/pyodide/internal/loadPackage.ts | 24 +- src/pyodide/internal/metadata.ts | 8 +- src/pyodide/internal/metadatafs.ts | 15 +- src/pyodide/internal/python.ts | 47 +- src/pyodide/internal/readOnlyFS.ts | 11 +- src/pyodide/internal/setupPackages.ts | 50 +- src/pyodide/internal/snapshot.ts | 136 +- src/pyodide/internal/tar.ts | 24 +- src/pyodide/internal/tarfs.ts | 12 +- src/pyodide/internal/topLevelEntropy/lib.ts | 34 +- src/pyodide/internal/util.ts | 12 +- src/pyodide/python-entrypoint-helper.ts | 88 +- src/pyodide/python-entrypoint.js | 2 +- src/pyodide/types/FS.d.ts | 47 +- src/pyodide/types/Module.d.ts | 3 +- src/pyodide/types/Pyodide.d.ts | 4 +- src/pyodide/types/artifacts.d.ts | 4 +- src/pyodide/types/emscripten.d.ts | 6 +- src/pyodide/types/limiter.d.ts | 1 - src/pyodide/types/packages_tar_reader.d.ts | 1 - src/pyodide/types/pyodide-bucket.d.ts | 2 +- src/pyodide/types/pyodide-lock.d.ts | 4 +- src/pyodide/types/pyodide.asm.d.ts | 4 +- src/pyodide/types/python_stdlib.zip.d.ts | 2 +- .../types/runtime-generated/metadata.d.ts | 2 +- src/workerd/api/actor-alarms-delete-test.js | 23 +- src/workerd/api/actor-alarms-test.js | 22 +- src/workerd/api/analytics-engine-test.js | 22 +- src/workerd/api/gpu/webgpu-buffer-test.js | 18 +- src/workerd/api/gpu/webgpu-compute-test.js | 42 +- src/workerd/api/gpu/webgpu-errors-test.js | 21 +- src/workerd/api/gpu/webgpu-windowless-test.js | 36 +- src/workerd/api/gpu/webgpu-write-test.js | 10 +- src/workerd/api/http-standard-test.js | 17 +- src/workerd/api/http-test-ts.ts | 70 +- src/workerd/api/http-test.js | 172 +- src/workerd/api/node/tests/assert-test.js | 234 +- .../api/node/tests/buffer-nodejs-test.js | 2962 +-- src/workerd/api/node/tests/crypto_dh-test.js | 173 +- .../api/node/tests/crypto_hash-test.js | 185 +- .../api/node/tests/crypto_hkdf-test.js | 114 +- .../api/node/tests/crypto_hmac-test.js | 477 +- .../api/node/tests/crypto_keys-test.js | 141 +- .../api/node/tests/crypto_pbkdf2-test.js | 286 +- .../api/node/tests/crypto_random-test.js | 258 +- .../api/node/tests/crypto_scrypt-test.js | 83 +- .../api/node/tests/crypto_spkac-test.js | 25 +- .../api/node/tests/crypto_x509-test.js | 136 +- .../node/tests/diagnostics-channel-test.js | 27 +- src/workerd/api/node/tests/mimetype-test.js | 19 +- .../api/node/tests/node-compat-v2-test.js | 30 +- src/workerd/api/node/tests/path-test.js | 156 +- src/workerd/api/node/tests/streams-test.js | 5528 +++-- .../api/node/tests/string-decoder-test.js | 299 +- .../api/node/tests/util-nodejs-test.js | 2035 +- .../api/node/tests/zlib-nodejs-test.js | 346 +- src/workerd/api/queue-test.js | 281 +- src/workerd/api/rtti-test.js | 10 +- src/workerd/api/sql-test.js | 943 +- ...entitytransformstream-backpressure-test.js | 11 +- src/workerd/api/streams/streams-test.js | 68 +- .../api/tests/abort-internal-streams-test.js | 2 +- src/workerd/api/tests/abortable-fetch-test.js | 37 +- src/workerd/api/tests/abortsignal-test.js | 34 +- src/workerd/api/tests/actor-stub-test.js | 30 +- src/workerd/api/tests/als-only-test.js | 7 +- src/workerd/api/tests/als-test.js | 24 +- src/workerd/api/tests/blob-test.js | 173 +- src/workerd/api/tests/blob2-test.js | 12 +- src/workerd/api/tests/commonjs-module-test.js | 2 +- src/workerd/api/tests/crypto-extras-test.js | 131 +- .../api/tests/crypto-impl-asymmetric-test.js | 57 +- src/workerd/api/tests/crypto-streams-test.js | 55 +- src/workerd/api/tests/data-url-fetch-test.js | 12 +- src/workerd/api/tests/encoding-test.js | 827 +- src/workerd/api/tests/events-test.js | 144 +- src/workerd/api/tests/eventsource-test.js | 255 +- .../api/tests/form-data-legacy-test.js | 36 +- src/workerd/api/tests/form-data-test.js | 496 +- src/workerd/api/tests/global-scope-test.js | 331 +- src/workerd/api/tests/htmlrewriter-test.js | 448 +- src/workerd/api/tests/js-rpc-flag.js | 11 +- src/workerd/api/tests/js-rpc-test.js | 842 +- src/workerd/api/tests/memory-cache-test.js | 112 +- src/workerd/api/tests/module-test.js | 2 +- .../api/tests/navigator-beacon-test.js | 26 +- src/workerd/api/tests/reporterror-test.js | 7 +- src/workerd/api/tests/response-json.js | 52 +- src/workerd/api/tests/scheduler-test.js | 12 +- src/workerd/api/tests/streams-test.js | 122 +- src/workerd/api/tests/unsafe-test.js | 28 +- src/workerd/api/tests/url-test.js | 17654 ++++++++-------- .../api/tests/websocket-hibernation.js | 42 +- src/workerd/api/tsconfig.json | 2 +- src/workerd/jsg/resource-test-bootstrap.js | 4 +- src/workerd/jsg/resource-test-builtin.js | 2 +- .../server/tests/extensions/binding.js | 7 +- .../tests/extensions/extensions-test.js | 49 +- .../tests/extensions/internal-module.js | 4 +- src/workerd/server/tests/extensions/module.js | 4 +- src/workerd/server/tests/inspector/driver.mjs | 34 +- src/workerd/server/tests/inspector/index.mjs | 21 +- src/workerd/server/tests/server-harness.mjs | 59 +- .../server/tests/unsafe-eval/module.js | 4 +- .../tests/unsafe-eval/unsafe-eval-test.js | 6 +- .../tests/unsafe-module/unsafe-module-test.js | 60 +- src/workerd/tests/performance-test.js | 3 +- 189 files changed, 25925 insertions(+), 22928 deletions(-) diff --git a/samples/nodejs-compat-diagnosticschannel/worker.js b/samples/nodejs-compat-diagnosticschannel/worker.js index cd56366cb98..0808a2ce745 100644 --- a/samples/nodejs-compat-diagnosticschannel/worker.js +++ b/samples/nodejs-compat-diagnosticschannel/worker.js @@ -32,6 +32,7 @@ export default { async fetch(request) { doSomething(); + // prettier-ignore console.log(c.runStores(1, (...args) => { console.log(this, ...args, als1.getStore(), als2.getStore()); return 1; diff --git a/src/cloudflare/.eslintrc.json b/src/cloudflare/.eslintrc.json index 9c906731c97..c907f53af0d 100644 --- a/src/cloudflare/.eslintrc.json +++ b/src/cloudflare/.eslintrc.json @@ -1,41 +1,41 @@ { "env": { - "es2022": true, - "worker": true + "es2022": true, + "worker": true }, "extends": [ - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@typescript-eslint/strict" + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:@typescript-eslint/strict" ], "overrides": [], "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "project": "src/cloudflare/tsconfig.json" - }, + "ecmaVersion": "latest", + "sourceType": "module", + "project": "src/cloudflare/tsconfig.json" + }, "rules": { - "@typescript-eslint/explicit-function-return-type": "error", - "@typescript-eslint/explicit-member-accessibility": "error", - "@typescript-eslint/explicit-module-boundary-types": "error", - "@typescript-eslint/no-require-imports": "error", - "@typescript-eslint/prefer-enum-initializers": "error", - "@typescript-eslint/type-annotation-spacing": "error", - "@typescript-eslint/restrict-template-expressions": "warn", - "@typescript-eslint/no-non-null-assertion": "warn", - "@typescript-eslint/no-extraneous-class": "off", - "@typescript-eslint/unified-signatures": "off", - "@typescript-eslint/no-unused-vars": [ - "error", - { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } - ] + "@typescript-eslint/explicit-function-return-type": "error", + "@typescript-eslint/explicit-member-accessibility": "error", + "@typescript-eslint/explicit-module-boundary-types": "error", + "@typescript-eslint/no-require-imports": "error", + "@typescript-eslint/prefer-enum-initializers": "error", + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/restrict-template-expressions": "warn", + "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/no-extraneous-class": "off", + "@typescript-eslint/unified-signatures": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "args": "all", + "argsIgnorePattern": "^_", + "caughtErrors": "all", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ] } } diff --git a/src/cloudflare/ai.ts b/src/cloudflare/ai.ts index c400cb4ef99..3ea02267a4c 100644 --- a/src/cloudflare/ai.ts +++ b/src/cloudflare/ai.ts @@ -2,4 +2,8 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -export { AiOptions, InferenceUpstreamError, Ai } from 'cloudflare-internal:ai-api'; +export { + AiOptions, + InferenceUpstreamError, + Ai, +} from 'cloudflare-internal:ai-api'; diff --git a/src/cloudflare/internal/ai-api.ts b/src/cloudflare/internal/ai-api.ts index 4ac7d9db045..a06b4995058 100644 --- a/src/cloudflare/internal/ai-api.ts +++ b/src/cloudflare/internal/ai-api.ts @@ -3,26 +3,27 @@ // https://opensource.org/licenses/Apache-2.0 interface Fetcher { - fetch: typeof fetch + fetch: typeof fetch; } interface AiError { - internalCode: number - message: string - name: string - description: string + internalCode: number; + message: string; + name: string; + description: string; } -export type SessionOptions = { // Deprecated, do not use this +export type SessionOptions = { + // Deprecated, do not use this extraHeaders?: object; -} +}; export type GatewayOptions = { id: string; - cacheTtl?: number - skipCache?: boolean + cacheTtl?: number; + skipCache?: boolean; metadata?: Record; -} +}; export type AiOptions = { gateway?: GatewayOptions; @@ -33,17 +34,17 @@ export type AiOptions = { * @deprecated this option is deprecated, do not use this */ sessionOptions?: SessionOptions; -} +}; export class InferenceUpstreamError extends Error { - public constructor(message: string, name = "InferenceUpstreamError") { + public constructor(message: string, name = 'InferenceUpstreamError') { super(message); this.name = name; } } export class Ai { - private readonly fetcher: Fetcher + private readonly fetcher: Fetcher; /* * @deprecated this option is deprecated, do not use this @@ -54,11 +55,14 @@ export class Ai { public lastRequestId: string | null = null; public constructor(fetcher: Fetcher) { - this.fetcher = fetcher + this.fetcher = fetcher; } - public async fetch(input: RequestInfo | URL, init?: RequestInit): Promise { - return this.fetcher.fetch(input, init) + public async fetch( + input: RequestInfo | URL, + init?: RequestInit + ): Promise { + return this.fetcher.fetch(input, init); } public async run( @@ -67,73 +71,83 @@ export class Ai { options: AiOptions = {} ): Promise | object | null> { this.options = options; - this.lastRequestId = ""; + this.lastRequestId = ''; // This removes some unwanted options from getting sent in the body - const cleanedOptions = (({ prefix, extraHeaders, sessionOptions, ...object }): object => object)(this.options || {}); + const cleanedOptions = (({ + prefix, + extraHeaders, + sessionOptions, + ...object + }): object => object)(this.options || {}); const body = JSON.stringify({ inputs, - options: cleanedOptions + options: cleanedOptions, }); const fetchOptions = { - method: "POST", + method: 'POST', body: body, headers: { ...(this.options?.sessionOptions?.extraHeaders || {}), ...(this.options?.extraHeaders || {}), - "content-type": "application/json", - "cf-consn-sdk-version": "2.0.0", - "cf-consn-model-id": `${this.options.prefix ? `${this.options.prefix}:` : ""}${model}`, + 'content-type': 'application/json', + 'cf-consn-sdk-version': '2.0.0', + 'cf-consn-model-id': `${this.options.prefix ? `${this.options.prefix}:` : ''}${model}`, }, }; - const res = await this.fetcher.fetch("http://workers-binding.ai/run?version=3", fetchOptions); + const res = await this.fetcher.fetch( + 'http://workers-binding.ai/run?version=3', + fetchOptions + ); - this.lastRequestId = res.headers.get("cf-ai-req-id"); + this.lastRequestId = res.headers.get('cf-ai-req-id'); if (inputs['stream']) { if (!res.ok) { - throw await this._parseError(res) + throw await this._parseError(res); } return res.body; - } else { if (!res.ok || !res.body) { - throw await this._parseError(res) + throw await this._parseError(res); } - const contentType = res.headers.get("content-type"); + const contentType = res.headers.get('content-type'); - if (contentType === "application/json") { - return (await res.json() as object); + if (contentType === 'application/json') { + return (await res.json()) as object; } return res.body; } } - /* - * @deprecated this method is deprecated, do not use this - */ - public getLogs(): string[] { - return [] - } - - private async _parseError(res: Response): Promise { - const content = await res.text() + /* + * @deprecated this method is deprecated, do not use this + */ + public getLogs(): string[] { + return []; + } - try { - const parsedContent = (JSON.parse(content)) as AiError - return new InferenceUpstreamError(`${parsedContent.internalCode}: ${parsedContent.description}`, parsedContent.name); - } catch { - return new InferenceUpstreamError(content); - } + private async _parseError(res: Response): Promise { + const content = await res.text(); + + try { + const parsedContent = JSON.parse(content) as AiError; + return new InferenceUpstreamError( + `${parsedContent.internalCode}: ${parsedContent.description}`, + parsedContent.name + ); + } catch { + return new InferenceUpstreamError(content); } + } } export default function makeBinding(env: { fetcher: Fetcher }): Ai { - return new Ai(env.fetcher) + return new Ai(env.fetcher); } diff --git a/src/cloudflare/internal/d1-api.ts b/src/cloudflare/internal/d1-api.ts index 4d3386c8793..482c9786d42 100644 --- a/src/cloudflare/internal/d1-api.ts +++ b/src/cloudflare/internal/d1-api.ts @@ -3,64 +3,64 @@ // https://opensource.org/licenses/Apache-2.0 interface Fetcher { - fetch: typeof fetch + fetch: typeof fetch; } type D1Response = { - success: true - meta: Record - error?: never -} + success: true; + meta: Record; + error?: never; +}; type D1Result = D1Response & { - results: T[] -} + results: T[]; +}; type D1RawOptions = { - columnNames?: boolean -} + columnNames?: boolean; +}; type D1UpstreamFailure = { - results?: never - error: string - success: false - meta: Record -} + results?: never; + error: string; + success: false; + meta: Record; +}; type D1RowsColumns = D1Response & { results: { - columns: string[] - rows: T[][] - } -} + columns: string[]; + rows: T[][]; + }; +}; type D1UpstreamSuccess = | D1Result | D1Response - | D1RowsColumns + | D1RowsColumns; -type D1UpstreamResponse = D1UpstreamSuccess | D1UpstreamFailure +type D1UpstreamResponse = D1UpstreamSuccess | D1UpstreamFailure; type D1ExecResult = { - count: number - duration: number -} + count: number; + duration: number; +}; type SQLError = { - error: string -} + error: string; +}; -type ResultsFormat = 'ARRAY_OF_OBJECTS' | 'ROWS_AND_COLUMNS' | 'NONE' +type ResultsFormat = 'ARRAY_OF_OBJECTS' | 'ROWS_AND_COLUMNS' | 'NONE'; class D1Database { - private readonly fetcher: Fetcher + private readonly fetcher: Fetcher; public constructor(fetcher: Fetcher) { - this.fetcher = fetcher + this.fetcher = fetcher; } public prepare(query: string): D1PreparedStatement { - return new D1PreparedStatement(this, query) + return new D1PreparedStatement(this, query); } // DEPRECATED, TO BE REMOVED WITH NEXT BREAKING CHANGE @@ -70,20 +70,20 @@ class D1Database { headers: { 'content-type': 'application/json', }, - }) + }); if (response.status !== 200) { try { - const err = (await response.json()) as SQLError + const err = (await response.json()) as SQLError; throw new Error(`D1_DUMP_ERROR: ${err.error}`, { cause: new Error(err.error), - }) + }); } catch { throw new Error(`D1_DUMP_ERROR: Status + ${response.status}`, { cause: new Error(`Status ${response.status}`), - }) + }); } } - return await response.arrayBuffer() + return await response.arrayBuffer(); } public async batch( @@ -94,19 +94,19 @@ class D1Database { statements.map((s: D1PreparedStatement) => s.statement), statements.map((s: D1PreparedStatement) => s.params), 'ROWS_AND_COLUMNS' - )) as D1UpstreamSuccess[] - return exec.map(toArrayOfObjects) + )) as D1UpstreamSuccess[]; + return exec.map(toArrayOfObjects); } public async exec(query: string): Promise { - const lines = query.trim().split('\n') - const _exec = await this._send('/execute', lines, [], 'NONE') - const exec = Array.isArray(_exec) ? _exec : [_exec] + const lines = query.trim().split('\n'); + const _exec = await this._send('/execute', lines, [], 'NONE'); + const exec = Array.isArray(_exec) ? _exec : [_exec]; const error = exec .map((r) => { - return r.error ? 1 : 0 + return r.error ? 1 : 0; }) - .indexOf(1) + .indexOf(1); if (error !== -1) { throw new Error( `D1_EXEC_ERROR: Error in line ${error + 1}: ${lines[error]}: ${ @@ -117,14 +117,14 @@ class D1Database { `Error in line ${error + 1}: ${lines[error]}: ${exec[error]?.error}` ), } - ) + ); } else { return { count: exec.length, duration: exec.reduce((p, c) => { - return p + (c.meta['duration'] as number) + return p + (c.meta['duration'] as number); }, 0), - } + }; } } @@ -134,14 +134,14 @@ class D1Database { params: unknown[], resultsFormat: ResultsFormat ): Promise[] | D1UpstreamSuccess> { - const results = await this._send(endpoint, query, params, resultsFormat) - const firstResult = firstIfArray(results) + const results = await this._send(endpoint, query, params, resultsFormat); + const firstResult = firstIfArray(results); if (!firstResult.success) { throw new Error(`D1_ERROR: ${firstResult.error}`, { cause: new Error(firstResult.error), - }) + }); } else { - return results as D1UpstreamSuccess[] | D1UpstreamSuccess + return results as D1UpstreamSuccess[] | D1UpstreamSuccess; } } @@ -155,60 +155,60 @@ class D1Database { const body = JSON.stringify( Array.isArray(query) ? query.map((s: string, index: number) => { - return { sql: s, params: params[index] } + return { sql: s, params: params[index] }; }) : { sql: query, params: params, } - ) + ); - const url = new URL(endpoint, 'http://d1') - url.searchParams.set('resultsFormat', resultsFormat) + const url = new URL(endpoint, 'http://d1'); + url.searchParams.set('resultsFormat', resultsFormat); const response = await this.fetcher.fetch(url.href, { method: 'POST', headers: { 'content-type': 'application/json', }, body, - }) + }); try { const answer = await toJson< D1UpstreamResponse[] | D1UpstreamResponse - >(response) + >(response); if (Array.isArray(answer)) { - return answer.map((r: D1UpstreamResponse) => mapD1Result(r)) + return answer.map((r: D1UpstreamResponse) => mapD1Result(r)); } else { - return mapD1Result(answer) + return mapD1Result(answer); } } catch (_e: unknown) { - const e = _e as Error + const e = _e as Error; const message = (e.cause as Error | undefined)?.message || e.message || - 'Something went wrong' + 'Something went wrong'; throw new Error(`D1_ERROR: ${message}`, { cause: new Error(message), - }) + }); } } } class D1PreparedStatement { - private readonly database: D1Database - public readonly statement: string - public readonly params: unknown[] + private readonly database: D1Database; + public readonly statement: string; + public readonly params: unknown[]; public constructor( database: D1Database, statement: string, values?: unknown[] ) { - this.database = database - this.statement = statement - this.params = values || [] + this.database = database; + this.statement = statement; + this.params = values || []; } public bind(...values: unknown[]): D1PreparedStatement { @@ -216,28 +216,28 @@ class D1PreparedStatement { const transformedValues = values.map((r: unknown): unknown => { const rType = typeof r; if (rType === 'number' || rType === 'string') { - return r + return r; } else if (rType === 'boolean') { return r ? 1 : 0; } else if (rType === 'object') { // nulls are objects in javascript - if (r == null) return r + if (r == null) return r; // arrays with uint8's are good if ( Array.isArray(r) && r.every((b: unknown) => { - return typeof b == 'number' && b >= 0 && b < 256 + return typeof b == 'number' && b >= 0 && b < 256; }) ) - return r as unknown[] + return r as unknown[]; // convert ArrayBuffer to array if (r instanceof ArrayBuffer) { - return Array.from(new Uint8Array(r)) + return Array.from(new Uint8Array(r)); } // convert view to array if (ArrayBuffer.isView(r)) { // For some reason TS doesn't think this is valid, but it is! - return Array.from(r as unknown as ArrayLike) + return Array.from(r as unknown as ArrayLike); } } @@ -246,17 +246,17 @@ class D1PreparedStatement { { cause: new Error(`Type '${rType}' not supported for value '${r}'`), } - ) - }) + ); + }); return new D1PreparedStatement( this.database, this.statement, transformedValues - ) + ); } - public async first(colName: string): Promise - public async first>(): Promise + public async first(colName: string): Promise; + public async first>(): Promise; public async first( colName?: string ): Promise | T | null> { @@ -267,22 +267,22 @@ class D1PreparedStatement { this.params, 'ROWS_AND_COLUMNS' ) - ) + ); - const results = toArrayOfObjects(info).results - const hasResults = results.length > 0 - if (!hasResults) return null + const results = toArrayOfObjects(info).results; + const hasResults = results.length > 0; + if (!hasResults) return null; - const firstResult = results[0]! + const firstResult = results[0]!; if (colName !== undefined) { if (hasResults && firstResult[colName] === undefined) { throw new Error(`D1_COLUMN_NOTFOUND: Column not found (${colName})`, { cause: new Error('Column not found'), - }) + }); } - return firstResult[colName]! + return firstResult[colName]!; } else { - return firstResult + return firstResult; } } @@ -294,7 +294,7 @@ class D1PreparedStatement { this.params, 'NONE' ) - ) + ); } public async all>(): Promise> { @@ -307,7 +307,7 @@ class D1PreparedStatement { 'ROWS_AND_COLUMNS' ) ) - ) + ); } public async raw(options?: D1RawOptions): Promise { @@ -318,35 +318,35 @@ class D1PreparedStatement { this.params, 'ROWS_AND_COLUMNS' ) - ) + ); // If no results returned, return empty array - if (!('results' in s)) return [] + if (!('results' in s)) return []; // If ARRAY_OF_OBJECTS returned, extract cells if (Array.isArray(s.results)) { - const raw: T[] = [] + const raw: T[] = []; for (const row of s.results) { if (options?.columnNames && raw.length === 0) { - raw.push(Array.from(Object.keys(row)) as T) + raw.push(Array.from(Object.keys(row)) as T); } const entry = Object.keys(row).map((k) => { - return row[k] - }) - raw.push(entry as T) + return row[k]; + }); + raw.push(entry as T); } - return raw + return raw; } else { // Otherwise, data is already in the correct format return [ ...(options?.columnNames ? [s.results.columns as T] : []), ...(s.results.rows as T[]), - ] + ]; } } } function firstIfArray(results: T | T[]): T { - return Array.isArray(results) ? results[0]! : results + return Array.isArray(results) ? results[0]! : results; } // This shim may be used against an older version of D1 that doesn't support @@ -357,20 +357,20 @@ function toArrayOfObjects(response: D1UpstreamSuccess): D1Result { return { ...response, results: [], - } + }; - const results = response.results + const results = response.results; if (Array.isArray(results)) { - return { ...response, results } + return { ...response, results }; } else { - const { rows, columns } = results + const { rows, columns } = results; return { ...response, results: rows.map( (row) => Object.fromEntries(row.map((cell, i) => [columns[i], cell])) as T ), - } + }; } } @@ -387,18 +387,18 @@ function mapD1Result(result: D1UpstreamResponse): D1UpstreamResponse { success: true, meta: result.meta || {}, ...('results' in result ? { results: result.results } : {}), - } + }; } async function toJson(response: Response): Promise { - const body = await response.text() + const body = await response.text(); try { - return JSON.parse(body) as T + return JSON.parse(body) as T; } catch { - throw new Error(`Failed to parse body as JSON, got: ${body}`) + throw new Error(`Failed to parse body as JSON, got: ${body}`); } } export default function makeBinding(env: { fetcher: Fetcher }): D1Database { - return new D1Database(env.fetcher) + return new D1Database(env.fetcher); } diff --git a/src/cloudflare/internal/images-api.ts b/src/cloudflare/internal/images-api.ts index 8d8dda8b594..6581fdafbf0 100644 --- a/src/cloudflare/internal/images-api.ts +++ b/src/cloudflare/internal/images-api.ts @@ -7,7 +7,7 @@ type Fetcher = { }; type RawInfoResponse = - | { format: "image/svg+xml" } + | { format: 'image/svg+xml' } | { format: string; file_size: number; @@ -19,10 +19,10 @@ class TransformationResultImpl implements TransformationResult { public constructor(private readonly bindingsResponse: Response) {} public contentType(): string { - const contentType = this.bindingsResponse.headers.get("content-type"); + const contentType = this.bindingsResponse.headers.get('content-type'); if (!contentType) { throw new ImagesErrorImpl( - "IMAGES_TRANSFORM_ERROR 9523: No content-type on bindings response", + 'IMAGES_TRANSFORM_ERROR 9523: No content-type on bindings response', 9523 ); } @@ -37,7 +37,7 @@ class TransformationResultImpl implements TransformationResult { public response(): Response { return new Response(this.image(), { headers: { - "content-type": this.contentType(), + 'content-type': this.contentType(), }, }); } @@ -71,34 +71,34 @@ class ImageTransformerImpl implements ImageTransformer { public async output(options: OutputOptions): Promise { if (this.consumed) { throw new ImagesErrorImpl( - "IMAGES_TRANSFORM_ERROR 9525: ImageTransformer consumed; you may only call .output() once", + 'IMAGES_TRANSFORM_ERROR 9525: ImageTransformer consumed; you may only call .output() once', 9525 ); } this.consumed = true; const body = new FormData(); - body.append("image", await streamToBlob(this.stream)); - body.append("output_format", options.format); + body.append('image', await streamToBlob(this.stream)); + body.append('output_format', options.format); if (options.quality !== undefined) { - body.append("output_quality", options.quality.toString()); + body.append('output_quality', options.quality.toString()); } if (options.background !== undefined) { - body.append("background", options.background); + body.append('background', options.background); } - body.append("transforms", JSON.stringify(this.transforms)); + body.append('transforms', JSON.stringify(this.transforms)); const response = await this.fetcher.fetch( - "https://js.images.cloudflare.com/transform", + 'https://js.images.cloudflare.com/transform', { - method: "POST", + method: 'POST', body, } ); - await throwErrorIfErrorResponse("TRANSFORM", response); + await throwErrorIfErrorResponse('TRANSFORM', response); return new TransformationResultImpl(response); } @@ -109,21 +109,21 @@ class ImagesBindingImpl implements ImagesBinding { public async info(stream: ReadableStream): Promise { const body = new FormData(); - body.append("image", await streamToBlob(stream)); + body.append('image', await streamToBlob(stream)); const response = await this.fetcher.fetch( - "https://js.images.cloudflare.com/info", + 'https://js.images.cloudflare.com/info', { - method: "POST", + method: 'POST', body, } ); - await throwErrorIfErrorResponse("INFO", response); + await throwErrorIfErrorResponse('INFO', response); const r = (await response.json()) as RawInfoResponse; - if ("file_size" in r) { + if ('file_size' in r) { return { fileSize: r.file_size, width: r.width, @@ -153,7 +153,7 @@ async function throwErrorIfErrorResponse( operation: string, response: Response ): Promise { - const statusHeader = response.headers.get("cf-images-binding") || ""; + const statusHeader = response.headers.get('cf-images-binding') || ''; const match = /err=(\d+)/.exec(statusHeader); diff --git a/src/cloudflare/internal/images.d.ts b/src/cloudflare/internal/images.d.ts index 0b5f380faf0..49ec2615b62 100644 --- a/src/cloudflare/internal/images.d.ts +++ b/src/cloudflare/internal/images.d.ts @@ -3,7 +3,7 @@ // https://opensource.org/licenses/Apache-2.0 type InfoResponse = - | { format: "image/svg+xml" } + | { format: 'image/svg+xml' } | { format: string; fileSize: number; @@ -12,20 +12,20 @@ type InfoResponse = }; type Transform = { - fit?: "scale-down" | "contain" | "pad" | "squeeze" | "cover" | "crop"; + fit?: 'scale-down' | 'contain' | 'pad' | 'squeeze' | 'cover' | 'crop'; gravity?: - | "left" - | "right" - | "top" - | "bottom" - | "center" - | "auto" - | "entropy" - | "face" + | 'left' + | 'right' + | 'top' + | 'bottom' + | 'center' + | 'auto' + | 'entropy' + | 'face' | { x?: number; y?: number; - mode: "remainder" | "box-center"; + mode: 'remainder' | 'box-center'; }; trim?: { top?: number; @@ -64,13 +64,13 @@ type Transform = { type OutputOptions = { format: - | "image/jpeg" - | "image/png" - | "image/gif" - | "image/webp" - | "image/avif" - | "rgb" - | "rgba"; + | 'image/jpeg' + | 'image/png' + | 'image/gif' + | 'image/webp' + | 'image/avif' + | 'rgb' + | 'rgba'; quality?: number; background?: string; }; diff --git a/src/cloudflare/internal/sockets.d.ts b/src/cloudflare/internal/sockets.d.ts index 76dd06732f6..6fd0317da8d 100644 --- a/src/cloudflare/internal/sockets.d.ts +++ b/src/cloudflare/internal/sockets.d.ts @@ -5,25 +5,28 @@ // Type definitions for c++ implementation. export class Socket { - public readonly readable: unknown - public readonly writable: unknown - public readonly closed: Promise - public close(): Promise - public startTls(options: TlsOptions): Socket + public readonly readable: unknown; + public readonly writable: unknown; + public readonly closed: Promise; + public close(): Promise; + public startTls(options: TlsOptions): Socket; } export type TlsOptions = { - expectedServerHostname?: string -} + expectedServerHostname?: string; +}; export type SocketAddress = { - hostname: string - port: number -} + hostname: string; + port: number; +}; export type SocketOptions = { - secureTransport?: 'off' | 'on' | 'starttls' - allowHalfOpen?: boolean -} + secureTransport?: 'off' | 'on' | 'starttls'; + allowHalfOpen?: boolean; +}; -export function connect(address: string | SocketAddress, options?: SocketOptions): Socket; +export function connect( + address: string | SocketAddress, + options?: SocketOptions +): Socket; diff --git a/src/cloudflare/internal/test/ai/ai-api-test.js b/src/cloudflare/internal/test/ai/ai-api-test.js index e5cd0b66c73..c362b46a707 100644 --- a/src/cloudflare/internal/test/ai/ai-api-test.js +++ b/src/cloudflare/internal/test/ai/ai-api-test.js @@ -2,90 +2,126 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from 'node:assert' +import * as assert from 'node:assert'; export const tests = { - async test(_, env) { - { - // Test ai run response is object - const resp = await env.ai.run('testModel', {prompt: 'test'}) - assert.deepStrictEqual(resp, { response: 'model response' }); + async test(_, env) { + { + // Test ai run response is object + const resp = await env.ai.run('testModel', { prompt: 'test' }); + assert.deepStrictEqual(resp, { response: 'model response' }); - // Test request id is present - assert.deepStrictEqual(env.ai.lastRequestId, '3a1983d7-1ddd-453a-ab75-c4358c91b582'); - } + // Test request id is present + assert.deepStrictEqual( + env.ai.lastRequestId, + '3a1983d7-1ddd-453a-ab75-c4358c91b582' + ); + } - { - // Test ai blob model run response is a blob/stream - const resp = await env.ai.run('blobResponseModel', {prompt: 'test'}) - assert.deepStrictEqual(resp instanceof ReadableStream, true); - } + { + // Test ai blob model run response is a blob/stream + const resp = await env.ai.run('blobResponseModel', { prompt: 'test' }); + assert.deepStrictEqual(resp instanceof ReadableStream, true); + } + { + // Test legacy fetch + const resp = await env.ai.fetch( + 'http://workers-binding.ai/run?version=2', { - // Test legacy fetch - const resp = await env.ai.fetch("http://workers-binding.ai/run?version=2", { - method: 'POST', - headers: {'content-type': 'application/json'}, - body: JSON.stringify({ - inputs: {prompt: 'test'}, - options: {} - }) - }) - assert.deepStrictEqual(await resp.json(), { response: 'model response' }); + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + inputs: { prompt: 'test' }, + options: {}, + }), } + ); + assert.deepStrictEqual(await resp.json(), { response: 'model response' }); + } - { - // Test error response - try { - await env.ai.run('inputErrorModel', {prompt: 'test'}) - } catch(e) { - assert.deepEqual({ - name: e.name, message: e.message - }, { - name: 'InvalidInput', - message: '1001: prompt and messages are mutually exclusive', - }) - } - } + { + // Test error response + try { + await env.ai.run('inputErrorModel', { prompt: 'test' }); + } catch (e) { + assert.deepEqual( + { + name: e.name, + message: e.message, + }, + { + name: 'InvalidInput', + message: '1001: prompt and messages are mutually exclusive', + } + ); + } + } - { - // Test error properties - const err = await env.ai._parseError(Response.json({ - internalCode: 1001, - message: "InvalidInput: prompt and messages are mutually exclusive", - name: "InvalidInput", - description: "prompt and messages are mutually exclusive" - })) - assert.equal(err.name, 'InvalidInput') - assert.equal(err.message, '1001: prompt and messages are mutually exclusive') - } + { + // Test error properties + const err = await env.ai._parseError( + Response.json({ + internalCode: 1001, + message: 'InvalidInput: prompt and messages are mutually exclusive', + name: 'InvalidInput', + description: 'prompt and messages are mutually exclusive', + }) + ); + assert.equal(err.name, 'InvalidInput'); + assert.equal( + err.message, + '1001: prompt and messages are mutually exclusive' + ); + } - { - // Test error properties from non json response - const err = await env.ai._parseError(new Response("Unknown error")) - assert.equal(err.name, 'InferenceUpstreamError') - assert.equal(err.message, 'Unknown error') - } + { + // Test error properties from non json response + const err = await env.ai._parseError(new Response('Unknown error')); + assert.equal(err.name, 'InferenceUpstreamError'); + assert.equal(err.message, 'Unknown error'); + } - { - // Test raw input - const resp = await env.ai.run('rawInputs', {prompt: 'test'}) + { + // Test raw input + const resp = await env.ai.run('rawInputs', { prompt: 'test' }); - assert.deepStrictEqual(resp, { inputs: {prompt: 'test'}, options: {} }); - } + assert.deepStrictEqual(resp, { inputs: { prompt: 'test' }, options: {} }); + } - { - // Test gateway option - const resp = await env.ai.run('rawInputs', {prompt: 'test'}, {gateway: {id: 'my-gateway', skipCache: true}}) + { + // Test gateway option + const resp = await env.ai.run( + 'rawInputs', + { prompt: 'test' }, + { gateway: { id: 'my-gateway', skipCache: true } } + ); - assert.deepStrictEqual(resp, { inputs: {prompt: 'test'}, options: {gateway: {id: 'my-gateway', skipCache: true}}}); - } + assert.deepStrictEqual(resp, { + inputs: { prompt: 'test' }, + options: { gateway: { id: 'my-gateway', skipCache: true } }, + }); + } + { + // Test unwanted options not getting sent upstream + const resp = await env.ai.run( + 'rawInputs', + { prompt: 'test' }, { - // Test unwanted options not getting sent upstream - const resp = await env.ai.run('rawInputs', {prompt: 'test'}, {extraHeaders: 'test', example: 123, gateway: {id: 'my-gateway', metadata: { "employee": 1233}}}) - - assert.deepStrictEqual(resp, { inputs: {prompt: 'test'}, options: {example: 123, gateway: {id: 'my-gateway', metadata: { "employee": 1233}}} }); + extraHeaders: 'test', + example: 123, + gateway: { id: 'my-gateway', metadata: { employee: 1233 } }, } - }, -} + ); + + assert.deepStrictEqual(resp, { + inputs: { prompt: 'test' }, + options: { + example: 123, + gateway: { id: 'my-gateway', metadata: { employee: 1233 } }, + }, + }); + } + }, +}; diff --git a/src/cloudflare/internal/test/ai/ai-mock.js b/src/cloudflare/internal/test/ai/ai-mock.js index 592e0389e29..da07f77e752 100644 --- a/src/cloudflare/internal/test/ai/ai-mock.js +++ b/src/cloudflare/internal/test/ai/ai-mock.js @@ -3,50 +3,56 @@ // https://opensource.org/licenses/Apache-2.0 export default { - async fetch(request, env, ctx) { - const data = await request.json() - - const modelName = request.headers.get("cf-consn-model-id") - - const respHeaders = { - 'cf-ai-req-id': '3a1983d7-1ddd-453a-ab75-c4358c91b582', - } - - if (modelName === 'blobResponseModel') { - let utf8Encode = new TextEncoder(); - utf8Encode.encode("hello world"); - - return new Response(utf8Encode, { - headers: respHeaders - }) + async fetch(request, env, ctx) { + const data = await request.json(); + + const modelName = request.headers.get('cf-consn-model-id'); + + const respHeaders = { + 'cf-ai-req-id': '3a1983d7-1ddd-453a-ab75-c4358c91b582', + }; + + if (modelName === 'blobResponseModel') { + let utf8Encode = new TextEncoder(); + utf8Encode.encode('hello world'); + + return new Response(utf8Encode, { + headers: respHeaders, + }); + } + + if (modelName === 'rawInputs') { + return Response.json(data, { + headers: respHeaders, + }); + } + + if (modelName === 'inputErrorModel') { + return Response.json( + { + internalCode: 1001, + message: 'InvalidInput: prompt and messages are mutually exclusive', + name: 'InvalidInput', + description: 'prompt and messages are mutually exclusive', + }, + { + status: 400, + headers: { + 'content-type': 'application/json', + ...respHeaders, + }, } - - if (modelName === 'rawInputs') { - return Response.json(data, { - headers: respHeaders - }) - } - - if (modelName === 'inputErrorModel') { - return Response.json({ - internalCode: 1001, - message: "InvalidInput: prompt and messages are mutually exclusive", - name: "InvalidInput", - description: "prompt and messages are mutually exclusive" - }, { - status: 400, - headers: { - 'content-type': 'application/json', - ...respHeaders - } - }) - } - - return Response.json({response: 'model response'}, { - headers: { - 'content-type': 'application/json', - ...respHeaders - } - }) - }, -} + ); + } + + return Response.json( + { response: 'model response' }, + { + headers: { + 'content-type': 'application/json', + ...respHeaders, + }, + } + ); + }, +}; diff --git a/src/cloudflare/internal/test/d1/d1-api-test.js b/src/cloudflare/internal/test/d1/d1-api-test.js index 286ad24d5f4..8cdd92d12a0 100644 --- a/src/cloudflare/internal/test/d1/d1-api-test.js +++ b/src/cloudflare/internal/test/d1/d1-api-test.js @@ -2,52 +2,52 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from 'node:assert' +import * as assert from 'node:assert'; // Test helpers, since I want everything to run in sequence but I don't // want to lose context about which assertion failed. const test = (fn) => ({ async test(ctr, env) { - await fn(env.d1) + await fn(env.d1); }, -}) +}); // Recurse through nested objects/arrays looking for 'anything' and deleting that // key/value from both objects. Gives us a way to get expect.toMatchObject behaviour // with only deepEqual -const anything = Symbol('anything') +const anything = Symbol('anything'); const deleteAnything = (expected, actual) => { Object.entries(expected).forEach(([k, v]) => { if (v === anything) { - delete actual[k] - delete expected[k] + delete actual[k]; + delete expected[k]; } else if (typeof v === 'object' && typeof actual[k] === 'object') { - deleteAnything(expected[k], actual[k]) + deleteAnything(expected[k], actual[k]); } - }) -} + }); +}; const itShould = async (description, ...assertions) => { if (assertions.length % 2 !== 0) - throw new Error('itShould takes pairs of cb, expected args') + throw new Error('itShould takes pairs of cb, expected args'); try { for (let i = 0; i < assertions.length; i += 2) { - const cb = assertions[i] - const expected = assertions[i + 1] - const actual = await cb() - deleteAnything(expected, actual) + const cb = assertions[i]; + const expected = assertions[i + 1]; + const actual = await cb(); + deleteAnything(expected, actual); try { - assert.deepEqual(actual, expected) + assert.deepEqual(actual, expected); } catch (e) { - console.log(actual) - throw e + console.log(actual); + throw e; } } } catch (e) { - throw new Error(`TEST ERROR!\n❌ Failed to ${description}\n${e.message}`) + throw new Error(`TEST ERROR!\n❌ Failed to ${description}\n${e.message}`); } -} +}; // Make it easy to specify only a the meta properties we're interested in const meta = (values) => ({ @@ -60,7 +60,7 @@ const meta = (values) => ({ rows_read: anything, rows_written: anything, ...values, -}) +}); export const test_d1_api = test(async (DB) => { await itShould( @@ -77,7 +77,7 @@ export const test_d1_api = test(async (DB) => { );` ).run(), { success: true, meta: anything } - ) + ); await itShould( 'select an empty set', @@ -87,19 +87,19 @@ export const test_d1_api = test(async (DB) => { results: [], meta: meta({ changed_db: false }), } - ) + ); await itShould( 'have no results for .run()', () => DB.prepare(`SELECT * FROM users;`).run(), { success: true, meta: anything } - ) + ); await itShould( 'delete no rows ok', () => DB.prepare(`DELETE FROM users;`).run(), { success: true, meta: anything } - ) + ); await itShould( 'insert a few rows with a returning statement', @@ -132,13 +132,13 @@ export const test_d1_api = test(async (DB) => { ], meta: anything, } - ) + ); await itShould( 'delete two rows ok', () => DB.prepare(`DELETE FROM users;`).run(), { success: true, meta: anything } - ) + ); // In an earlier implementation, .run() called a different endpoint that threw on RETURNING clauses. await itShould( @@ -156,11 +156,11 @@ export const test_d1_api = test(async (DB) => { success: true, meta: anything, } - ) + ); // Results format tests - const select_1 = DB.prepare(`select 1;`) + const select_1 = DB.prepare(`select 1;`); await itShould( 'return simple results for select 1', () => select_1.all(), @@ -175,9 +175,9 @@ export const test_d1_api = test(async (DB) => { { 1: 1 }, () => select_1.first('1'), 1 - ) + ); - const select_all = DB.prepare(`SELECT * FROM users;`) + const select_all = DB.prepare(`SELECT * FROM users;`); await itShould( 'return all users', () => select_all.all(), @@ -216,9 +216,9 @@ export const test_d1_api = test(async (DB) => { }, () => select_all.first('name'), 'Albert Ross' - ) + ); - const select_one = DB.prepare(`SELECT * FROM users WHERE user_id = ?;`) + const select_one = DB.prepare(`SELECT * FROM users WHERE user_id = ?;`); await itShould( 'return the first user when bound with user_id = 1', @@ -248,7 +248,7 @@ export const test_d1_api = test(async (DB) => { }, () => select_one.bind(1).first('name'), 'Albert Ross' - ) + ); await itShould( 'return the second user when bound with user_id = 2', @@ -278,7 +278,7 @@ export const test_d1_api = test(async (DB) => { }, () => select_one.bind(2).first('name'), 'Al Dente' - ) + ); await itShould( 'return the results of two commands with batch', @@ -311,7 +311,7 @@ export const test_d1_api = test(async (DB) => { success: true, }, ] - ) + ); await itShould( 'allow binding all types of parameters', @@ -339,8 +339,8 @@ export const test_d1_api = test(async (DB) => { DB.prepare(`SELECT count(1) as count FROM users WHERE land_based = ?`) .bind(2) .first('count'), - 0, - ) + 0 + ); await itShould( 'create two tables with overlapping column names', @@ -399,7 +399,7 @@ export const test_d1_api = test(async (DB) => { }), }, ] - ) + ); await itShould( 'still sadly lose data for duplicate columns in a join', @@ -421,7 +421,7 @@ export const test_d1_api = test(async (DB) => { rows_written: 0, }), } - ) + ); await itShould( 'not lose data for duplicate columns in a join using raw()', @@ -434,7 +434,7 @@ export const test_d1_api = test(async (DB) => { [4, 5, 6, 'D', 'E', 'F'], [4, 5, 6, 'G', 'H', 'I'], ] - ) + ); await itShould( 'add columns using .raw({ columnNames: true })', @@ -448,7 +448,7 @@ export const test_d1_api = test(async (DB) => { [4, 5, 6, 'D', 'E', 'F'], [4, 5, 6, 'G', 'H', 'I'], ] - ) + ); await itShould( 'not add columns using .raw({ columnNames: false })', @@ -461,7 +461,7 @@ export const test_d1_api = test(async (DB) => { [4, 5, 6, 'D', 'E', 'F'], [4, 5, 6, 'G', 'H', 'I'], ] - ) + ); await itShould( 'return 0 rows_written for IN clauses', @@ -474,5 +474,5 @@ export const test_d1_api = test(async (DB) => { results: [{ c: 'A', d: 'B', e: 'C' }], meta: meta({ rows_read: 3, rows_written: 0 }), } - ) -}) + ); +}); diff --git a/src/cloudflare/internal/test/d1/d1-mock.js b/src/cloudflare/internal/test/d1/d1-mock.js index 7536bea28ca..779dc3df6c9 100644 --- a/src/cloudflare/internal/test/d1/d1-mock.js +++ b/src/cloudflare/internal/test/d1/d1-mock.js @@ -4,66 +4,66 @@ export class D1MockDO { constructor(state, env) { - this.state = state - this.sql = this.state.storage.sql + this.state = state; + this.sql = this.state.storage.sql; } async fetch(request) { - const { pathname, searchParams } = new URL(request.url) - const is_query = pathname === '/query' - const is_execute = pathname === '/execute' + const { pathname, searchParams } = new URL(request.url); + const is_query = pathname === '/query'; + const is_execute = pathname === '/execute'; if (request.method === 'POST' && (is_query || is_execute)) { - const body = await request.json() + const body = await request.json(); const resultsFormat = searchParams.get('resultsFormat') ?? - (is_query ? 'ARRAY_OF_OBJECTS' : 'NONE') + (is_query ? 'ARRAY_OF_OBJECTS' : 'NONE'); return Response.json( Array.isArray(body) ? body.map((query) => this.runQuery(query, resultsFormat)) : this.runQuery(body, resultsFormat) - ) + ); } else { - return Response.json({ error: 'Not found' }, { status: 404 }) + return Response.json({ error: 'Not found' }, { status: 404 }); } } runQuery(query, resultsFormat) { - const { sql, params = [] } = query + const { sql, params = [] } = query; const changes_stmt = this.sql.prepare( `SELECT total_changes() as changes, last_insert_rowid() as last_row_id` - ) - const size_before = this.sql.databaseSize + ); + const size_before = this.sql.databaseSize; const [[changes_before, last_row_id_before]] = Array.from( changes_stmt().raw() - ) + ); - const stmt = this.sql.prepare(sql)(...params) - const columnNames = stmt.columnNames - const rawResults = Array.from(stmt.raw()) + const stmt = this.sql.prepare(sql)(...params); + const columnNames = stmt.columnNames; + const rawResults = Array.from(stmt.raw()); const results = resultsFormat === 'NONE' ? undefined : resultsFormat === 'ROWS_AND_COLUMNS' - ? { columns: columnNames, rows: rawResults } - : rawResults.map((row) => - Object.fromEntries(columnNames.map((c, i) => [c, row[i]])) - ) + ? { columns: columnNames, rows: rawResults } + : rawResults.map((row) => + Object.fromEntries(columnNames.map((c, i) => [c, row[i]])) + ); const [[changes_after, last_row_id_after]] = Array.from( changes_stmt().raw() - ) + ); - const size_after = this.sql.databaseSize - const num_changes = changes_after - changes_before - const has_changes = num_changes !== 0 - const last_row_changed = last_row_id_after !== last_row_id_before + const size_after = this.sql.databaseSize; + const num_changes = changes_after - changes_before; + const has_changes = num_changes !== 0; + const last_row_changed = last_row_id_after !== last_row_id_before; - const db_size_different = size_after != size_before + const db_size_different = size_after != size_before; // `changed_db` includes multiple ways the DB might be altered - const changed_db = has_changes || last_row_changed || db_size_different + const changed_db = has_changes || last_row_changed || db_size_different; const { rowsRead: rows_read, rowsWritten: rows_written } = stmt; @@ -80,20 +80,20 @@ export class D1MockDO { rows_read, rows_written, }, - } + }; } } export default { async fetch(request, env, ctx) { try { - const stub = env.db.get(env.db.idFromName('test')) - return stub.fetch(request) + const stub = env.db.get(env.db.idFromName('test')); + return stub.fetch(request); } catch (err) { return Response.json( { error: err.message, stack: err.stack }, { status: 500 } - ) + ); } }, -} +}; diff --git a/src/cloudflare/internal/test/images/images-api-test.js b/src/cloudflare/internal/test/images/images-api-test.js index 599b45b5d3e..21e42005bb9 100644 --- a/src/cloudflare/internal/test/images/images-api-test.js +++ b/src/cloudflare/internal/test/images/images-api-test.js @@ -2,7 +2,7 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 // @ts-ignore -import * as assert from "node:assert"; +import * as assert from 'node:assert'; /** * @typedef {{'images': ImagesBinding}} Env @@ -15,10 +15,10 @@ export const test_images_info_bitmap = { * @param {Env} env */ async test(_, env) { - const blob = new Blob(["png"]); + const blob = new Blob(['png']); const info = await env.images.info(blob.stream()); assert.deepStrictEqual(info, { - format: "image/png", + format: 'image/png', fileSize: 123, width: 123, height: 123, @@ -32,10 +32,10 @@ export const test_images_info_svg = { * @param {Env} env */ async test(_, env) { - const blob = new Blob([""]); + const blob = new Blob(['']); const info = await env.images.info(blob.stream()); assert.deepStrictEqual(info, { - format: "image/svg+xml", + format: 'image/svg+xml', }); }, }; @@ -46,7 +46,7 @@ export const test_images_info_error = { * @param {Env} env */ async test(_, env) { - const blob = new Blob(["BAD"]); + const blob = new Blob(['BAD']); /** * @type {any} e; @@ -61,7 +61,7 @@ export const test_images_info_error = { assert.equal(true, !!e); assert.equal(e.code, 123); - assert.equal(e.message, "IMAGES_INFO_ERROR 123: Bad request"); + assert.equal(e.message, 'IMAGES_INFO_ERROR 123: Bad request'); }, }; @@ -72,20 +72,20 @@ export const test_images_transform = { */ async test(_, env) { - const blob = new Blob(["png"]); + const blob = new Blob(['png']); const result = await env.images .input(blob.stream()) .transform({ rotate: 90 }) - .output({ format: "image/avif" }); + .output({ format: 'image/avif' }); // Would be image/avif in real life, but mock always returns JSON - assert.equal(result.contentType(), "application/json"); + assert.equal(result.contentType(), 'application/json'); const body = await result.response().json(); assert.deepStrictEqual(body, { - image: "png", - output_format: "image/avif", + image: 'png', + output_format: 'image/avif', transforms: [{ rotate: 90 }], }); }, @@ -98,7 +98,7 @@ export const test_images_transform_bad = { */ async test(_, env) { - const blob = new Blob(["BAD"]); + const blob = new Blob(['BAD']); /** * @type {any} e; @@ -109,14 +109,14 @@ export const test_images_transform_bad = { await env.images .input(blob.stream()) .transform({ rotate: 90 }) - .output({ format: "image/avif" }); + .output({ format: 'image/avif' }); } catch (e2) { e = e2; } assert.equal(true, !!e); assert.equal(e.code, 123); - assert.equal(e.message, "IMAGES_TRANSFORM_ERROR 123: Bad request"); + assert.equal(e.message, 'IMAGES_TRANSFORM_ERROR 123: Bad request'); }, }; @@ -127,7 +127,7 @@ export const test_images_transform_consumed = { */ async test(_, env) { - const blob = new Blob(["png"]); + const blob = new Blob(['png']); /** * @type {any} e; @@ -139,8 +139,8 @@ export const test_images_transform_consumed = { .input(blob.stream()) .transform({ rotate: 90 }); - await transformer.output({ format: "image/avif" }); - await transformer.output({ format: "image/avif" }); + await transformer.output({ format: 'image/avif' }); + await transformer.output({ format: 'image/avif' }); } catch (e2) { e = e2; } @@ -149,7 +149,7 @@ export const test_images_transform_consumed = { assert.equal(e.code, 9525); assert.equal( e.message, - "IMAGES_TRANSFORM_ERROR 9525: ImageTransformer consumed; you may only call .output() once" + 'IMAGES_TRANSFORM_ERROR 9525: ImageTransformer consumed; you may only call .output() once' ); }, }; diff --git a/src/cloudflare/internal/test/images/images-upstream-mock.js b/src/cloudflare/internal/test/images/images-upstream-mock.js index a26fdc53857..a6802105e17 100644 --- a/src/cloudflare/internal/test/images/images-upstream-mock.js +++ b/src/cloudflare/internal/test/images/images-upstream-mock.js @@ -7,13 +7,13 @@ * @returns {Promise} */ async function imageAsString(form) { - let blob = form.get("image"); + let blob = form.get('image'); if (blob === null) { return null; } - if (typeof blob === "string") { + if (typeof blob === 'string') { return null; } @@ -26,41 +26,41 @@ export default { */ async fetch(request) { const form = await request.formData(); - const image = (await imageAsString(form)) || ""; - if (image.includes("BAD")) { - const resp = new Response("ERROR 123: Bad request", { + const image = (await imageAsString(form)) || ''; + if (image.includes('BAD')) { + const resp = new Response('ERROR 123: Bad request', { status: 409, headers: { - "cf-images-binding": "err=123", + 'cf-images-binding': 'err=123', }, }); return resp; } switch (new URL(request.url).pathname) { - case "/info": - if (image.includes(" 0); /** @type {VectorizeMatches} */ const expected = { matches: [ { - id: "b0daca4a-ffd8-4865-926b-e24800af2a2d", + id: 'b0daca4a-ffd8-4865-926b-e24800af2a2d', values: [0.2331, 1.0125, 0.6131, 0.9421, 0.9661, 0.8121], - metadata: { text: "She sells seashells by the seashore" }, + metadata: { text: 'She sells seashells by the seashore' }, score: 0.71151, }, { - id: "a44706aa-a366-48bc-8cc1-3feffd87d548", + id: 'a44706aa-a366-48bc-8cc1-3feffd87d548', values: [0.2321, 0.8121, 0.6315, 0.6151, 0.4121, 0.1512], metadata: { - text: "Peter Piper picked a peck of pickled peppers", + text: 'Peter Piper picked a peck of pickled peppers', }, score: 0.68913, }, { - id: "43cfcb31-07e2-411f-8bf9-f82a95ba8b96", + id: '43cfcb31-07e2-411f-8bf9-f82a95ba8b96', values: [0.0515, 0.7512, 0.8612, 0.2153, 0.15121, 0.6812], metadata: { - text: "You know New York, you need New York, you know you need unique New York", + text: 'You know New York, you need New York, you know you need unique New York', }, score: 0.94812, }, @@ -67,15 +67,15 @@ export const test_vector_search_vector_query = { const expected = { matches: [ { - id: "b0daca4a-ffd8-4865-926b-e24800af2a2d", + id: 'b0daca4a-ffd8-4865-926b-e24800af2a2d', score: 0.71151, }, { - id: "a44706aa-a366-48bc-8cc1-3feffd87d548", + id: 'a44706aa-a366-48bc-8cc1-3feffd87d548', score: 0.68913, }, { - id: "43cfcb31-07e2-411f-8bf9-f82a95ba8b96", + id: '43cfcb31-07e2-411f-8bf9-f82a95ba8b96', score: 0.94812, }, ], @@ -89,7 +89,7 @@ export const test_vector_search_vector_query = { const results = await IDX.query(new Float32Array(new Array(5).fill(0)), { topK: 1, filter: { - text: { $eq: "Peter Piper picked a peck of pickled peppers" }, + text: { $eq: 'Peter Piper picked a peck of pickled peppers' }, }, }); assert.equal(true, results.count > 0); @@ -97,7 +97,7 @@ export const test_vector_search_vector_query = { const expected = { matches: [ { - id: "a44706aa-a366-48bc-8cc1-3feffd87d548", + id: 'a44706aa-a366-48bc-8cc1-3feffd87d548', score: 0.68913, }, ], @@ -114,19 +114,19 @@ export const test_vector_search_vector_insert = { * @param {Env} env */ async test(_, env) { - const IDX = env["vector-search"]; + const IDX = env['vector-search']; { /** @type {Array} */ const newVectors = [ { - id: "15cc795d-93d3-416d-9a2a-36fa6fac73da", + id: '15cc795d-93d3-416d-9a2a-36fa6fac73da', values: new Float32Array(), - metadata: { text: "He threw three free throws" }, + metadata: { text: 'He threw three free throws' }, }, { - id: "15cc795d-93d3-416d-9a2a-36fa6fac73da", + id: '15cc795d-93d3-416d-9a2a-36fa6fac73da', values: new Float32Array(), - metadata: { text: "Which witch is which?" }, + metadata: { text: 'Which witch is which?' }, }, ]; const results = await IDX.insert(newVectors); @@ -141,12 +141,12 @@ export const test_vector_search_vector_insert_error = { * @param {Env} env */ async test(_, env) { - const IDX = env["vector-search"]; + const IDX = env['vector-search']; { /** @type {Array} */ const newVectors = [ { - id: "fail-with-test-error", + id: 'fail-with-test-error', values: new Float32Array(), }, ]; @@ -161,7 +161,7 @@ export const test_vector_search_vector_insert_error = { assert.equal( error && error.message, - "VECTOR_INSERT_ERROR (code = 9999): You asked me for this error" + 'VECTOR_INSERT_ERROR (code = 9999): You asked me for this error' ); } }, @@ -173,19 +173,19 @@ export const test_vector_search_vector_upsert = { * @param {Env} env */ async test(_, env) { - const IDX = env["vector-search"]; + const IDX = env['vector-search']; { /** @type {Array} */ const newVectors = [ { - id: "15cc795d-93d3-416d-9a2a-36fa6fac73da", + id: '15cc795d-93d3-416d-9a2a-36fa6fac73da', values: new Float32Array(), - metadata: { text: "He threw three free throws" }, + metadata: { text: 'He threw three free throws' }, }, { - id: "15cc795d-93d3-416d-9a2a-36fa6fac73da", + id: '15cc795d-93d3-416d-9a2a-36fa6fac73da', values: [0.3611, 0.9481, 0.8121, 0.7121, 0.8121, 0.0512], - metadata: { text: "Which witch is which?" }, + metadata: { text: 'Which witch is which?' }, }, ]; const results = await IDX.upsert(newVectors); @@ -200,12 +200,12 @@ export const test_vector_search_vector_delete_ids = { * @param {Env} env */ async test(_, env) { - const IDX = env["vector-search"]; + const IDX = env['vector-search']; { const results = await IDX.deleteByIds([ - "vector-a", - "vector-b", - "vector-c", + 'vector-a', + 'vector-b', + 'vector-c', ]); assert.equal(results.mutationId, `deleted vectors: 3`); } @@ -218,23 +218,23 @@ export const test_vector_search_vector_get_ids = { * @param {Env} env */ async test(_, env) { - const IDX = env["vector-search"]; + const IDX = env['vector-search']; { const results = await IDX.getByIds([ - "b0daca4a-ffd8-4865-926b-e24800af2a2d", - "43cfcb31-07e2-411f-8bf9-f82a95ba8b96", + 'b0daca4a-ffd8-4865-926b-e24800af2a2d', + '43cfcb31-07e2-411f-8bf9-f82a95ba8b96', ]); assert.deepStrictEqual(results, [ { - id: "b0daca4a-ffd8-4865-926b-e24800af2a2d", + id: 'b0daca4a-ffd8-4865-926b-e24800af2a2d', values: [0.2331, 1.0125, 0.6131, 0.9421, 0.9661, 0.8121], - metadata: { text: "She sells seashells by the seashore" }, + metadata: { text: 'She sells seashells by the seashore' }, }, { - id: "43cfcb31-07e2-411f-8bf9-f82a95ba8b96", + id: '43cfcb31-07e2-411f-8bf9-f82a95ba8b96', values: [0.0515, 0.7512, 0.8612, 0.2153, 0.15121, 0.6812], metadata: { - text: "You know New York, you need New York, you know you need unique New York", + text: 'You know New York, you need New York, you know you need unique New York', }, }, ]); @@ -245,9 +245,9 @@ export const test_vector_search_vector_get_ids = { export const test_vector_search_can_use_enum_exports = { async test() { assert.equal( - KnownModel["openai/text-embedding-ada-002"], - "openai/text-embedding-ada-002" + KnownModel['openai/text-embedding-ada-002'], + 'openai/text-embedding-ada-002' ); - assert.equal(DistanceMetric.COSINE, "cosine"); + assert.equal(DistanceMetric.COSINE, 'cosine'); }, }; diff --git a/src/cloudflare/internal/test/vectorize/vectorize-mock.js b/src/cloudflare/internal/test/vectorize/vectorize-mock.js index ef42dca072a..a8e033020b8 100644 --- a/src/cloudflare/internal/test/vectorize/vectorize-mock.js +++ b/src/cloudflare/internal/test/vectorize/vectorize-mock.js @@ -5,29 +5,29 @@ /** @type {Array} */ const exampleVectorMatches = [ { - id: "b0daca4a-ffd8-4865-926b-e24800af2a2d", + id: 'b0daca4a-ffd8-4865-926b-e24800af2a2d', values: [0.2331, 1.0125, 0.6131, 0.9421, 0.9661, 0.8121], - metadata: { text: "She sells seashells by the seashore" }, + metadata: { text: 'She sells seashells by the seashore' }, score: 0.71151, }, { - id: "a44706aa-a366-48bc-8cc1-3feffd87d548", + id: 'a44706aa-a366-48bc-8cc1-3feffd87d548', values: [0.2321, 0.8121, 0.6315, 0.6151, 0.4121, 0.1512], - metadata: { text: "Peter Piper picked a peck of pickled peppers" }, + metadata: { text: 'Peter Piper picked a peck of pickled peppers' }, score: 0.68913, }, { - id: "43cfcb31-07e2-411f-8bf9-f82a95ba8b96", + id: '43cfcb31-07e2-411f-8bf9-f82a95ba8b96', values: [0.0515, 0.7512, 0.8612, 0.2153, 0.15121, 0.6812], metadata: { - text: "You know New York, you need New York, you know you need unique New York", + text: 'You know New York, you need New York, you know you need unique New York', }, score: 0.94812, }, ]; /** @type {Array} */ const exampleVectors = exampleVectorMatches - .filter((m) => typeof m !== "undefined") + .filter((m) => typeof m !== 'undefined') .map(({ id, values, metadata }) => ({ id, values: values ?? [], @@ -42,79 +42,79 @@ export default { try { const { pathname } = new URL(request.url); - if (request.method === "POST" && pathname.endsWith("/create")) { + if (request.method === 'POST' && pathname.endsWith('/create')) { /** @type {VectorizeIndexConfig} */ const config = await request.json(); - const name = pathname.split("/")[2]; + const name = pathname.split('/')[2]; /** @type {VectorizeIndexDetails} */ const index = { - id: "ffeb30f5-d349-4ba5-8dde-79da543190fe", - name: name || "my-index", + id: 'ffeb30f5-d349-4ba5-8dde-79da543190fe', + name: name || 'my-index', config: config, vectorsCount: 0, }; return Response.json(index); - } else if (request.method === "GET" && pathname.endsWith("/list")) { + } else if (request.method === 'GET' && pathname.endsWith('/list')) { /** @type {Array} */ const index = [ { - id: "0f48d520-5bf5-4980-acd9-98453fb8a27f", - name: "my-first-index", + id: '0f48d520-5bf5-4980-acd9-98453fb8a27f', + name: 'my-first-index', config: { dimensions: 1536, - preset: "openai/text-embedding-ada-002", - metric: "euclidean", + preset: 'openai/text-embedding-ada-002', + metric: 'euclidean', }, vectorsCount: 500000, }, { - id: "b9fc84af-31f3-449c-bc61-b62abc86d5a1", - name: "my-second-index", + id: 'b9fc84af-31f3-449c-bc61-b62abc86d5a1', + name: 'my-second-index', config: { dimensions: 1536, - metric: "dot-product", + metric: 'dot-product', }, vectorsCount: 750000, }, ]; return Response.json(index); - } else if (request.method === "GET" && pathname.split("/").length === 3) { + } else if (request.method === 'GET' && pathname.split('/').length === 3) { /** @type {VectorizeIndexDetails} */ const index = { - id: "ffeb30f5-d349-4ba5-8dde-79da543190fe", - name: pathname.split("/")[2] || "my-index", + id: 'ffeb30f5-d349-4ba5-8dde-79da543190fe', + name: pathname.split('/')[2] || 'my-index', config: { dimensions: 1536, - preset: "openai/text-embedding-ada-002", - metric: "euclidean", + preset: 'openai/text-embedding-ada-002', + metric: 'euclidean', }, vectorsCount: 850850, }; return Response.json(index); } else if ( - request.method === "DELETE" && - pathname.split("/").length === 2 + request.method === 'DELETE' && + pathname.split('/').length === 2 ) { return Response.json({}); - } else if (request.method === "POST" && pathname.endsWith("/query")) { + } else if (request.method === 'POST' && pathname.endsWith('/query')) { /** @type {VectorizeQueryOptions & {vector: number[]}} */ const body = await request.json(); let returnSet = structuredClone(exampleVectorMatches); if ( - body?.filter?.["text"] && - typeof body?.filter?.["text"] === "object" && - body?.filter?.["text"]?.["$eq"] !== undefined + body?.filter?.['text'] && + typeof body?.filter?.['text'] === 'object' && + body?.filter?.['text']?.['$eq'] !== undefined ) { - const criteria = body?.filter?.["text"]?.["$eq"]; + const criteria = body?.filter?.['text']?.['$eq']; returnSet = returnSet.filter( - (m) => m.metadata?.["text"] === criteria + (m) => m.metadata?.['text'] === criteria ); } if (!body?.returnValues) returnSet.forEach((v) => { delete v.values; }); - if (!body?.returnMetadata || body?.returnMetadata === "none") + if (!body?.returnMetadata || body?.returnMetadata === 'none') returnSet.forEach((v) => { delete v.metadata; }); @@ -122,14 +122,14 @@ export default { matches: returnSet, count: returnSet.length, }); - } else if (request.method === "POST" && pathname.endsWith("/insert")) { + } else if (request.method === 'POST' && pathname.endsWith('/insert')) { /** @type {{vectors: Array}} */ const data = await request.json(); - if (data.vectors.find((v) => v.id === "fail-with-test-error")) { + if (data.vectors.find((v) => v.id === 'fail-with-test-error')) { return Response.json( { code: 9999, - error: "You asked me for this error", + error: 'You asked me for this error', }, { status: 400, @@ -143,7 +143,7 @@ export default { mutationId: `total vectors: ${data.vectors.length + exampleVectors.length}`, }; return Response.json(res); - } else if (request.method === "POST" && pathname.endsWith("/upsert")) { + } else if (request.method === 'POST' && pathname.endsWith('/upsert')) { /** @type {{vectors: Array}} */ let data = await request.json(); if (data.vectors.length > 1) data.vectors.splice(-1); @@ -154,8 +154,8 @@ export default { }; return Response.json(res); } else if ( - request.method === "POST" && - pathname.endsWith("/deleteByIds") + request.method === 'POST' && + pathname.endsWith('/deleteByIds') ) { /** @type {{ids: Array}} */ const body = await request.json(); @@ -165,14 +165,14 @@ export default { mutationId: `deleted vectors: ${body.ids.length}`, }; return Response.json(res); - } else if (request.method === "POST" && pathname.endsWith("/getByIds")) { + } else if (request.method === 'POST' && pathname.endsWith('/getByIds')) { /** @type {{ids: Array}} */ const body = await request.json(); return Response.json( exampleVectors.filter(({ id }) => body.ids.includes(id)) ); } else { - return Response.json({ error: "Not found" }, { status: 404 }); + return Response.json({ error: 'Not found' }, { status: 404 }); } } catch (err) { return Response.json( diff --git a/src/cloudflare/internal/vectorize-api.ts b/src/cloudflare/internal/vectorize-api.ts index 300bdb61d88..40c23ff41e3 100644 --- a/src/cloudflare/internal/vectorize-api.ts +++ b/src/cloudflare/internal/vectorize-api.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { default as flags } from "workerd:compatibility-flags"; +import { default as flags } from 'workerd:compatibility-flags'; interface Fetcher { fetch: typeof fetch; @@ -16,7 +16,7 @@ enum Operation { VECTOR_DELETE = 5, } -type VectorizeVersion = "v1" | "v2"; +type VectorizeVersion = 'v1' | 'v2'; /* * The Vectorize beta VectorizeIndex shares the same methods, so to keep things simple, they share one implementation. @@ -32,9 +32,9 @@ class VectorizeIndexImpl implements Vectorize { public async describe(): Promise { const endpoint = - this.indexVersion === "v2" ? `info` : `binding/indexes/${this.indexId}`; + this.indexVersion === 'v2' ? `info` : `binding/indexes/${this.indexId}`; const res = await this._send(Operation.INDEX_GET, endpoint, { - method: "GET", + method: 'GET', }); return await toJson(res); @@ -44,27 +44,35 @@ class VectorizeIndexImpl implements Vectorize { vector: VectorFloatArray | number[], options?: VectorizeQueryOptions ): Promise { - if (this.indexVersion === "v2") { - if (options && options.returnMetadata && !isVectorizeMetadataRetrievalLevel(options.returnMetadata) ) { + if (this.indexVersion === 'v2') { + if ( + options && + options.returnMetadata && + !isVectorizeMetadataRetrievalLevel(options.returnMetadata) + ) { throw new Error( `Invalid returnMetadata option. Expected: "none", "indexed" or "all"; got: ${options.returnMetadata}` ); } const res = await this._send(Operation.VECTOR_QUERY, `query`, { - method: "POST", + method: 'POST', body: JSON.stringify({ ...options, vector: Array.isArray(vector) ? vector : Array.from(vector), }), headers: { - "content-type": "application/json", - accept: "application/json", + 'content-type': 'application/json', + accept: 'application/json', }, }); return await toJson(res); } else { - if (options && options.returnMetadata && typeof options.returnMetadata !== 'boolean') { + if ( + options && + options.returnMetadata && + typeof options.returnMetadata !== 'boolean' + ) { throw new Error( `Invalid returnMetadata option. Expected boolean; got: ${options.returnMetadata}` ); @@ -76,16 +84,16 @@ class VectorizeIndexImpl implements Vectorize { Operation.VECTOR_QUERY, `binding/indexes/${this.indexId}/query`, { - method: "POST", + method: 'POST', body: JSON.stringify({ ...options, vector: Array.isArray(vector) ? vector : Array.from(vector), compat, }), headers: { - "content-type": "application/json", - accept: "application/json", - "cf-vector-search-query-compat": JSON.stringify(compat), + 'content-type': 'application/json', + accept: 'application/json', + 'cf-vector-search-query-compat': JSON.stringify(compat), }, } ); @@ -98,11 +106,11 @@ class VectorizeIndexImpl implements Vectorize { vectors: VectorizeVector[] ): Promise { const endpoint = - this.indexVersion === "v2" + this.indexVersion === 'v2' ? `insert` : `binding/indexes/${this.indexId}/insert`; const res = await this._send(Operation.VECTOR_INSERT, endpoint, { - method: "POST", + method: 'POST', body: JSON.stringify({ vectors: vectors.map((vec) => ({ ...vec, @@ -112,12 +120,12 @@ class VectorizeIndexImpl implements Vectorize { })), }), headers: { - "content-type": "application/json", - "cf-vector-search-dim-width": String( + 'content-type': 'application/json', + 'cf-vector-search-dim-width': String( vectors.length ? vectors[0]?.values?.length : 0 ), - "cf-vector-search-dim-height": String(vectors.length), - accept: "application/json", + 'cf-vector-search-dim-height': String(vectors.length), + accept: 'application/json', }, }); @@ -128,11 +136,11 @@ class VectorizeIndexImpl implements Vectorize { vectors: VectorizeVector[] ): Promise { const endpoint = - this.indexVersion === "v2" + this.indexVersion === 'v2' ? `upsert` : `binding/indexes/${this.indexId}/upsert`; const res = await this._send(Operation.VECTOR_UPSERT, endpoint, { - method: "POST", + method: 'POST', body: JSON.stringify({ vectors: vectors.map((vec) => ({ ...vec, @@ -142,12 +150,12 @@ class VectorizeIndexImpl implements Vectorize { })), }), headers: { - "content-type": "application/json", - "cf-vector-search-dim-width": String( + 'content-type': 'application/json', + 'cf-vector-search-dim-width': String( vectors.length ? vectors[0]?.values?.length : 0 ), - "cf-vector-search-dim-height": String(vectors.length), - accept: "application/json", + 'cf-vector-search-dim-height': String(vectors.length), + accept: 'application/json', }, }); @@ -156,15 +164,15 @@ class VectorizeIndexImpl implements Vectorize { public async getByIds(ids: string[]): Promise { const endpoint = - this.indexVersion === "v2" + this.indexVersion === 'v2' ? `getByIds` : `binding/indexes/${this.indexId}/getByIds`; const res = await this._send(Operation.VECTOR_GET, endpoint, { - method: "POST", + method: 'POST', body: JSON.stringify({ ids }), headers: { - "content-type": "application/json", - accept: "application/json", + 'content-type': 'application/json', + accept: 'application/json', }, }); @@ -173,15 +181,15 @@ class VectorizeIndexImpl implements Vectorize { public async deleteByIds(ids: string[]): Promise { const endpoint = - this.indexVersion === "v2" + this.indexVersion === 'v2' ? `deleteByIds` : `binding/indexes/${this.indexId}/deleteByIds`; const res = await this._send(Operation.VECTOR_DELETE, endpoint, { - method: "POST", + method: 'POST', body: JSON.stringify({ ids }), headers: { - "content-type": "application/json", - accept: "application/json", + 'content-type': 'application/json', + accept: 'application/json', }, }); @@ -204,9 +212,9 @@ class VectorizeIndexImpl implements Vectorize { const errResponse = (await res.json()) as VectorizeError; err = new Error( `${Operation[operation]}_ERROR${ - typeof errResponse.code === "number" + typeof errResponse.code === 'number' ? ` (code = ${errResponse.code})` - : "" + : '' }: ${errResponse.error}`, { cause: new Error(errResponse.error), @@ -230,8 +238,13 @@ class VectorizeIndexImpl implements Vectorize { } } -function isVectorizeMetadataRetrievalLevel(value: unknown): value is VectorizeMetadataRetrievalLevel { - return typeof value === 'string' && (value === 'all' || value === 'indexed' || value === 'none'); +function isVectorizeMetadataRetrievalLevel( + value: unknown +): value is VectorizeMetadataRetrievalLevel { + return ( + typeof value === 'string' && + (value === 'all' || value === 'indexed' || value === 'none') + ); } const maxBodyLogChars = 1_000; @@ -258,7 +271,7 @@ export function makeBinding(env: { return new VectorizeIndexImpl( env.fetcher, env.indexId, - env.indexVersion ?? "v1" + env.indexVersion ?? 'v1' ); } diff --git a/src/cloudflare/internal/vectorize.d.ts b/src/cloudflare/internal/vectorize.d.ts index e1fc9fd221a..8f9a101ac6b 100644 --- a/src/cloudflare/internal/vectorize.d.ts +++ b/src/cloudflare/internal/vectorize.d.ts @@ -33,7 +33,7 @@ interface VectorizeError { * * This list is expected to grow as support for more operations are released. */ -type VectorizeVectorMetadataFilterOp = "$eq" | "$ne"; +type VectorizeVectorMetadataFilterOp = '$eq' | '$ne'; /** * Filter criteria for vector metadata used to limit the retrieved query result set. @@ -54,7 +54,7 @@ type VectorizeVectorMetadataFilter = { * Supported distance metrics for an index. * Distance metrics determine how other "similar" vectors are determined. */ -type VectorizeDistanceMetric = "euclidean" | "cosine" | "dot-product"; +type VectorizeDistanceMetric = 'euclidean' | 'cosine' | 'dot-product'; /** * Metadata return levels for a Vectorize query. @@ -65,9 +65,9 @@ type VectorizeDistanceMetric = "euclidean" | "cosine" | "dot-product"; * @property indexed Return all metadata fields configured for indexing in the vector return set. This level of retrieval is "free" in that no additional overhead is incurred returning this data. However, note that indexed metadata is subject to truncation (especially for larger strings). * @property none No indexed metadata will be returned. */ -type VectorizeMetadataRetrievalLevel = "all" | "indexed" | "none"; +type VectorizeMetadataRetrievalLevel = 'all' | 'indexed' | 'none'; -interface VectorizeQueryOptions{ +interface VectorizeQueryOptions { topK?: number; namespace?: string; returnValues?: boolean; @@ -137,8 +137,8 @@ interface VectorizeVector { /** * Represents a matched vector for a query along with its score and (if specified) the matching vector information. */ -type VectorizeMatch = Pick, "values"> & - Omit & { +type VectorizeMatch = Pick, 'values'> & + Omit & { /** The score or rank for similarity, when returned as a result */ score: number; }; diff --git a/src/cloudflare/internal/workers.d.ts b/src/cloudflare/internal/workers.d.ts index 48fb53ae348..2cac08728dc 100644 --- a/src/cloudflare/internal/workers.d.ts +++ b/src/cloudflare/internal/workers.d.ts @@ -23,5 +23,4 @@ export class RpcStub { public constructor(server: object); } -export class RpcTarget { -} +export class RpcTarget {} diff --git a/src/cloudflare/sockets.ts b/src/cloudflare/sockets.ts index 3e7eb1d2e49..dbe4cf4f992 100644 --- a/src/cloudflare/sockets.ts +++ b/src/cloudflare/sockets.ts @@ -5,7 +5,8 @@ // TODO: c++ built-ins do not yet support named exports import sockets from 'cloudflare-internal:sockets'; export function connect( - address: string | sockets.SocketAddress, options: sockets.SocketOptions + address: string | sockets.SocketAddress, + options: sockets.SocketOptions ): sockets.Socket { return sockets.connect(address, options); } diff --git a/src/cloudflare/tsconfig.json b/src/cloudflare/tsconfig.json index 2896932b747..2797b8a57df 100644 --- a/src/cloudflare/tsconfig.json +++ b/src/cloudflare/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ESNext", "module": "ESNext", - "lib": [ "ESNext", "DOM" ], + "lib": ["ESNext", "DOM"], "alwaysStrict": true, "strict": true, "allowJs": true, diff --git a/src/cloudflare/vectorize.ts b/src/cloudflare/vectorize.ts index 93ca2105cd0..e1aeaaacc45 100644 --- a/src/cloudflare/vectorize.ts +++ b/src/cloudflare/vectorize.ts @@ -7,11 +7,11 @@ * These can be supplied in place of configuring explicit dimensions. */ export enum KnownModel { - "openai/text-embedding-ada-002" = "openai/text-embedding-ada-002", - "cohere/embed-multilingual-v2.0" = "cohere/embed-multilingual-v2.0", - "@cf/baai/bge-small-en-v1.5" = "@cf/baai/bge-small-en-v1.5", - "@cf/baai/bge-base-en-v1.5" = "@cf/baai/bge-base-en-v1.5", - "@cf/baai/bge-large-en-v1.5" = "@cf/baai/bge-large-en-v1.5", + 'openai/text-embedding-ada-002' = 'openai/text-embedding-ada-002', + 'cohere/embed-multilingual-v2.0' = 'cohere/embed-multilingual-v2.0', + '@cf/baai/bge-small-en-v1.5' = '@cf/baai/bge-small-en-v1.5', + '@cf/baai/bge-base-en-v1.5' = '@cf/baai/bge-base-en-v1.5', + '@cf/baai/bge-large-en-v1.5' = '@cf/baai/bge-large-en-v1.5', } /** @@ -19,9 +19,9 @@ export enum KnownModel { * Distance metrics determine how other "similar" vectors are determined. */ export enum DistanceMetric { - EUCLIDEAN = "euclidean", - COSINE = "cosine", - DOT_PRODUCT = "dot-product", + EUCLIDEAN = 'euclidean', + COSINE = 'cosine', + DOT_PRODUCT = 'dot-product', } /** @@ -33,14 +33,14 @@ export enum MetadataRetrievalLevel { * * This is a more expensive retrieval, as it requires additional fetching & reading of un-indexed data. */ - ALL = "all", + ALL = 'all', /** * Return all metadata fields configured for indexing in the vector return set. * * This level of retrieval is "free" in that no additional overhead is incurred returning this data. * However, note that indexed metadata is subject to truncation (especially for larger strings). */ - INDEXED = "indexed", + INDEXED = 'indexed', /** No indexed metadata will be returned. */ - NONE = "none", + NONE = 'none', } diff --git a/src/node/.eslintrc.json b/src/node/.eslintrc.json index 4f497e77ca3..6608d399d6b 100644 --- a/src/node/.eslintrc.json +++ b/src/node/.eslintrc.json @@ -1,12 +1,12 @@ { "env": { - "es2022": true, - "worker": true + "es2022": true, + "worker": true }, "extends": [ - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@typescript-eslint/strict" + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:@typescript-eslint/strict" ], "overrides": [], "parserOptions": { diff --git a/src/node/_stream_duplex.js b/src/node/_stream_duplex.js index 65190f1fd09..96d2e1ca4d3 100644 --- a/src/node/_stream_duplex.js +++ b/src/node/_stream_duplex.js @@ -3,12 +3,16 @@ // https://opensource.org/licenses/Apache-2.0 // /* eslint-disable */ + +// prettier-ignore import { Duplex, from, fromWeb, toWeb, } from 'node-internal:streams_duplex'; + +// prettier-ignore export { Duplex, from, diff --git a/src/node/_stream_readable.js b/src/node/_stream_readable.js index 3321daa982b..44300d28353 100644 --- a/src/node/_stream_readable.js +++ b/src/node/_stream_readable.js @@ -3,6 +3,8 @@ // https://opensource.org/licenses/Apache-2.0 // /* eslint-disable */ + +// prettier-ignore import { Readable, ReadableState, @@ -11,6 +13,8 @@ import { from, wrap, } from 'node-internal:streams_readable'; + +// prettier-ignore export { Readable, ReadableState, diff --git a/src/node/_stream_writable.js b/src/node/_stream_writable.js index 07458f61f61..4dccfbe6f70 100644 --- a/src/node/_stream_writable.js +++ b/src/node/_stream_writable.js @@ -3,12 +3,16 @@ // https://opensource.org/licenses/Apache-2.0 // /* eslint-disable */ + +// prettier-ignore import { Writable, WritableState, fromWeb, toWeb, } from 'node-internal:streams_writable'; + +// prettier-ignore export { Writable, WritableState, diff --git a/src/node/crypto.ts b/src/node/crypto.ts index 310a18b668b..b60966388d3 100644 --- a/src/node/crypto.ts +++ b/src/node/crypto.ts @@ -4,9 +4,7 @@ // /* eslint-disable */ -import { - ERR_METHOD_NOT_IMPLEMENTED -} from 'node-internal:internal_errors'; +import { ERR_METHOD_NOT_IMPLEMENTED } from 'node-internal:internal_errors'; export const getRandomValues = crypto.getRandomValues; export const subtle = crypto.subtle; @@ -47,21 +45,11 @@ import { Hmac, } from 'node-internal:crypto_hash'; -import { - hkdf, - hkdfSync, -} from 'node-internal:crypto_hkdf'; +import { hkdf, hkdfSync } from 'node-internal:crypto_hkdf'; -import { - pbkdf2, - pbkdf2Sync, - ArrayLike, -} from 'node-internal:crypto_pbkdf2'; +import { pbkdf2, pbkdf2Sync, ArrayLike } from 'node-internal:crypto_pbkdf2'; -import { - scrypt, - scryptSync, -} from 'node-internal:crypto_scrypt'; +import { scrypt, scryptSync } from 'node-internal:crypto_scrypt'; import { KeyObject, @@ -79,9 +67,7 @@ import { import { Certificate } from 'node-internal:crypto_spkac'; -import { - X509Certificate, -} from 'node-internal:crypto_x509'; +import { X509Certificate } from 'node-internal:crypto_x509'; export { // DH @@ -136,9 +122,10 @@ export { Certificate, // X509 X509Certificate, -} +}; export function getCiphers() { + // prettier-ignore return ["aes-128-cbc", "aes-192-cbc", "aes-256-cbc", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-ecb", "aes-192-ecb", "aes-256-ecb", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "des-ecb", "des-ede", "des-ede-cbc", "rc2-cbc"]; @@ -147,12 +134,16 @@ export function getCiphers() { export function getCurves() { // Hardcoded list of supported curves. Note that prime256v1 is equivalent to secp256r1, we follow // OpenSSL's and bssl's nomenclature here. + + // prettier-ignore return ['secp224r1', 'prime256v1', 'secp384r1', 'secp521r1']; } export function getHashes() { // Hardcoded list of hashes supported in boringssl, node's approach looks pretty clunky. This is // expected to change infrequently based of bssl's stability-focused approach. + + // prettier-ignore return ['md4', 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5-sha1', 'RSA-MD5', 'RSA-SHA1', 'RSA-SHA224', 'RSA-SHA256', 'RSA-SHA384', 'RSA-SHA512', 'DSA-SHA', 'DSA-SHA1', 'ecdsa-with-SHA1']; @@ -165,11 +156,11 @@ export function secureHeapUsed() { used: 0, utilization: 0, min: 0, - } + }; } // We do not allow users to set the engine used. -export function setEngine(_1 : string, _2?: number) { +export function setEngine(_1: string, _2?: number) { throw new ERR_METHOD_NOT_IMPLEMENTED('setEngine'); } @@ -180,7 +171,9 @@ export function setFips(_: boolean) { // We always run in FIPS mode. export const fips = true; -export function getFips() { return fips; } +export function getFips() { + return fips; +} export default { // DH @@ -236,8 +229,12 @@ export default { // Fips getFips, setFips, - get fips() { return getFips(); }, - set fips(_: boolean) { setFips(_); }, + get fips() { + return getFips(); + }, + set fips(_: boolean) { + setFips(_); + }, // WebCrypto subtle, webcrypto, @@ -326,4 +323,3 @@ export default { // * WebCrypto // * [x] crypto.subtle // * [x] crypto.webcrypto - diff --git a/src/node/diagnostics_channel.ts b/src/node/diagnostics_channel.ts index bf93c0080e3..e35a97298b5 100644 --- a/src/node/diagnostics_channel.ts +++ b/src/node/diagnostics_channel.ts @@ -24,38 +24,38 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable */ -import { - default as diagnosticsChannel, -} from 'node-internal:diagnostics_channel'; +import { default as diagnosticsChannel } from 'node-internal:diagnostics_channel'; import type { Channel as ChannelType, MessageCallback, } from 'node-internal:diagnostics_channel'; -import { - ERR_INVALID_ARG_TYPE, -} from 'node-internal:internal_errors'; +import { ERR_INVALID_ARG_TYPE } from 'node-internal:internal_errors'; -import { - validateObject, -} from 'node-internal:validators'; +import { validateObject } from 'node-internal:validators'; export const { Channel } = diagnosticsChannel; -export function hasSubscribers(name: string|symbol): boolean { +export function hasSubscribers(name: string | symbol): boolean { return diagnosticsChannel.hasSubscribers(name); } -export function channel(name: string|symbol): ChannelType { +export function channel(name: string | symbol): ChannelType { return diagnosticsChannel.channel(name); } -export function subscribe(name: string|symbol, callback: MessageCallback): void { +export function subscribe( + name: string | symbol, + callback: MessageCallback +): void { diagnosticsChannel.subscribe(name, callback); } -export function unsubscribe(name: string|symbol, callback: MessageCallback): void { +export function unsubscribe( + name: string | symbol, + callback: MessageCallback +): void { diagnosticsChannel.unsubscribe(name, callback); } @@ -68,11 +68,11 @@ export interface TracingChannelSubscriptions { } export interface TracingChannels { - start: ChannelType, - end: ChannelType, - asyncStart: ChannelType, - asyncEnd: ChannelType, - error: ChannelType, + start: ChannelType; + end: ChannelType; + asyncStart: ChannelType; + asyncEnd: ChannelType; + error: ChannelType; } const kStart = Symbol('kStart'); @@ -89,14 +89,26 @@ export class TracingChannel { private [kError]?: ChannelType; public constructor() { - throw new Error('Use diagnostic_channel.tracingChannels() to create TracingChannel'); + throw new Error( + 'Use diagnostic_channel.tracingChannels() to create TracingChannel' + ); } - public get start(): ChannelType { return this[kStart]!; } - public get end(): ChannelType { return this[kEnd]!; } - public get asyncStart(): ChannelType { return this[kAsyncStart]!; } - public get asyncEnd(): ChannelType { return this[kAsyncEnd]!; } - public get error(): ChannelType { return this[kError]!; } + public get start(): ChannelType { + return this[kStart]!; + } + public get end(): ChannelType { + return this[kEnd]!; + } + public get asyncStart(): ChannelType { + return this[kAsyncStart]!; + } + public get asyncEnd(): ChannelType { + return this[kAsyncEnd]!; + } + public get error(): ChannelType { + return this[kError]!; + } public subscribe(subscriptions: TracingChannelSubscriptions) { if (subscriptions.start !== undefined) @@ -124,31 +136,39 @@ export class TracingChannel { this[kError]!.unsubscribe(subscriptions.error); } - public traceSync(fn : (...args: any[]) => any, - context: unknown = {}, - thisArg: any = globalThis, - ...args: any[]): any { + public traceSync( + fn: (...args: any[]) => any, + context: unknown = {}, + thisArg: any = globalThis, + ...args: any[] + ): any { const { start, end, error } = this; - return start.runStores(context, () => { - try { - const result = Reflect.apply(fn, thisArg, args); - (context as any).result = result; - return result; - } catch (err) { - (context as any).error = err; - error.publish(context); - throw err; - } finally { - end.publish(context); - } - }, thisArg); + return start.runStores( + context, + () => { + try { + const result = Reflect.apply(fn, thisArg, args); + (context as any).result = result; + return result; + } catch (err) { + (context as any).error = err; + error.publish(context); + throw err; + } finally { + end.publish(context); + } + }, + thisArg + ); } - public tracePromise(fn : (...args: any[]) => any, - context: unknown = {}, - thisArg: any = globalThis, - ...args: any[]): any { + public tracePromise( + fn: (...args: any[]) => any, + context: unknown = {}, + thisArg: any = globalThis, + ...args: any[] + ): any { const { start, end, asyncStart, asyncEnd, error } = this; function reject(err: any) { @@ -166,29 +186,35 @@ export class TracingChannel { return result; } - return start.runStores(context, () => { - try { - let promise = Reflect.apply(fn, thisArg, args); - // Convert thenables to native promises - if (!(promise instanceof Promise)) { - promise = Promise.resolve(promise); + return start.runStores( + context, + () => { + try { + let promise = Reflect.apply(fn, thisArg, args); + // Convert thenables to native promises + if (!(promise instanceof Promise)) { + promise = Promise.resolve(promise); + } + return promise.then(resolve, reject); + } catch (err) { + (context as any).error = err; + error.publish(context); + throw err; + } finally { + end.publish(context); } - return promise.then(resolve, reject); - } catch (err) { - (context as any).error = err; - error.publish(context); - throw err; - } finally { - end.publish(context); - } - }, thisArg); + }, + thisArg + ); } - public traceCallback(fn : (...args: any[]) => any, - position = -1, - context: unknown = {}, - thisArg: any = globalThis, - ...args: any[]): any { + public traceCallback( + fn: (...args: any[]) => any, + position = -1, + context: unknown = {}, + thisArg: any = globalThis, + ...args: any[] + ): any { const { start, end, asyncStart, asyncEnd, error } = this; function wrappedCallback(this: any, err: any, res: any) { @@ -200,15 +226,19 @@ export class TracingChannel { } // Using runStores here enables manual context failure recovery - asyncStart.runStores(context, () => { - try { - if (callback) { - return Reflect.apply(callback, this, arguments); + asyncStart.runStores( + context, + () => { + try { + if (callback) { + return Reflect.apply(callback, this, arguments); + } + } finally { + asyncEnd.publish(context); } - } finally { - asyncEnd.publish(context); - } - }, thisArg); + }, + thisArg + ); } const callback = args[position]; @@ -217,17 +247,21 @@ export class TracingChannel { } args.splice(position, 1, wrappedCallback); - return start.runStores(context, () => { - try { - return Reflect.apply(fn, thisArg, args); - } catch (err) { - (context as any).error = err; - error.publish(context); - throw err; - } finally { - end.publish(context); - } - }, thisArg); + return start.runStores( + context, + () => { + try { + return Reflect.apply(fn, thisArg, args); + } catch (err) { + (context as any).error = err; + error.publish(context); + throw err; + } finally { + end.publish(context); + } + }, + thisArg + ); } } @@ -238,25 +272,37 @@ function validateChannel(channel: any, name: string) { return channel as ChannelType; } -export function tracingChannel(nameOrChannels : string|TracingChannels) : TracingChannel { - return Reflect.construct(function (this: TracingChannel) { - if (typeof nameOrChannels === 'string') { - const name = nameOrChannels as string; - this[kStart] = channel(`tracing:${name}:start`); - this[kEnd] = channel(`tracing:${name}:end`); - this[kAsyncStart] = channel(`tracing:${name}:asyncStart`); - this[kAsyncEnd] = channel(`tracing:${name}:asyncEnd`); - this[kError] = channel(`tracing:${name}:error`); - } else { - validateObject(nameOrChannels, 'channels', {}); - const channels = nameOrChannels as TracingChannels; - this[kStart] = validateChannel(channels.start, 'channels.start'); - this[kEnd] = validateChannel(channels.end, 'channels.end'); - this[kAsyncStart] = validateChannel(channels.asyncStart, 'channels.asyncStart'); - this[kAsyncEnd] = validateChannel(channels.asyncEnd, 'channels.asyncEnd'); - this[kError] = validateChannel(channels.error, 'channels.error'); - } - }, [], TracingChannel) as TracingChannel; +export function tracingChannel( + nameOrChannels: string | TracingChannels +): TracingChannel { + return Reflect.construct( + function (this: TracingChannel) { + if (typeof nameOrChannels === 'string') { + const name = nameOrChannels as string; + this[kStart] = channel(`tracing:${name}:start`); + this[kEnd] = channel(`tracing:${name}:end`); + this[kAsyncStart] = channel(`tracing:${name}:asyncStart`); + this[kAsyncEnd] = channel(`tracing:${name}:asyncEnd`); + this[kError] = channel(`tracing:${name}:error`); + } else { + validateObject(nameOrChannels, 'channels', {}); + const channels = nameOrChannels as TracingChannels; + this[kStart] = validateChannel(channels.start, 'channels.start'); + this[kEnd] = validateChannel(channels.end, 'channels.end'); + this[kAsyncStart] = validateChannel( + channels.asyncStart, + 'channels.asyncStart' + ); + this[kAsyncEnd] = validateChannel( + channels.asyncEnd, + 'channels.asyncEnd' + ); + this[kError] = validateChannel(channels.error, 'channels.error'); + } + }, + [], + TracingChannel + ) as TracingChannel; } export default { diff --git a/src/node/internal/async_hooks.d.ts b/src/node/internal/async_hooks.d.ts index 4e97d10a025..abcf5030478 100644 --- a/src/node/internal/async_hooks.d.ts +++ b/src/node/internal/async_hooks.d.ts @@ -6,13 +6,23 @@ export interface AsyncResourceOptions { export class AsyncResource { public constructor(type: string, options?: AsyncResourceOptions); - public runInAsyncScope(fn: (...args: unknown[]) => R, ...args: unknown[]): R; + public runInAsyncScope( + fn: (...args: unknown[]) => R, + ...args: unknown[] + ): R; public bind unknown>( - fn: Func): Func & { asyncResource: AsyncResource; }; + fn: Func + ): Func & { asyncResource: AsyncResource }; - public static bind unknown, ThisArg>( - fn: Func, type?: string, thisArg?: ThisArg): Func & { asyncResource: AsyncResource; }; + public static bind< + Func extends (this: ThisArg, ...args: unknown[]) => unknown, + ThisArg, + >( + fn: Func, + type?: string, + thisArg?: ThisArg + ): Func & { asyncResource: AsyncResource }; } export class AsyncLocalStorage { diff --git a/src/node/internal/buffer.d.ts b/src/node/internal/buffer.d.ts index 00326e213c8..593ab7bf416 100644 --- a/src/node/internal/buffer.d.ts +++ b/src/node/internal/buffer.d.ts @@ -4,7 +4,7 @@ interface CompareOptions { aStart?: number; aEnd?: number; bStart?: number; - bEnd?: number + bEnd?: number; } type BufferSource = ArrayBufferView | ArrayBuffer; @@ -12,34 +12,50 @@ type BufferSource = ArrayBufferView | ArrayBuffer; export type Encoding = number; export function byteLength(value: string): number; -export function compare(a: Uint8Array, b: Uint8Array, options?: CompareOptions): number; +export function compare( + a: Uint8Array, + b: Uint8Array, + options?: CompareOptions +): number; export function concat(list: Uint8Array[], length: number): ArrayBuffer; export function decodeString(value: string, encoding: Encoding): ArrayBuffer; -export function fillImpl(buffer: Uint8Array, - value: string | BufferSource, - start: number, - end: number, - encoding?: Encoding): void; -export function indexOf(buffer: Uint8Array, - value: string | Uint8Array, - byteOffset?: number, - encoding?: Encoding, - findLast?: boolean): number | undefined; -export function swap(buffer: Uint8Array, size: 16|32|64): void; -export function toString(buffer: Uint8Array, - start: number, - end: number, - encoding: Encoding): string; -export function write(buffer: Uint8Array, - value: string, - offset: number, - length: number, - encoding: Encoding): void; +export function fillImpl( + buffer: Uint8Array, + value: string | BufferSource, + start: number, + end: number, + encoding?: Encoding +): void; +export function indexOf( + buffer: Uint8Array, + value: string | Uint8Array, + byteOffset?: number, + encoding?: Encoding, + findLast?: boolean +): number | undefined; +export function swap(buffer: Uint8Array, size: 16 | 32 | 64): void; +export function toString( + buffer: Uint8Array, + start: number, + end: number, + encoding: Encoding +): string; +export function write( + buffer: Uint8Array, + value: string, + offset: number, + length: number, + encoding: Encoding +): void; export function decode(buffer: Uint8Array, state: Uint8Array): string; export function flush(state: Uint8Array): string; export function isAscii(value: ArrayBufferView): boolean; export function isUtf8(value: ArrayBufferView): boolean; -export function transcode(source: ArrayBufferView, fromEncoding: Encoding, toEncoding: Encoding): ArrayBuffer; +export function transcode( + source: ArrayBufferView, + fromEncoding: Encoding, + toEncoding: Encoding +): ArrayBuffer; export const ASCII: Encoding; export const LATIN1: Encoding; diff --git a/src/node/internal/constants.ts b/src/node/internal/constants.ts index a24f4a8a8c8..7ea5d70accb 100644 --- a/src/node/internal/constants.ts +++ b/src/node/internal/constants.ts @@ -65,4 +65,4 @@ export const CHAR_AMPERSAND = 38; /* & */ export const CHAR_EQUAL = 61; /* = */ export const CHAR_0 = 48; /* 0 */ export const CHAR_9 = 57; /* 9 */ -export const EOL = '\;'; +export const EOL = ';'; diff --git a/src/node/internal/crypto.d.ts b/src/node/internal/crypto.d.ts index c528546eecb..6167eb461c8 100644 --- a/src/node/internal/crypto.d.ts +++ b/src/node/internal/crypto.d.ts @@ -2,14 +2,19 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; // random -export function checkPrimeSync(candidate: ArrayBufferView, num_checks: number): boolean; -export function randomPrime(size: number, safe: boolean, add?: ArrayBufferView|undefined, - rem?: ArrayBufferView|undefined): ArrayBuffer; +export function checkPrimeSync( + candidate: ArrayBufferView, + num_checks: number +): boolean; +export function randomPrime( + size: number, + safe: boolean, + add?: ArrayBufferView | undefined, + rem?: ArrayBufferView | undefined +): ArrayBuffer; // X509Certificate export interface CheckOptions { @@ -21,26 +26,26 @@ export interface CheckOptions { } export class X509Certificate { - public static parse(data: ArrayBuffer|ArrayBufferView): X509Certificate; - public get subject(): string|undefined; - public get subjectAltName(): string|undefined; - public get infoAccess(): string|undefined; - public get issuer(): string|undefined; - public get issuerCert(): X509Certificate|undefined; - public get validFrom(): string|undefined; - public get validTo(): string|undefined; - public get fingerprint(): string|undefined; - public get fingerprint256(): string|undefined; - public get fingerprint512(): string|undefined; - public get keyUsage(): string[]|undefined; - public get serialNumber(): string|undefined; - public get pem(): string|undefined; - public get raw(): ArrayBuffer|undefined; - public get publicKey(): CryptoKey|undefined; + public static parse(data: ArrayBuffer | ArrayBufferView): X509Certificate; + public get subject(): string | undefined; + public get subjectAltName(): string | undefined; + public get infoAccess(): string | undefined; + public get issuer(): string | undefined; + public get issuerCert(): X509Certificate | undefined; + public get validFrom(): string | undefined; + public get validTo(): string | undefined; + public get fingerprint(): string | undefined; + public get fingerprint256(): string | undefined; + public get fingerprint512(): string | undefined; + public get keyUsage(): string[] | undefined; + public get serialNumber(): string | undefined; + public get pem(): string | undefined; + public get raw(): ArrayBuffer | undefined; + public get publicKey(): CryptoKey | undefined; public get isCA(): boolean; - public checkHost(host: string, options?: CheckOptions): string|undefined; - public checkEmail(email: string, options?: CheckOptions): string|undefined; - public checkIp(ip: string, options?: CheckOptions): string|undefined; + public checkHost(host: string, options?: CheckOptions): string | undefined; + public checkEmail(email: string, options?: CheckOptions): string | undefined; + public checkIp(ip: string, options?: CheckOptions): string | undefined; public checkIssued(cert: X509Certificate): boolean; public checkPrivateKey(key: CryptoKey): boolean; public verify(key: CryptoKey): boolean; @@ -55,7 +60,7 @@ export class HashHandle { public copy(xofLen: number): HashHandle; } -export type ArrayLike = ArrayBuffer|string|Buffer|ArrayBufferView; +export type ArrayLike = ArrayBuffer | string | Buffer | ArrayBufferView; export class HmacHandle { public constructor(algorithm: string, key: ArrayLike | CryptoKey); @@ -64,30 +69,58 @@ export class HmacHandle { } // hkdf -export function getHkdf(hash: string, key: ArrayLike, salt: ArrayLike, info: ArrayLike, - length: number): ArrayBuffer; +export function getHkdf( + hash: string, + key: ArrayLike, + salt: ArrayLike, + info: ArrayLike, + length: number +): ArrayBuffer; // pbkdf2 -export function getPbkdf(password: ArrayLike, salt: ArrayLike, iterations: number, keylen: number, - digest: string): ArrayBuffer; +export function getPbkdf( + password: ArrayLike, + salt: ArrayLike, + iterations: number, + keylen: number, + digest: string +): ArrayBuffer; // scrypt -export function getScrypt(password: ArrayLike, salt: ArrayLike, N: number, r: number, p: number, - maxmem: number, keylen: number): ArrayBuffer; +export function getScrypt( + password: ArrayLike, + salt: ArrayLike, + N: number, + r: number, + p: number, + maxmem: number, + keylen: number +): ArrayBuffer; // Keys -export function exportKey(key: CryptoKey, options?: InnerExportOptions): KeyExportResult; +export function exportKey( + key: CryptoKey, + options?: InnerExportOptions +): KeyExportResult; export function equals(key: CryptoKey, otherKey: CryptoKey): boolean; export function getAsymmetricKeyDetail(key: CryptoKey): AsymmetricKeyDetails; export function getAsymmetricKeyType(key: CryptoKey): AsymmetricKeyType; export function createSecretKey(key: ArrayBuffer | ArrayBufferView): CryptoKey; -export function createPrivateKey(key: InnerCreateAsymmetricKeyOptions): CryptoKey; -export function createPublicKey(key: InnerCreateAsymmetricKeyOptions): CryptoKey; +export function createPrivateKey( + key: InnerCreateAsymmetricKeyOptions +): CryptoKey; +export function createPublicKey( + key: InnerCreateAsymmetricKeyOptions +): CryptoKey; // Spkac -export function verifySpkac(input: ArrayBufferView|ArrayBuffer): boolean; -export function exportPublicKey(input: ArrayBufferView|ArrayBuffer): null | ArrayBuffer; -export function exportChallenge(input: ArrayBufferView|ArrayBuffer): null | ArrayBuffer; +export function verifySpkac(input: ArrayBufferView | ArrayBuffer): boolean; +export function exportPublicKey( + input: ArrayBufferView | ArrayBuffer +): null | ArrayBuffer; +export function exportChallenge( + input: ArrayBufferView | ArrayBuffer +): null | ArrayBuffer; export type KeyData = string | ArrayBuffer | ArrayBufferView; @@ -125,12 +158,13 @@ export interface AesKeyAlgorithm { length: number; } -export type KeyAlgorithm = RsaKeyAlgorithm | - EcKeyAlgorithm | - DhKeyAlgorithm | - DsaKeyAlgorithm | - HmacKeyAlgorithm | - AesKeyAlgorithm; +export type KeyAlgorithm = + | RsaKeyAlgorithm + | EcKeyAlgorithm + | DhKeyAlgorithm + | DsaKeyAlgorithm + | HmacKeyAlgorithm + | AesKeyAlgorithm; export interface CryptoKey { algorithm: KeyAlgorithm; @@ -179,7 +213,14 @@ export type SecretKeyFormat = 'buffer' | 'jwk'; export type AsymmetricKeyFormat = 'pem' | 'der' | 'jwk'; export type PublicKeyEncoding = 'pkcs1' | 'spki'; export type PrivateKeyEncoding = 'pkcs1' | 'pkcs8' | 'sec1'; -export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | 'x25519' | 'ed25519' | 'dh'; +export type AsymmetricKeyType = + | 'rsa' + | 'rsa-pss' + | 'dsa' + | 'ec' + | 'x25519' + | 'ed25519' + | 'dh'; export type SecretKeyType = 'hmac' | 'aes'; export type ParamEncoding = 'named' | 'explicit'; @@ -207,13 +248,15 @@ export interface InnerPrivateKeyExportOptions { passphrase?: Uint8Array; } -export type ExportOptions = SecretKeyExportOptions | - PublicKeyExportOptions | - PrivateKeyExportOptions; +export type ExportOptions = + | SecretKeyExportOptions + | PublicKeyExportOptions + | PrivateKeyExportOptions; -export type InnerExportOptions = SecretKeyExportOptions | - PublicKeyExportOptions | - InnerPrivateKeyExportOptions; +export type InnerExportOptions = + | SecretKeyExportOptions + | PublicKeyExportOptions + | InnerPrivateKeyExportOptions; export interface AsymmetricKeyDetails { modulusLength?: number; @@ -246,7 +289,7 @@ export interface GenerateKeyOptions { export interface GenerateKeyPairOptions { modulusLength?: number; - publicExponent?: number|bigint; + publicExponent?: number | bigint; hashAlgorithm?: string; mgf1HashAlgorithm?: string; saltLength?: number; @@ -263,8 +306,10 @@ export interface GenerateKeyPairOptions { // DiffieHellman export class DiffieHellmanHandle { - public constructor(sizeOrKey: number | ArrayBuffer | ArrayBufferView, - generator: number | ArrayBuffer | ArrayBufferView); + public constructor( + sizeOrKey: number | ArrayBuffer | ArrayBufferView, + generator: number | ArrayBuffer | ArrayBufferView + ); public setPublicKey(data: ArrayBuffer | ArrayBufferView | Buffer): void; public setPrivateKey(data: ArrayBuffer | ArrayBufferView | Buffer): void; public getPublicKey(): ArrayBuffer; @@ -272,7 +317,7 @@ export class DiffieHellmanHandle { public getGenerator(): ArrayBuffer; public getPrime(): ArrayBuffer; - public computeSecret(key: ArrayBuffer|ArrayBufferView): ArrayBuffer; + public computeSecret(key: ArrayBuffer | ArrayBufferView): ArrayBuffer; public generateKeys(): ArrayBuffer; public getVerifyError(): number; diff --git a/src/node/internal/crypto_dh.ts b/src/node/internal/crypto_dh.ts index 5d622a01233..e6f0d5604e0 100644 --- a/src/node/internal/crypto_dh.ts +++ b/src/node/internal/crypto_dh.ts @@ -28,9 +28,7 @@ 'use strict'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { default as cryptoImpl } from 'node-internal:crypto'; type ArrayLike = cryptoImpl.ArrayLike; @@ -40,13 +38,11 @@ import { ERR_INVALID_ARG_TYPE, } from 'node-internal:internal_errors'; -import { - validateInt32, -} from 'node-internal:validators'; +import { validateInt32 } from 'node-internal:validators'; import { isArrayBufferView, - isAnyArrayBuffer + isAnyArrayBuffer, } from 'node-internal:internal_types'; import { @@ -61,19 +57,25 @@ interface DiffieHellman { [kHandle]: cryptoImpl.DiffieHellmanHandle; } -let DiffieHellman = function (this: DiffieHellman, sizeOrKey: number|ArrayLike, - keyEncoding?: number|string, generator?: number|ArrayLike, - genEncoding?: string): DiffieHellman { +let DiffieHellman = function ( + this: DiffieHellman, + sizeOrKey: number | ArrayLike, + keyEncoding?: number | string, + generator?: number | ArrayLike, + genEncoding?: string +): DiffieHellman { if (!(this instanceof DiffieHellman)) return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding); - if (typeof sizeOrKey !== 'number' && - typeof sizeOrKey !== 'string' && - !isArrayBufferView(sizeOrKey) && - !isAnyArrayBuffer(sizeOrKey)) { + if ( + typeof sizeOrKey !== 'number' && + typeof sizeOrKey !== 'string' && + !isArrayBufferView(sizeOrKey) && + !isAnyArrayBuffer(sizeOrKey) + ) { throw new ERR_INVALID_ARG_TYPE( 'sizeOrKey', ['number', 'string', 'ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], - sizeOrKey, + sizeOrKey ); } @@ -81,13 +83,16 @@ let DiffieHellman = function (this: DiffieHellman, sizeOrKey: number|ArrayLike, // rejected with ERR_OSSL_BN_BITS_TOO_SMALL) by OpenSSL. The glue code // in node_crypto.cc accepts values that are IsInt32() for that reason // and that's why we do that here too. - if (typeof sizeOrKey === 'number') - validateInt32(sizeOrKey, 'sizeOrKey'); + if (typeof sizeOrKey === 'number') validateInt32(sizeOrKey, 'sizeOrKey'); - if (keyEncoding && keyEncoding !== 'buffer' && !Buffer.isEncoding(keyEncoding)) { + if ( + keyEncoding && + keyEncoding !== 'buffer' && + !Buffer.isEncoding(keyEncoding) + ) { genEncoding = generator as any; generator = keyEncoding; - keyEncoding = "utf-8"; // default encoding + keyEncoding = 'utf-8'; // default encoding } keyEncoding ??= 'utf-8'; @@ -106,12 +111,15 @@ let DiffieHellman = function (this: DiffieHellman, sizeOrKey: number|ArrayLike, throw new ERR_INVALID_ARG_TYPE( 'generator', ['number', 'string', 'ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], - generator, + generator ); } - this[kHandle] = new cryptoImpl.DiffieHellmanHandle(sizeOrKey as any, generator as any); - Object.defineProperty(DiffieHellman.prototype, "verifyError", { + this[kHandle] = new cryptoImpl.DiffieHellmanHandle( + sizeOrKey as any, + generator as any + ); + Object.defineProperty(DiffieHellman.prototype, 'verifyError', { get: function () { return this[kHandle].getVerifyError(); }, @@ -119,21 +127,30 @@ let DiffieHellman = function (this: DiffieHellman, sizeOrKey: number|ArrayLike, enumerable: true, }); return this; -} as any as { new (sizeOrKey: number|ArrayLike, keyEncoding?: number|string, - generator?: number|ArrayLike, genEncoding?: string): DiffieHellman; }; +} as any as { + new ( + sizeOrKey: number | ArrayLike, + keyEncoding?: number | string, + generator?: number | ArrayLike, + genEncoding?: string + ): DiffieHellman; +}; interface DiffieHellmanGroup { [kHandle]: cryptoImpl.DiffieHellmanHandle; } -let DiffieHellmanGroup = function(this: DiffieHellmanGroup, name: string): DiffieHellmanGroup { +let DiffieHellmanGroup = function ( + this: DiffieHellmanGroup, + name: string +): DiffieHellmanGroup { if (!(this instanceof DiffieHellmanGroup)) return new DiffieHellmanGroup(name); // The C++-based handle is shared between both classes, so DiffieHellmanGroupHandle() is merely // a different constructor for a DiffieHellmanHandle. this[kHandle] = cryptoImpl.DiffieHellmanGroupHandle(name); - Object.defineProperty(DiffieHellmanGroup.prototype, "verifyError", { + Object.defineProperty(DiffieHellmanGroup.prototype, 'verifyError', { get: function () { return this[kHandle].getVerifyError(); }, @@ -141,80 +158,95 @@ let DiffieHellmanGroup = function(this: DiffieHellmanGroup, name: string): Diffi enumerable: true, }); return this; -} as any as { new (name: string): DiffieHellmanGroup; }; - -DiffieHellmanGroup.prototype.generateKeys = DiffieHellman.prototype.generateKeys = - dhGenerateKeys; -DiffieHellmanGroup.prototype.computeSecret = DiffieHellman.prototype.computeSecret = - dhComputeSecret; -DiffieHellmanGroup.prototype.getPrime = DiffieHellman.prototype.getPrime = dhGetPrime; -DiffieHellmanGroup.prototype.getGenerator = DiffieHellman.prototype.getGenerator = - dhGetGenerator; -DiffieHellmanGroup.prototype.getPublicKey = DiffieHellman.prototype.getPublicKey = - dhGetPublicKey; -DiffieHellmanGroup.prototype.getPrivateKey = DiffieHellman.prototype.getPrivateKey = - dhGetPrivateKey; +} as any as { new (name: string): DiffieHellmanGroup }; + +DiffieHellmanGroup.prototype.generateKeys = + DiffieHellman.prototype.generateKeys = dhGenerateKeys; +DiffieHellmanGroup.prototype.computeSecret = + DiffieHellman.prototype.computeSecret = dhComputeSecret; +DiffieHellmanGroup.prototype.getPrime = DiffieHellman.prototype.getPrime = + dhGetPrime; +DiffieHellmanGroup.prototype.getGenerator = + DiffieHellman.prototype.getGenerator = dhGetGenerator; +DiffieHellmanGroup.prototype.getPublicKey = + DiffieHellman.prototype.getPublicKey = dhGetPublicKey; +DiffieHellmanGroup.prototype.getPrivateKey = + DiffieHellman.prototype.getPrivateKey = dhGetPrivateKey; DiffieHellman.prototype.setPublicKey = dhSetPublicKey; DiffieHellman.prototype.setPrivateKey = dhSetPrivateKey; -export {DiffieHellman, DiffieHellmanGroup}; +export { DiffieHellman, DiffieHellmanGroup }; -type DHLike = DiffieHellman|DiffieHellmanGroup; -function dhGenerateKeys(this: DHLike, encoding?: string): Buffer|string { +type DHLike = DiffieHellman | DiffieHellmanGroup; +function dhGenerateKeys(this: DHLike, encoding?: string): Buffer | string { const keys = this[kHandle].generateKeys(); return encode(keys, encoding); } -function dhComputeSecret(this: DHLike, key: ArrayLike, inEnc?: string, - outEnc?: string): Buffer|string { +function dhComputeSecret( + this: DHLike, + key: ArrayLike, + inEnc?: string, + outEnc?: string +): Buffer | string { key = getArrayBufferOrView(key, 'key', inEnc); const ret = this[kHandle].computeSecret(key); - if (typeof ret === 'string') - throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY(); + if (typeof ret === 'string') throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY(); return encode(ret, outEnc); } -function dhGetPrime(this: DHLike, encoding?: string): Buffer|string { +function dhGetPrime(this: DHLike, encoding?: string): Buffer | string { const prime = this[kHandle].getPrime(); return encode(prime, encoding); } -function dhGetGenerator(this: DHLike, encoding?: string): Buffer|string { +function dhGetGenerator(this: DHLike, encoding?: string): Buffer | string { const generator = this[kHandle].getGenerator(); return encode(generator, encoding); } -function dhGetPublicKey(this: DHLike, encoding?: string): Buffer|string { +function dhGetPublicKey(this: DHLike, encoding?: string): Buffer | string { const key = this[kHandle].getPublicKey(); return encode(key, encoding); } -function dhGetPrivateKey(this: DHLike, encoding?: string): Buffer|string { +function dhGetPrivateKey(this: DHLike, encoding?: string): Buffer | string { const key = this[kHandle].getPrivateKey(); return encode(key, encoding); } -function dhSetPublicKey(this: DiffieHellman, key: ArrayLike, encoding?: string): DiffieHellman { +function dhSetPublicKey( + this: DiffieHellman, + key: ArrayLike, + encoding?: string +): DiffieHellman { key = getArrayBufferOrView(key, 'key', encoding); this[kHandle].setPublicKey(key); return this; } -function dhSetPrivateKey(this: DiffieHellman, key: ArrayLike, encoding?: string): DiffieHellman { +function dhSetPrivateKey( + this: DiffieHellman, + key: ArrayLike, + encoding?: string +): DiffieHellman { key = getArrayBufferOrView(key, 'key', encoding); this[kHandle].setPrivateKey(key); return this; } -function encode(buffer: ArrayBuffer, encoding?: string): Buffer|string { +function encode(buffer: ArrayBuffer, encoding?: string): Buffer | string { if (encoding && encoding !== 'buffer') return Buffer.from(buffer).toString(encoding); return Buffer.from(buffer); } -export function createDiffieHellman(sizeOrKey: number|ArrayLike, - keyEncoding?: number|string, generator?: number|ArrayLike, - genEncoding?: string): DiffieHellman { +export function createDiffieHellman( + sizeOrKey: number | ArrayLike, + keyEncoding?: number | string, + generator?: number | ArrayLike, + genEncoding?: string +): DiffieHellman { return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding); } diff --git a/src/node/internal/crypto_hash.ts b/src/node/internal/crypto_hash.ts index b111e01effd..fc510e6bdff 100644 --- a/src/node/internal/crypto_hash.ts +++ b/src/node/internal/crypto_hash.ts @@ -37,9 +37,7 @@ import { getStringOption, } from 'node-internal:crypto_util'; -import { - Buffer -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { ERR_CRYPTO_HASH_FINALIZED, @@ -48,10 +46,7 @@ import { ERR_INVALID_ARG_TYPE, } from 'node-internal:internal_errors'; -import { - validateString, - validateUint32, -} from 'node-internal:validators'; +import { validateString, validateUint32 } from 'node-internal:validators'; import { isArrayBufferView, @@ -65,9 +60,7 @@ import { TransformCallback, } from 'node-internal:streams_transform'; -import { - KeyObject, -} from 'node-internal:crypto_keys'; +import { KeyObject } from 'node-internal:crypto_keys'; export interface HashOptions extends TransformOptions { outputLength?: number; @@ -88,14 +81,15 @@ export function createHash(algorithm: string, options?: HashOptions): Hash { return new Hash(algorithm, options); } -let Hash = function(this: Hash, algorithm: string | cryptoImpl.HashHandle, - options?: HashOptions): Hash { - if (!(this instanceof Hash)) - return new Hash(algorithm, options); +let Hash = function ( + this: Hash, + algorithm: string | cryptoImpl.HashHandle, + options?: HashOptions +): Hash { + if (!(this instanceof Hash)) return new Hash(algorithm, options); const xofLen = typeof options === 'object' ? options.outputLength : undefined; - if (xofLen !== undefined) - validateUint32(xofLen, 'options.outputLength'); + if (xofLen !== undefined) validateUint32(xofLen, 'options.outputLength'); if (algorithm instanceof cryptoImpl.HashHandle) { this[kHandle] = algorithm.copy(xofLen as number); } else { @@ -108,60 +102,74 @@ let Hash = function(this: Hash, algorithm: string | cryptoImpl.HashHandle, Transform.call(this, options); return this; -} as any as { new (algorithm: string | cryptoImpl.HashHandle, options?: HashOptions): Hash; }; +} as any as { + new (algorithm: string | cryptoImpl.HashHandle, options?: HashOptions): Hash; +}; Object.setPrototypeOf(Hash.prototype, Transform.prototype); Object.setPrototypeOf(Hash, Transform); -Hash.prototype.copy = function(this: Hash, options?: HashOptions): Hash { +Hash.prototype.copy = function (this: Hash, options?: HashOptions): Hash { const state = this[kState]; - if (state[kFinalized]) - throw new ERR_CRYPTO_HASH_FINALIZED(); + if (state[kFinalized]) throw new ERR_CRYPTO_HASH_FINALIZED(); return new Hash(this[kHandle], options); -} +}; -Hash.prototype._transform = function(this: Hash | Hmac, chunk: string | Buffer | ArrayBufferView, - encoding: string, callback: TransformCallback): void { +Hash.prototype._transform = function ( + this: Hash | Hmac, + chunk: string | Buffer | ArrayBufferView, + encoding: string, + callback: TransformCallback +): void { if (typeof chunk === 'string') { chunk = Buffer.from(chunk, encoding); } this[kHandle].update(chunk); callback(); -} +}; -Hash.prototype._flush = function(this: Hash | Hmac, callback: TransformCallback): void { +Hash.prototype._flush = function ( + this: Hash | Hmac, + callback: TransformCallback +): void { this.push(Buffer.from(this[kHandle].digest())); callback(); -} +}; -Hash.prototype.update = function(this: Hash | Hmac, data: string | Buffer | ArrayBufferView, - encoding?: string): Hash | Hmac { +Hash.prototype.update = function ( + this: Hash | Hmac, + data: string | Buffer | ArrayBufferView, + encoding?: string +): Hash | Hmac { encoding ??= 'utf8'; if (encoding === 'buffer') { encoding = undefined; } const state = this[kState]; - if (state[kFinalized]) - throw new ERR_CRYPTO_HASH_FINALIZED(); + if (state[kFinalized]) throw new ERR_CRYPTO_HASH_FINALIZED(); if (typeof data === 'string') { data = Buffer.from(data, encoding); } else if (!isArrayBufferView(data)) { throw new ERR_INVALID_ARG_TYPE( - 'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data); + 'data', + ['string', 'Buffer', 'TypedArray', 'DataView'], + data + ); } - if (!this[kHandle].update(data)) - throw new ERR_CRYPTO_HASH_UPDATE_FAILED(); + if (!this[kHandle].update(data)) throw new ERR_CRYPTO_HASH_UPDATE_FAILED(); return this; -} +}; -Hash.prototype.digest = function(this: Hash, outputEncoding?: string): Buffer | string { +Hash.prototype.digest = function ( + this: Hash, + outputEncoding?: string +): Buffer | string { const state = this[kState]; - if (state[kFinalized]) - throw new ERR_CRYPTO_HASH_FINALIZED(); + if (state[kFinalized]) throw new ERR_CRYPTO_HASH_FINALIZED(); // Explicit conversion for backward compatibility. const ret = Buffer.from(this[kHandle].digest()); @@ -171,7 +179,7 @@ Hash.prototype.digest = function(this: Hash, outputEncoding?: string): Buffer | } else { return ret; } -} +}; /////////////////////////// @@ -180,13 +188,20 @@ interface Hmac extends Transform { [kState]: _kState; } -export function createHmac(hmac: string, key: ArrayLike | KeyObject | CryptoKey, - options?: TransformOptions): Hmac { +export function createHmac( + hmac: string, + key: ArrayLike | KeyObject | CryptoKey, + options?: TransformOptions +): Hmac { return new Hmac(hmac, key, options); } -let Hmac = function(this: Hmac, hmac: string, key: ArrayLike | KeyObject | cryptoImpl.CryptoKey, - options?: TransformOptions): Hmac { +let Hmac = function ( + this: Hmac, + hmac: string, + key: ArrayLike | KeyObject | cryptoImpl.CryptoKey, + options?: TransformOptions +): Hmac { if (!(this instanceof Hmac)) { return new Hmac(hmac, key, options); } @@ -200,19 +215,34 @@ let Hmac = function(this: Hmac, hmac: string, key: ArrayLike | KeyObject | crypt this[kHandle] = new cryptoImpl.HmacHandle(hmac, key[kHandle]); } else if (isCryptoKey(key)) { if ((key as cryptoImpl.CryptoKey).type !== 'secret') { - throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE((key as cryptoImpl.CryptoKey).type, 'secret'); + throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE( + (key as cryptoImpl.CryptoKey).type, + 'secret' + ); } this[kHandle] = new cryptoImpl.HmacHandle(hmac, key); - } else if (typeof key !== 'string' && - !isArrayBufferView(key) && - !isAnyArrayBuffer(key)) { + } else if ( + typeof key !== 'string' && + !isArrayBufferView(key) && + !isAnyArrayBuffer(key) + ) { throw new ERR_INVALID_ARG_TYPE( 'key', - [ 'ArrayBuffer', 'Buffer', 'ArrayBufferView', 'string', 'KeyObject', 'CryptoKey'], - key); + [ + 'ArrayBuffer', + 'Buffer', + 'ArrayBufferView', + 'string', + 'KeyObject', + 'CryptoKey', + ], + key + ); } else { - this[kHandle] = new cryptoImpl.HmacHandle(hmac, getArrayBufferOrView(key as ArrayLike, - 'key', encoding)); + this[kHandle] = new cryptoImpl.HmacHandle( + hmac, + getArrayBufferOrView(key as ArrayLike, 'key', encoding) + ); } this[kState] = { @@ -220,18 +250,28 @@ let Hmac = function(this: Hmac, hmac: string, key: ArrayLike | KeyObject | crypt }; Transform.call(this, options); return this; -} as any as { new (hmac: string, key: ArrayLike | KeyObject | CryptoKey, - options?: TransformOptions): Hmac; }; +} as any as { + new ( + hmac: string, + key: ArrayLike | KeyObject | CryptoKey, + options?: TransformOptions + ): Hmac; +}; Object.setPrototypeOf(Hmac.prototype, Transform.prototype); Object.setPrototypeOf(Hmac, Transform); Hmac.prototype.update = Hash.prototype.update; -Hmac.prototype.digest = function(this: Hmac, outputEncoding?: string): Buffer | string { +Hmac.prototype.digest = function ( + this: Hmac, + outputEncoding?: string +): Buffer | string { const state = this[kState]; if (state[kFinalized]) { - return !outputEncoding || outputEncoding === 'buffer' ? Buffer.from('') : ''; + return !outputEncoding || outputEncoding === 'buffer' + ? Buffer.from('') + : ''; } // Explicit conversion for backward compatibility. @@ -247,4 +287,4 @@ Hmac.prototype.digest = function(this: Hmac, outputEncoding?: string): Buffer | Hmac.prototype._flush = Hash.prototype._flush; Hmac.prototype._transform = Hash.prototype._transform; -export {Hash, Hmac}; +export { Hash, Hmac }; diff --git a/src/node/internal/crypto_hkdf.ts b/src/node/internal/crypto_hkdf.ts index 292661dbf14..b7255cd1aaa 100644 --- a/src/node/internal/crypto_hkdf.ts +++ b/src/node/internal/crypto_hkdf.ts @@ -36,20 +36,13 @@ import { validateString, } from 'node-internal:validators'; -import { - KeyObject, -} from 'node-internal:crypto_keys'; +import { KeyObject } from 'node-internal:crypto_keys'; type ArrayLike = cryptoImpl.ArrayLike; -import { - kMaxLength, -} from 'node-internal:internal_buffer'; +import { kMaxLength } from 'node-internal:internal_buffer'; -import { - toBuf, - validateByteSource, -} from 'node-internal:crypto_util'; +import { toBuf, validateByteSource } from 'node-internal:crypto_util'; import { isAnyArrayBuffer, @@ -62,13 +55,21 @@ import { ERR_OUT_OF_RANGE, } from 'node-internal:internal_errors'; -function validateParameters(hash: string, key: ArrayLike | KeyObject, salt: ArrayLike, - info: ArrayLike, length: number) { +function validateParameters( + hash: string, + key: ArrayLike | KeyObject, + salt: ArrayLike, + info: ArrayLike, + length: number +) { // TODO(soon): Add support for KeyObject input. if (key instanceof KeyObject) { - throw new NodeError("ERR_METHOD_NOT_IMPLEMENTED", "KeyObject support for hkdf() and " + - "hkdfSync() is not yet implemented. Use ArrayBuffer, TypedArray, " + - "DataView, or Buffer instead."); + throw new NodeError( + 'ERR_METHOD_NOT_IMPLEMENTED', + 'KeyObject support for hkdf() and ' + + 'hkdfSync() is not yet implemented. Use ArrayBuffer, TypedArray, ' + + 'DataView, or Buffer instead.' + ); } validateString(hash, 'digest'); @@ -82,7 +83,8 @@ function validateParameters(hash: string, key: ArrayLike | KeyObject, salt: Arra throw new ERR_OUT_OF_RANGE( 'info', 'must not contain more than 1024 bytes', - info.byteLength); + info.byteLength + ); } return { @@ -108,43 +110,57 @@ function prepareKey(key: ArrayLike): ArrayLike { 'DataView', 'Buffer', ], - key); + key + ); } return key; } -export function hkdf(hash: string, key: ArrayLike | KeyObject, salt: ArrayLike, info: ArrayLike, - length: number, - callback: (err: Error|null, derivedKey?: ArrayBuffer) => void): void { - ({ +export function hkdf( + hash: string, + key: ArrayLike | KeyObject, + salt: ArrayLike, + info: ArrayLike, + length: number, + callback: (err: Error | null, derivedKey?: ArrayBuffer) => void +): void { + ({ hash, key, salt, info, length } = validateParameters( hash, key, salt, info, - length, - } = validateParameters(hash, key, salt, info, length)); + length + )); validateFunction(callback, 'callback'); new Promise((res, rej) => { try { res(cryptoImpl.getHkdf(hash, key as ArrayLike, salt, info, length)); - } catch(err) { + } catch (err) { rej(err); } - }).then((val: ArrayBuffer) => callback(null, val), (err) => callback(err)); + }).then( + (val: ArrayBuffer) => callback(null, val), + (err) => callback(err) + ); } -export function hkdfSync(hash: string, key: ArrayLike | KeyObject, salt: ArrayLike, - info: ArrayLike, length: number): ArrayBuffer { - ({ +export function hkdfSync( + hash: string, + key: ArrayLike | KeyObject, + salt: ArrayLike, + info: ArrayLike, + length: number +): ArrayBuffer { + ({ hash, key, salt, info, length } = validateParameters( hash, key, salt, info, - length, - } = validateParameters(hash, key, salt, info, length)); + length + )); return cryptoImpl.getHkdf(hash, key, salt, info, length); } diff --git a/src/node/internal/crypto_keys.ts b/src/node/internal/crypto_keys.ts index 671e098b7b7..cdc2c29c851 100644 --- a/src/node/internal/crypto_keys.ts +++ b/src/node/internal/crypto_keys.ts @@ -47,7 +47,7 @@ import { // TODO(soon): Uncomment these once createPrivateKey/createPublicKey are implemented. // JsonWebKey, // InnerCreateAsymmetricKeyOptions, - default as cryptoImpl + default as cryptoImpl, } from 'node-internal:crypto'; import { @@ -71,10 +71,7 @@ import { // ERR_INVALID_ARG_VALUE, } from 'node-internal:internal_errors'; -import { - validateObject, - validateString, -} from 'node-internal:validators'; +import { validateObject, validateString } from 'node-internal:validators'; // In Node.js, the definition of KeyObject is a bit complicated because // KeyObject instances in Node.js can be transferred via postMessage() and @@ -95,33 +92,46 @@ export abstract class KeyObject { throw new Error('Illegal constructor'); } - static from(key: CryptoKey) : KeyObject { + static from(key: CryptoKey): KeyObject { if (!(key instanceof CryptoKey)) { throw new ERR_INVALID_ARG_TYPE('key', 'CryptoKey', key); } switch (key.type) { case 'secret': - return Reflect.construct(function(this: SecretKeyObject) { - this[kHandle] = key; - }, [], SecretKeyObject); + return Reflect.construct( + function (this: SecretKeyObject) { + this[kHandle] = key; + }, + [], + SecretKeyObject + ); case 'private': - return Reflect.construct(function(this: PrivateKeyObject) { - this[kHandle] = key; - }, [], PrivateKeyObject); + return Reflect.construct( + function (this: PrivateKeyObject) { + this[kHandle] = key; + }, + [], + PrivateKeyObject + ); case 'public': - return Reflect.construct(function(this: PublicKeyObject) { - this[kHandle] = key; - }, [], PublicKeyObject); + return Reflect.construct( + function (this: PublicKeyObject) { + this[kHandle] = key; + }, + [], + PublicKeyObject + ); } } - export(options: ExportOptions = {}) : KeyExportResult { + export(options: ExportOptions = {}): KeyExportResult { validateObject(options, 'options', {}); // Yes, converting to any is a bit of a cheat, but it allows us to check // each option individually without having to do a bunch of type guards. const opts = options as any; - if (opts.format !== undefined) validateString(opts.format, 'options.format'); + if (opts.format !== undefined) + validateString(opts.format, 'options.format'); if (opts.type !== undefined) validateString(opts.type, 'options.type'); if (this.type === 'private') { if (opts.cipher !== undefined) { @@ -130,107 +140,142 @@ export abstract class KeyObject { opts.passphrase = Buffer.from(opts.passphrase, opts.encoding); } if (!isUint8Array(opts.passphrase)) { - throw new ERR_INVALID_ARG_TYPE('options.passphrase', [ - 'string', 'Uint8Array' - ], opts.passphrase); + throw new ERR_INVALID_ARG_TYPE( + 'options.passphrase', + ['string', 'Uint8Array'], + opts.passphrase + ); } } } - const ret = cryptoImpl.exportKey(this[kHandle], options as InnerExportOptions); + const ret = cryptoImpl.exportKey( + this[kHandle], + options as InnerExportOptions + ); if (typeof ret === 'string') return ret; if (isUint8Array(ret)) { - return Buffer.from((ret as Uint8Array).buffer, ret.byteOffset, ret.byteLength) as KeyExportResult; + return Buffer.from( + (ret as Uint8Array).buffer, + ret.byteOffset, + ret.byteLength + ) as KeyExportResult; } else if (isArrayBuffer(ret)) { - return Buffer.from(ret as ArrayBuffer, 0, (ret as ArrayBuffer).byteLength); + return Buffer.from( + ret as ArrayBuffer, + 0, + (ret as ArrayBuffer).byteLength + ); } return ret; } - equals(otherKeyObject: KeyObject) : boolean { - if (this === otherKeyObject || - this[kHandle] === otherKeyObject[kHandle]) return true; + equals(otherKeyObject: KeyObject): boolean { + if (this === otherKeyObject || this[kHandle] === otherKeyObject[kHandle]) + return true; if (this.type !== otherKeyObject.type) return false; if (!(otherKeyObject[kHandle] instanceof CryptoKey)) { - throw new ERR_INVALID_ARG_TYPE('otherKeyObject', 'KeyObject', otherKeyObject); + throw new ERR_INVALID_ARG_TYPE( + 'otherKeyObject', + 'KeyObject', + otherKeyObject + ); } return cryptoImpl.equals(this[kHandle], otherKeyObject[kHandle]); } - abstract get type() : KeyObjectType; + abstract get type(): KeyObjectType; get [Symbol.toStringTag]() { - return "KeyObject" + return 'KeyObject'; } } abstract class AsymmetricKeyObject extends KeyObject { - get asymmetricKeyDetails() : AsymmetricKeyDetails { + get asymmetricKeyDetails(): AsymmetricKeyDetails { let detail = cryptoImpl.getAsymmetricKeyDetail(this[kHandle]); if (isArrayBuffer(detail.publicExponent)) { - detail.publicExponent = arrayBufferToUnsignedBigInt(detail.publicExponent as any); + detail.publicExponent = arrayBufferToUnsignedBigInt( + detail.publicExponent as any + ); } return detail; } - get asymmetricKeyType() : AsymmetricKeyType { + get asymmetricKeyType(): AsymmetricKeyType { return cryptoImpl.getAsymmetricKeyType(this[kHandle]); } } export class PublicKeyObject extends AsymmetricKeyObject { - override export(options?: PublicKeyExportOptions) : KeyExportResult { + override export(options?: PublicKeyExportOptions): KeyExportResult { return super.export(options); } - get type() : KeyObjectType { return 'public'; } + get type(): KeyObjectType { + return 'public'; + } } export class PrivateKeyObject extends AsymmetricKeyObject { - override export(options?: PrivateKeyExportOptions) : KeyExportResult { + override export(options?: PrivateKeyExportOptions): KeyExportResult { return super.export(options); } - get type() : KeyObjectType { return 'private'; } + get type(): KeyObjectType { + return 'private'; + } } export class SecretKeyObject extends KeyObject { - get symmetricKeySize() : number { - return (this[kHandle].algorithm as any).length | 0 + get symmetricKeySize(): number { + return (this[kHandle].algorithm as any).length | 0; } - override export(options?: SecretKeyExportOptions) : KeyExportResult { + override export(options?: SecretKeyExportOptions): KeyExportResult { return super.export(options); } - get type() : KeyObjectType { return 'secret'; } + get type(): KeyObjectType { + return 'secret'; + } } type ValidateKeyDataOptions = { allowObject?: boolean; }; -function validateKeyData(key: unknown, name: string, options : ValidateKeyDataOptions = { - allowObject: false, -}) { - if (key == null || +function validateKeyData( + key: unknown, + name: string, + options: ValidateKeyDataOptions = { + allowObject: false, + } +) { + if ( + key == null || (typeof key !== 'string' && - (options.allowObject && typeof key !== 'object') && - !isArrayBufferView(key) && - !isAnyArrayBuffer(key))) { - const expected = [ - 'string', - 'ArrayBuffer', - 'TypedArray', - 'DataView' - ]; + options.allowObject && + typeof key !== 'object' && + !isArrayBufferView(key) && + !isAnyArrayBuffer(key)) + ) { + const expected = ['string', 'ArrayBuffer', 'TypedArray', 'DataView']; if (options.allowObject) expected.push('object'); throw new ERR_INVALID_ARG_TYPE(name, expected, key); } } -export function createSecretKey(key: string, encoding?: string) : SecretKeyObject; -export function createSecretKey(key: ArrayBuffer | ArrayBufferView) : SecretKeyObject; -export function createSecretKey(key: KeyData, encoding?: string) : SecretKeyObject { +export function createSecretKey( + key: string, + encoding?: string +): SecretKeyObject; +export function createSecretKey( + key: ArrayBuffer | ArrayBufferView +): SecretKeyObject; +export function createSecretKey( + key: KeyData, + encoding?: string +): SecretKeyObject { validateKeyData(key, 'key'); if (typeof key === 'string') key = Buffer.from(key as string, encoding); return KeyObject.from(cryptoImpl.createSecretKey(key)) as SecretKeyObject; @@ -328,10 +373,16 @@ export function createSecretKey(key: KeyData, encoding?: string) : SecretKeyObje // return inner; // } -export function createPrivateKey(key: string) : PrivateKeyObject; -export function createPrivateKey(key: ArrayBuffer | ArrayBufferView) : PrivateKeyObject; -export function createPrivateKey(key: CreateAsymmetricKeyOptions) : PrivateKeyObject; -export function createPrivateKey(_key: CreateAsymmetricKeyOptions | KeyData) : PrivateKeyObject { +export function createPrivateKey(key: string): PrivateKeyObject; +export function createPrivateKey( + key: ArrayBuffer | ArrayBufferView +): PrivateKeyObject; +export function createPrivateKey( + key: CreateAsymmetricKeyOptions +): PrivateKeyObject; +export function createPrivateKey( + _key: CreateAsymmetricKeyOptions | KeyData +): PrivateKeyObject { // The options here are fairly complex. The key data can be a string, // ArrayBuffer, or ArrayBufferView. The first argument can be one of // these or an object with a key property that is one of these. If the @@ -342,15 +393,18 @@ export function createPrivateKey(_key: CreateAsymmetricKeyOptions | KeyData) : P // validateAsymmetricKeyOptions(key, kPrivateKey))) as PrivateKeyObject; } -export function createPublicKey(key: string) : PublicKeyObject; -export function createPublicKey(key: ArrayBuffer) : PublicKeyObject; -export function createPublicKey(key: ArrayBufferView) : PublicKeyObject; - -export function createPublicKey(key: KeyObject) : PublicKeyObject; -export function createPublicKey(key: CryptoKey) : PublicKeyObject; -export function createPublicKey(key: CreateAsymmetricKeyOptions) : PublicKeyObject; -export function createPublicKey(_key: CreateAsymmetricKeyOptions | KeyData | CryptoKey | KeyObject) - : PublicKeyObject { +export function createPublicKey(key: string): PublicKeyObject; +export function createPublicKey(key: ArrayBuffer): PublicKeyObject; +export function createPublicKey(key: ArrayBufferView): PublicKeyObject; + +export function createPublicKey(key: KeyObject): PublicKeyObject; +export function createPublicKey(key: CryptoKey): PublicKeyObject; +export function createPublicKey( + key: CreateAsymmetricKeyOptions +): PublicKeyObject; +export function createPublicKey( + _key: CreateAsymmetricKeyOptions | KeyData | CryptoKey | KeyObject +): PublicKeyObject { // The options here are a bit complicated. The key material itself can // either be a string, ArrayBuffer, or ArrayBufferView. It is also // possible to pass a private key in the form of either a CryptoKey @@ -369,37 +423,45 @@ export function createPublicKey(_key: CreateAsymmetricKeyOptions | KeyData | Cry export type PublicKeyResult = KeyExportResult | PublicKeyObject; export type PrivateKeyResult = KeyExportResult | PrivateKeyObject; export type GenerateKeyCallback = (err?: any, key?: KeyObject) => void; -export type GenerateKeyPairCallback = - (err?: any, publicKey?: PublicKeyResult, privateKey?: PrivateKeyResult) => void; +export type GenerateKeyPairCallback = ( + err?: any, + publicKey?: PublicKeyResult, + privateKey?: PrivateKeyResult +) => void; export interface KeyObjectPair { publicKey: PublicKeyResult; privateKey: PrivateKeyResult; } -export function generateKey(_type: SecretKeyType, +export function generateKey( + _type: SecretKeyType, _options: GenerateKeyOptions, - callback: GenerateKeyCallback) { -// We intentionally have not implemented key generation up to this point. -// The reason is that generation of cryptographically safe keys is a CPU -// intensive operation that can often exceed limits on the amount of CPU -// time a worker is allowed. -callback(new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync')); + callback: GenerateKeyCallback +) { + // We intentionally have not implemented key generation up to this point. + // The reason is that generation of cryptographically safe keys is a CPU + // intensive operation that can often exceed limits on the amount of CPU + // time a worker is allowed. + callback(new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync')); } -export function generateKeySync(_type: SecretKeyType, - _options: GenerateKeyOptions) { -// We intentionally have not implemented key generation up to this point. -// The reason is that generation of cryptographically safe keys is a CPU -// intensive operation that can often exceed limits on the amount of CPU -// time a worker is allowed. -throw new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync'); +export function generateKeySync( + _type: SecretKeyType, + _options: GenerateKeyOptions +) { + // We intentionally have not implemented key generation up to this point. + // The reason is that generation of cryptographically safe keys is a CPU + // intensive operation that can often exceed limits on the amount of CPU + // time a worker is allowed. + throw new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync'); } export function generateKeyPair( - _type : AsymmetricKeyType, - _options: GenerateKeyPairOptions, - callback: GenerateKeyPairCallback) { + _type: AsymmetricKeyType, + _options: GenerateKeyPairOptions, + callback: GenerateKeyPairCallback +) { // We intentionally have not implemented key generation up to this point. // The reason is that generation of cryptographically safe keys is a CPU // intensive operation that can often exceed limits on the amount of CPU @@ -408,8 +470,9 @@ export function generateKeyPair( } export function generateKeyPairSync( - _type : AsymmetricKeyType, - _options: GenerateKeyPairOptions) : KeyObjectPair { + _type: AsymmetricKeyType, + _options: GenerateKeyPairOptions +): KeyObjectPair { // We intentionally have not implemented key generation up to this point. // The reason is that generation of cryptographically safe keys is a CPU // intensive operation that can often exceed limits on the amount of CPU diff --git a/src/node/internal/crypto_pbkdf2.ts b/src/node/internal/crypto_pbkdf2.ts index 87f864328cd..f193a443420 100644 --- a/src/node/internal/crypto_pbkdf2.ts +++ b/src/node/internal/crypto_pbkdf2.ts @@ -30,11 +30,9 @@ import { default as cryptoImpl } from 'node-internal:crypto'; type ArrayLike = cryptoImpl.ArrayLike; -export {ArrayLike}; +export { ArrayLike }; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { validateInt32, @@ -42,41 +40,74 @@ import { validateString, } from 'node-internal:validators'; -import { - getArrayBufferOrView, -} from 'node-internal:crypto_util'; +import { getArrayBufferOrView } from 'node-internal:crypto_util'; -export function pbkdf2Sync(password: ArrayLike, salt: ArrayLike, iterations: number, - keylen: number, digest: string): Buffer { - ({ password, salt, iterations, keylen, digest } = - check(password, salt, iterations, keylen, digest)); +export function pbkdf2Sync( + password: ArrayLike, + salt: ArrayLike, + iterations: number, + keylen: number, + digest: string +): Buffer { + ({ password, salt, iterations, keylen, digest } = check( + password, + salt, + iterations, + keylen, + digest + )); - const result = cryptoImpl.getPbkdf(password, salt, iterations, keylen, digest); + const result = cryptoImpl.getPbkdf( + password, + salt, + iterations, + keylen, + digest + ); return Buffer.from(result); } -export type Pbkdf2Callback = (err?: Error|null, result?: Buffer) => void; -export function pbkdf2(password: ArrayLike, salt: ArrayLike, iterations: number, keylen: number, - digest: string, callback: Pbkdf2Callback): void { +export type Pbkdf2Callback = (err?: Error | null, result?: Buffer) => void; +export function pbkdf2( + password: ArrayLike, + salt: ArrayLike, + iterations: number, + keylen: number, + digest: string, + callback: Pbkdf2Callback +): void { if (typeof digest === 'function') { // Appease node test cases validateString(undefined, 'digest'); } validateFunction(callback, 'callback'); - ({ password, salt, iterations, keylen, digest } = - check(password, salt, iterations, keylen, digest)); + ({ password, salt, iterations, keylen, digest } = check( + password, + salt, + iterations, + keylen, + digest + )); new Promise((res, rej) => { try { res(cryptoImpl.getPbkdf(password, salt, iterations, keylen, digest)); - } catch(err) { + } catch (err) { rej(err); } - }).then((val) => callback(null, Buffer.from(val)), (err) => callback(err)); + }).then( + (val) => callback(null, Buffer.from(val)), + (err) => callback(err) + ); } -function check(password: ArrayLike|ArrayBufferView, salt: ArrayLike|ArrayBufferView, iterations: number, keylen: number, - digest: string): any { +function check( + password: ArrayLike | ArrayBufferView, + salt: ArrayLike | ArrayBufferView, + iterations: number, + keylen: number, + digest: string +): any { validateString(digest, 'digest'); password = getArrayBufferOrView(password, 'password'); diff --git a/src/node/internal/crypto_random.ts b/src/node/internal/crypto_random.ts index 8fd22fd4d01..50777ceb78a 100644 --- a/src/node/internal/crypto_random.ts +++ b/src/node/internal/crypto_random.ts @@ -38,7 +38,7 @@ import { import { isAnyArrayBuffer, - isArrayBufferView + isArrayBufferView, } from 'node-internal:internal_types'; import { @@ -46,19 +46,17 @@ import { ERR_OUT_OF_RANGE, } from 'node-internal:internal_errors'; -import { - Buffer, - kMaxLength -} from 'node-internal:internal_buffer'; +import { Buffer, kMaxLength } from 'node-internal:internal_buffer'; -import { - arrayBufferToUnsignedBigInt, -} from 'node-internal:crypto_util'; +import { arrayBufferToUnsignedBigInt } from 'node-internal:crypto_util'; -export type RandomBytesCallback = (err: any|null, buffer: Uint8Array) => void; +export type RandomBytesCallback = (err: any | null, buffer: Uint8Array) => void; export function randomBytes(size: number, callback: RandomBytesCallback): void; export function randomBytes(size: number): Uint8Array; -export function randomBytes(size: number, callback?: RandomBytesCallback) : Uint8Array|void{ +export function randomBytes( + size: number, + callback?: RandomBytesCallback +): Uint8Array | void { validateInteger(size, 'size', 0, kMaxLength); const buf = Buffer.alloc(size); if (callback !== undefined) { @@ -70,16 +68,16 @@ export function randomBytes(size: number, callback?: RandomBytesCallback) : Uint } export function randomFillSync( - buffer: NodeJS.ArrayBufferView, - offset?: number, - size?: number) { + buffer: NodeJS.ArrayBufferView, + offset?: number, + size?: number +) { if (!isAnyArrayBuffer(buffer) && !isArrayBufferView(buffer)) { - throw new ERR_INVALID_ARG_TYPE('buffer', [ - 'TypedArray', - 'DataView', - 'ArrayBuffer', - 'SharedArrayBuffer' - ], buffer); + throw new ERR_INVALID_ARG_TYPE( + 'buffer', + ['TypedArray', 'DataView', 'ArrayBuffer', 'SharedArrayBuffer'], + buffer + ); } const maxLength = (buffer as Uint8Array).length; if (offset !== undefined) { @@ -95,27 +93,37 @@ export function randomFillSync( return crypto.getRandomValues(buffer); } -export type RandomFillCallback = (err: any|null, buf?: NodeJS.ArrayBufferView) => void; -export function randomFill(buffer: NodeJS.ArrayBufferView, - callback?: RandomFillCallback) : void; -export function randomFill(buffer: NodeJS.ArrayBufferView, - offset: number, - callback?: RandomFillCallback) : void; - export function randomFill(buffer: NodeJS.ArrayBufferView, - offset: number, - size: number, - callback?: RandomFillCallback) : void; -export function randomFill(buffer: NodeJS.ArrayBufferView, - offsetOrCallback?: number|RandomFillCallback, - sizeOrCallback?: number|RandomFillCallback, - callback?: RandomFillCallback) { +export type RandomFillCallback = ( + err: any | null, + buf?: NodeJS.ArrayBufferView +) => void; +export function randomFill( + buffer: NodeJS.ArrayBufferView, + callback?: RandomFillCallback +): void; +export function randomFill( + buffer: NodeJS.ArrayBufferView, + offset: number, + callback?: RandomFillCallback +): void; +export function randomFill( + buffer: NodeJS.ArrayBufferView, + offset: number, + size: number, + callback?: RandomFillCallback +): void; +export function randomFill( + buffer: NodeJS.ArrayBufferView, + offsetOrCallback?: number | RandomFillCallback, + sizeOrCallback?: number | RandomFillCallback, + callback?: RandomFillCallback +) { if (!isAnyArrayBuffer(buffer) && !isArrayBufferView(buffer)) { - throw new ERR_INVALID_ARG_TYPE('buffer', [ - 'TypedArray', - 'DataView', - 'ArrayBuffer', - 'SharedArrayBuffer' - ], buffer); + throw new ERR_INVALID_ARG_TYPE( + 'buffer', + ['TypedArray', 'DataView', 'ArrayBuffer', 'SharedArrayBuffer'], + buffer + ); } let offset = 0; @@ -144,10 +152,13 @@ export function randomFill(buffer: NodeJS.ArrayBufferView, new Promise((res) => { randomFillSync(buffer, offset, size); res(); - }).then(() => callback!(null, buffer), (err: any) => callback!(err)); + }).then( + () => callback!(null, buffer), + (err: any) => callback!(err) + ); } -const RAND_MAX = 0xFFFF_FFFF_FFFF; +const RAND_MAX = 0xffff_ffff_ffff; // Cache random data to use in randomInt. The cache size must be evenly // divisible by 6 because each attempt to obtain a random int uses 6 bytes. const randomCache = Buffer.alloc(6 * 1024); @@ -163,7 +174,11 @@ function getRandomInt(min: number, max: number) { const range = max - min; if (!(range <= RAND_MAX)) { - throw new ERR_OUT_OF_RANGE(`max${max ? '' : ' - min'}`, `<= ${RAND_MAX}`, range); + throw new ERR_OUT_OF_RANGE( + `max${max ? '' : ' - min'}`, + `<= ${RAND_MAX}`, + range + ); } // For (x % range) to produce an unbiased value greater than or equal to 0 and @@ -190,14 +205,20 @@ function getRandomInt(min: number, max: number) { return 0; // Should be unreachable. } -export type RandomIntCallback = (err: any|null, n?: number) => void; -export function randomInt(max: number) : number; -export function randomInt(min: number, max: number) : number; -export function randomInt(max: number, callback: RandomIntCallback) : void; -export function randomInt(min: number, max: number, callback: RandomIntCallback) : void; -export function randomInt(minOrMax: number, - maxOrCallback?: number|RandomIntCallback, - callback?: RandomIntCallback) { +export type RandomIntCallback = (err: any | null, n?: number) => void; +export function randomInt(max: number): number; +export function randomInt(min: number, max: number): number; +export function randomInt(max: number, callback: RandomIntCallback): void; +export function randomInt( + min: number, + max: number, + callback: RandomIntCallback +): void; +export function randomInt( + minOrMax: number, + maxOrCallback?: number | RandomIntCallback, + callback?: RandomIntCallback +) { let min = 0; let max = 0; if (typeof callback === 'function') { @@ -228,7 +249,10 @@ export function randomInt(minOrMax: number, if (callback !== undefined) { new Promise((res) => { res(getRandomInt(min, max)); - }).then((n: number) => callback!(null, n), (err: any) => callback!(err)); + }).then( + (n: number) => callback!(null, n), + (err: any) => callback!(err) + ); return; } else { return getRandomInt(min, max); @@ -241,7 +265,10 @@ export function randomUUID(options?: any) { if (options !== undefined) { validateObject(options, 'options', options); if (options.disableEntropyCache !== undefined) { - validateBoolean(options.disableEntropyCache, 'options.disableEntropyCache'); + validateBoolean( + options.disableEntropyCache, + 'options.disableEntropyCache' + ); } } return crypto.randomUUID(); @@ -259,23 +286,21 @@ export interface CheckPrimeOptions { checks?: number; } -export type GeneratePrimeCallback = (err?: any, prime?: bigint|ArrayBuffer) => void; +export type GeneratePrimeCallback = ( + err?: any, + prime?: bigint | ArrayBuffer +) => void; export type CheckPrimeCallback = (err?: any, prime?: boolean) => void; -function processGeneratePrimeOptions(options: GeneratePrimeOptions) : { - add: ArrayBufferView, - rem: ArrayBufferView, - safe: boolean, - bigint: boolean } { +function processGeneratePrimeOptions(options: GeneratePrimeOptions): { + add: ArrayBufferView; + rem: ArrayBufferView; + safe: boolean; + bigint: boolean; +} { validateObject(options, 'options', {}); - const { - safe = false, - bigint = false, - } = options; - let { - add, - rem, - } = options; + const { safe = false, bigint = false } = options; + let { add, rem } = options; validateBoolean(safe, 'options.safe'); validateBoolean(bigint, 'options.bigint'); @@ -285,14 +310,9 @@ function processGeneratePrimeOptions(options: GeneratePrimeOptions) : { } else if (!isAnyArrayBuffer(add) && !isArrayBufferView(add)) { throw new ERR_INVALID_ARG_TYPE( 'options.add', - [ - 'ArrayBuffer', - 'TypedArray', - 'Buffer', - 'DataView', - 'bigint', - ], - add); + ['ArrayBuffer', 'TypedArray', 'Buffer', 'DataView', 'bigint'], + add + ); } } @@ -302,14 +322,9 @@ function processGeneratePrimeOptions(options: GeneratePrimeOptions) : { } else if (!isAnyArrayBuffer(rem) && !isArrayBufferView(rem)) { throw new ERR_INVALID_ARG_TYPE( 'options.rem', - [ - 'ArrayBuffer', - 'TypedArray', - 'Buffer', - 'DataView', - 'bigint', - ], - rem); + ['ArrayBuffer', 'TypedArray', 'Buffer', 'DataView', 'bigint'], + rem + ); } } @@ -318,29 +333,34 @@ function processGeneratePrimeOptions(options: GeneratePrimeOptions) : { bigint, add: add as ArrayBufferView, rem: rem as ArrayBufferView, - } + }; } -export function generatePrimeSync(size: number, options: GeneratePrimeOptions = {}) { +export function generatePrimeSync( + size: number, + options: GeneratePrimeOptions = {} +) { validateInt32(size, 'size', 1); - const { - safe, - bigint, - add, - rem, - } = processGeneratePrimeOptions(options); + const { safe, bigint, add, rem } = processGeneratePrimeOptions(options); let primeBuf = cryptoImpl.randomPrime(size, safe, add, rem); return bigint ? arrayBufferToUnsignedBigInt(primeBuf) : primeBuf; } -export function generatePrime(size: number, - options: GeneratePrimeOptions, - callback: GeneratePrimeCallback) : void; -export function generatePrime(size: number, callback: GeneratePrimeCallback) : void; -export function generatePrime(size: number, - options: GeneratePrimeOptions|GeneratePrimeCallback, - callback?: GeneratePrimeCallback) : void { +export function generatePrime( + size: number, + options: GeneratePrimeOptions, + callback: GeneratePrimeCallback +): void; +export function generatePrime( + size: number, + callback: GeneratePrimeCallback +): void; +export function generatePrime( + size: number, + options: GeneratePrimeOptions | GeneratePrimeCallback, + callback?: GeneratePrimeCallback +): void { validateInt32(size, 'size', 1); if (typeof options === 'function') { callback = options; @@ -348,21 +368,21 @@ export function generatePrime(size: number, } validateFunction(callback, 'callback'); - const { - safe, - bigint, - add, - rem - } = processGeneratePrimeOptions(options as GeneratePrimeOptions); + const { safe, bigint, add, rem } = processGeneratePrimeOptions( + options as GeneratePrimeOptions + ); - new Promise((res, rej) => { + new Promise((res, rej) => { try { const primeBuf = cryptoImpl.randomPrime(size, safe, add, rem); res(bigint ? arrayBufferToUnsignedBigInt(primeBuf) : primeBuf); - } catch(err) { + } catch (err) { rej(err); } - }).then((val) => callback!(null, val), (err) => callback!(err)); + }).then( + (val) => callback!(null, val), + (err) => callback!(err) + ); } function unsignedBigIntToBuffer(bigint: bigint, name: string) { @@ -375,49 +395,50 @@ function unsignedBigIntToBuffer(bigint: bigint, name: string) { return Buffer.from(padded, 'hex'); } -function validateCandidate(candidate: PrimeNum) : Buffer { +function validateCandidate(candidate: PrimeNum): Buffer { if (typeof candidate === 'bigint') candidate = unsignedBigIntToBuffer(candidate, 'candidate'); if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) { throw new ERR_INVALID_ARG_TYPE( 'candidate', - [ - 'ArrayBuffer', - 'TypedArray', - 'Buffer', - 'DataView', - 'bigint', - ], - candidate, + ['ArrayBuffer', 'TypedArray', 'Buffer', 'DataView', 'bigint'], + candidate ); } return candidate as Buffer; } -function validateChecks(options : CheckPrimeOptions) : number { - const { - checks = 0, - } = options; +function validateChecks(options: CheckPrimeOptions): number { + const { checks = 0 } = options; // The checks option is unsigned but must fit into a signed 32-bit integer for OpenSSL. validateInt32(checks, 'options.checks', 0); return checks; } -export function checkPrimeSync(candidate: PrimeNum, options: CheckPrimeOptions = {}) { +export function checkPrimeSync( + candidate: PrimeNum, + options: CheckPrimeOptions = {} +) { candidate = validateCandidate(candidate); validateObject(options, 'options', {}); const checks = validateChecks(options); return cryptoImpl.checkPrimeSync(candidate as ArrayBufferView, checks); } -export function checkPrime(candidate: PrimeNum, - options: CheckPrimeOptions, - callback: CheckPrimeCallback) : void; -export function checkPrime(candidate: PrimeNum, - callback: CheckPrimeCallback) : void; -export function checkPrime(candidate: PrimeNum, - options: CheckPrimeOptions|CheckPrimeCallback, - callback?: CheckPrimeCallback) : void { +export function checkPrime( + candidate: PrimeNum, + options: CheckPrimeOptions, + callback: CheckPrimeCallback +): void; +export function checkPrime( + candidate: PrimeNum, + callback: CheckPrimeCallback +): void; +export function checkPrime( + candidate: PrimeNum, + options: CheckPrimeOptions | CheckPrimeCallback, + callback?: CheckPrimeCallback +): void { candidate = validateCandidate(candidate); if (typeof options === 'function') { callback = options; @@ -429,8 +450,11 @@ export function checkPrime(candidate: PrimeNum, new Promise((res, rej) => { try { res(cryptoImpl.checkPrimeSync(candidate as ArrayBufferView, checks)); - } catch(err) { + } catch (err) { rej(err); } - }).then((val) => callback!(null, val), (err) => callback!(err)); + }).then( + (val) => callback!(null, val), + (err) => callback!(err) + ); } diff --git a/src/node/internal/crypto_scrypt.ts b/src/node/internal/crypto_scrypt.ts index 2ef10e31ab6..1df3d7b3fe9 100644 --- a/src/node/internal/crypto_scrypt.ts +++ b/src/node/internal/crypto_scrypt.ts @@ -36,33 +36,25 @@ import { validateUint32, } from 'node-internal:validators'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; type ArrayLike = cryptoImpl.ArrayLike; -import { - kMaxLength, -} from 'node-internal:internal_buffer'; +import { kMaxLength } from 'node-internal:internal_buffer'; -import { - getArrayBufferOrView, -} from 'node-internal:crypto_util'; +import { getArrayBufferOrView } from 'node-internal:crypto_util'; -import { - ERR_INVALID_ARG_VALUE, -} from 'node-internal:internal_errors'; +import { ERR_INVALID_ARG_VALUE } from 'node-internal:internal_errors'; export interface ValidatedScryptOptions { password: ArrayLike; salt: ArrayLike; - keylen: number + keylen: number; N: number; r: number; p: number; maxmem: number; -}; +} export interface ScryptOptions { N?: number; @@ -72,7 +64,7 @@ export interface ScryptOptions { cost?: number; blockSize?: number; parallelization?: number; -}; +} const defaults: ScryptOptions = { N: 16384, @@ -81,8 +73,12 @@ const defaults: ScryptOptions = { maxmem: 32 << 20, }; -function validateParameters(password: ArrayLike, salt: ArrayLike, - keylen: number, options: ScryptOptions) : ValidatedScryptOptions { +function validateParameters( + password: ArrayLike, + salt: ArrayLike, + keylen: number, + options: ScryptOptions +): ValidatedScryptOptions { // TODO(soon): Add support for KeyObject input. password = getArrayBufferOrView(password, 'password'); salt = getArrayBufferOrView(salt, 'salt'); @@ -108,13 +104,14 @@ function validateParameters(password: ArrayLike, salt: ArrayLike, N = options.cost; validateUint32(N, 'cost'); } - const has_r = (options.r !== undefined); + const has_r = options.r !== undefined; if (has_r) { r = options.r; validateUint32(r, 'r'); } if (options.blockSize !== undefined) { - if (has_r) throw new ERR_INVALID_ARG_VALUE('blockSize', options.blockSize); + if (has_r) + throw new ERR_INVALID_ARG_VALUE('blockSize', options.blockSize); r = options.blockSize; validateUint32(r, 'blockSize'); } @@ -124,7 +121,11 @@ function validateParameters(password: ArrayLike, salt: ArrayLike, validateUint32(p, 'p'); } if (options.parallelization !== undefined) { - if (has_p) throw new ERR_INVALID_ARG_VALUE('parallelization', options.parallelization); + if (has_p) + throw new ERR_INVALID_ARG_VALUE( + 'parallelization', + options.parallelization + ); p = options.parallelization; validateUint32(p, 'parallelization'); } @@ -141,13 +142,16 @@ function validateParameters(password: ArrayLike, salt: ArrayLike, return { password, salt, keylen, N: N!, r: r!, p: p!, maxmem: maxmem! }; } -type Callback = (err: Error|null, derivedKey?: ArrayBuffer) => void; +type Callback = (err: Error | null, derivedKey?: ArrayBuffer) => void; type OptionsOrCallback = ScryptOptions | Callback; -export function scrypt(password: ArrayLike, salt: ArrayLike, - keylen: number, - options: OptionsOrCallback, - callback: OptionsOrCallback = defaults) { +export function scrypt( + password: ArrayLike, + salt: ArrayLike, + keylen: number, + options: OptionsOrCallback, + callback: OptionsOrCallback = defaults +) { if (callback === defaults) { callback = options; options = defaults; @@ -157,45 +161,47 @@ export function scrypt(password: ArrayLike, salt: ArrayLike, let r: number; let p: number; let maxmem: number; - ({ + ({ password, salt, keylen, N, r, p, maxmem } = validateParameters( password, salt, keylen, - N, - r, - p, - maxmem, - } = validateParameters(password, salt, keylen, options as ScryptOptions)); + options as ScryptOptions + )); validateFunction(callback, 'callback'); new Promise((res, rej) => { try { res(cryptoImpl.getScrypt(password, salt, N, r, p, maxmem, keylen)); - } catch(err) { + } catch (err) { rej(err); } - }).then((val: ArrayBuffer) => { - (callback as Callback)(null, Buffer.from(val)); - }, (err) => (callback as Callback)(err)); + }).then( + (val: ArrayBuffer) => { + (callback as Callback)(null, Buffer.from(val)); + }, + (err) => (callback as Callback)(err) + ); } -export function scryptSync(password: ArrayLike, salt: ArrayLike, - keylen: number, options: ScryptOptions): ArrayBuffer { +export function scryptSync( + password: ArrayLike, + salt: ArrayLike, + keylen: number, + options: ScryptOptions +): ArrayBuffer { let N: number; let r: number; let p: number; let maxmem: number; - ({ + ({ password, salt, keylen, N, r, p, maxmem } = validateParameters( password, salt, keylen, - N, - r, - p, - maxmem, - } = validateParameters(password, salt, keylen, options)); + options + )); - return Buffer.from(cryptoImpl.getScrypt(password, salt, N, r, p, maxmem, keylen)); + return Buffer.from( + cryptoImpl.getScrypt(password, salt, N, r, p, maxmem, keylen) + ); } - diff --git a/src/node/internal/crypto_spkac.ts b/src/node/internal/crypto_spkac.ts index 3e5ddeb6a12..d014ea77f8e 100644 --- a/src/node/internal/crypto_spkac.ts +++ b/src/node/internal/crypto_spkac.ts @@ -27,28 +27,35 @@ /* eslint-disable */ import { default as cryptoImpl } from 'node-internal:crypto'; -import { - StringLike, - Buffer, -} from 'node-internal:internal_buffer'; +import { StringLike, Buffer } from 'node-internal:internal_buffer'; -import { - getArrayBufferOrView, -} from 'node-internal:crypto_util'; +import { getArrayBufferOrView } from 'node-internal:crypto_util'; type ArrayLike = cryptoImpl.ArrayLike; export function verifySpkac(spkac: StringLike | ArrayLike, encoding?: string) { - return cryptoImpl.verifySpkac(getArrayBufferOrView(spkac as any, 'spkac', encoding)); + return cryptoImpl.verifySpkac( + getArrayBufferOrView(spkac as any, 'spkac', encoding) + ); } -export function exportPublicKey(spkac: StringLike | ArrayLike, encoding?: string) { - const ret = cryptoImpl.exportPublicKey(getArrayBufferOrView(spkac as any, 'spkac', encoding)); +export function exportPublicKey( + spkac: StringLike | ArrayLike, + encoding?: string +) { + const ret = cryptoImpl.exportPublicKey( + getArrayBufferOrView(spkac as any, 'spkac', encoding) + ); return ret ? Buffer.from(ret) : Buffer.alloc(0); } -export function exportChallenge(spkac: StringLike | ArrayLike, encoding?: string) { - const ret = cryptoImpl.exportChallenge(getArrayBufferOrView(spkac as any, 'spkac', encoding)); +export function exportChallenge( + spkac: StringLike | ArrayLike, + encoding?: string +) { + const ret = cryptoImpl.exportChallenge( + getArrayBufferOrView(spkac as any, 'spkac', encoding) + ); return ret ? Buffer.from(ret) : Buffer.alloc(0); } @@ -61,8 +68,7 @@ export function exportChallenge(spkac: StringLike | ArrayLike, encoding?: string // For backwards compatibility reasons, this cannot be converted into a // ES6 Class. export function Certificate(this: any) { - if (!(this instanceof Certificate)) - return new (Certificate as any)(); + if (!(this instanceof Certificate)) return new (Certificate as any)(); } Certificate.prototype.verifySpkac = verifySpkac; diff --git a/src/node/internal/crypto_util.ts b/src/node/internal/crypto_util.ts index d21d9067c51..18d7f8f4026 100644 --- a/src/node/internal/crypto_util.ts +++ b/src/node/internal/crypto_util.ts @@ -28,22 +28,16 @@ 'use strict'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { - isAnyArrayBuffer, - isArrayBufferView, + isAnyArrayBuffer, + isArrayBufferView, } from 'node-internal:internal_types'; -import { - ERR_INVALID_ARG_TYPE, -} from 'node-internal:internal_errors'; +import { ERR_INVALID_ARG_TYPE } from 'node-internal:internal_errors'; -import { - validateString, -} from 'node-internal:validators'; +import { validateString } from 'node-internal:validators'; import { default as cryptoImpl } from 'node-internal:crypto'; type ArrayLike = cryptoImpl.ArrayLike; @@ -59,9 +53,12 @@ export function getStringOption(options: any, key: string) { return value; } -export function getArrayBufferOrView(buffer: Buffer | ArrayBuffer | ArrayBufferView | string, name: string, encoding?: string): Buffer | ArrayBuffer | ArrayBufferView { - if (isAnyArrayBuffer(buffer)) - return buffer as ArrayBuffer; +export function getArrayBufferOrView( + buffer: Buffer | ArrayBuffer | ArrayBufferView | string, + name: string, + encoding?: string +): Buffer | ArrayBuffer | ArrayBufferView { + if (isAnyArrayBuffer(buffer)) return buffer as ArrayBuffer; if (typeof buffer === 'string') { if (encoding === undefined || encoding === 'buffer') { encoding = 'utf8'; @@ -71,14 +68,8 @@ export function getArrayBufferOrView(buffer: Buffer | ArrayBuffer | ArrayBufferV if (!isArrayBufferView(buffer)) { throw new ERR_INVALID_ARG_TYPE( name, - [ - 'string', - 'ArrayBuffer', - 'Buffer', - 'TypedArray', - 'DataView', - ], - buffer, + ['string', 'ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], + buffer ); } return buffer; @@ -90,7 +81,8 @@ export function getArrayBufferOrView(buffer: Buffer | ArrayBuffer | ArrayBufferV * @returns {number} corresponding to the ASCII code of the hex representation * of the parameter. */ -export const numberToHexCharCode = (number: number): number => (number < 10 ? 48 : 87) + number; +export const numberToHexCharCode = (number: number): number => + (number < 10 ? 48 : 87) + number; /** * @param {ArrayBuffer} buf An ArrayBuffer. @@ -113,7 +105,10 @@ export function arrayBufferToUnsignedBigInt(buf: ArrayBuffer): bigint { // This is here because many functions accepted binary strings without // any explicit encoding in older versions of node, and we don't want // to break them unnecessarily. -export function toBuf(val: ArrayLike, encoding?: string): Buffer|ArrayBuffer|ArrayBufferView { +export function toBuf( + val: ArrayLike, + encoding?: string +): Buffer | ArrayBuffer | ArrayBufferView { if (typeof val === 'string') { if (encoding === 'buffer') { encoding = 'utf8'; @@ -123,8 +118,10 @@ export function toBuf(val: ArrayLike, encoding?: string): Buffer|ArrayBuffer|Arr return val; } -export function validateByteSource(val: ArrayLike, - name: string): Buffer|ArrayBuffer|ArrayBufferView { +export function validateByteSource( + val: ArrayLike, + name: string +): Buffer | ArrayBuffer | ArrayBufferView { val = toBuf(val); if (isAnyArrayBuffer(val) || isArrayBufferView(val)) { @@ -133,12 +130,7 @@ export function validateByteSource(val: ArrayLike, throw new ERR_INVALID_ARG_TYPE( name, - [ - 'string', - 'ArrayBuffer', - 'TypedArray', - 'DataView', - 'Buffer', - ], - val); + ['string', 'ArrayBuffer', 'TypedArray', 'DataView', 'Buffer'], + val + ); } diff --git a/src/node/internal/crypto_x509.ts b/src/node/internal/crypto_x509.ts index ddbc847133b..c08405ca895 100644 --- a/src/node/internal/crypto_x509.ts +++ b/src/node/internal/crypto_x509.ts @@ -26,10 +26,7 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - default as cryptoImpl, - CheckOptions, -} from 'node-internal:crypto'; +import { default as cryptoImpl, CheckOptions } from 'node-internal:crypto'; import { validateString, @@ -37,27 +34,18 @@ import { validateBoolean, } from 'node-internal:validators'; -import { - isArrayBufferView, -} from 'node-internal:internal_types'; +import { isArrayBufferView } from 'node-internal:internal_types'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, } from 'node-internal:internal_errors'; -import { - kHandle, -} from 'node-internal:crypto_util'; +import { kHandle } from 'node-internal:crypto_util'; -import { - PublicKeyObject, - PrivateKeyObject, -} from 'node-internal:crypto_keys'; +import { PublicKeyObject, PrivateKeyObject } from 'node-internal:crypto_keys'; function translatePeerCertificate(c: any) { if (!c) return null; @@ -71,7 +59,7 @@ function translatePeerCertificate(c: any) { // XXX: More key validation? const regex = /([^\n:]*):([^\n]*)(?:\n|$)/g; - regex[Symbol.replace](info, (_: any, key: any, val: any) : any => { + regex[Symbol.replace](info, (_: any, key: any, val: any): any => { if (val.charCodeAt(0) === 0x22) { // The translatePeerCertificate function is only // used on internally created legacy certificate @@ -80,10 +68,8 @@ function translatePeerCertificate(c: any) { // so this should never throw. val = JSON.parse(val); } - if (key in c.infoAccess) - c.infoAccess[key].push(val); - else - c.infoAccess[key] = [val]; + if (key in c.infoAccess) c.infoAccess[key].push(val); + else c.infoAccess[key] = [val]; }); } return c; @@ -97,7 +83,10 @@ function checkOptions(options?: CheckOptions) { if (options.partialWildcards !== undefined) validateBoolean(options.partialWildcards, 'options.partialWildcards'); if (options.singleLabelSubdomains !== undefined) - validateBoolean(options.singleLabelSubdomains, 'options.singleLabelSubdomains'); + validateBoolean( + options.singleLabelSubdomains, + 'options.singleLabelSubdomains' + ); if (options.wildcards !== undefined) validateBoolean(options.wildcards, 'options.wildcards'); if (options.subject !== undefined) @@ -108,7 +97,9 @@ export class X509Certificate { #handle?: cryptoImpl.X509Certificate = undefined; #state = new Map(); - constructor(buffer: ArrayBufferView | ArrayBuffer | cryptoImpl.X509Certificate | string) { + constructor( + buffer: ArrayBufferView | ArrayBuffer | cryptoImpl.X509Certificate | string + ) { if (buffer instanceof cryptoImpl.X509Certificate) { this.#handle = buffer; return; @@ -117,8 +108,11 @@ export class X509Certificate { buffer = Buffer.from(buffer); } if (!isArrayBufferView(buffer)) { - throw new ERR_INVALID_ARG_TYPE('buffer', - ['string', 'Buffer', 'TypedArray', 'DataView'], buffer); + throw new ERR_INVALID_ARG_TYPE( + 'buffer', + ['string', 'Buffer', 'TypedArray', 'DataView'], + buffer + ); } this.#handle = cryptoImpl.X509Certificate.parse(buffer); } @@ -154,8 +148,7 @@ export class X509Certificate { let value = this.#state.get('issuerCertificate'); if (value === undefined) { const cert = this.#handle!.issuerCert; - if (cert) - value = new X509Certificate(cert); + if (cert) value = new X509Certificate(cert); this.#state.set('issuerCertificate', value); } return value ?? undefined; @@ -267,7 +260,9 @@ export class X509Certificate { // There's no standardized JSON encoding for X509 certs so we // fallback to providing the PEM encoding as a string. - toJSON() { return this.toString(); } + toJSON() { + return this.toString(); + } get ca() { let value = this.#state.get('ca'); @@ -310,16 +305,14 @@ export class X509Certificate { checkPrivateKey(pkey: PrivateKeyObject) { if (!(pkey instanceof PrivateKeyObject)) throw new ERR_INVALID_ARG_TYPE('pkey', 'KeyObject', pkey); - if (pkey.type !== 'private') - throw new ERR_INVALID_ARG_VALUE('pkey', pkey); + if (pkey.type !== 'private') throw new ERR_INVALID_ARG_VALUE('pkey', pkey); return this.#handle!.checkPrivateKey(pkey[kHandle]) ?? undefined; } verify(pkey: PublicKeyObject) { if (!(pkey instanceof PublicKeyObject)) throw new ERR_INVALID_ARG_TYPE('pkey', 'KeyObject', pkey); - if (pkey.type !== 'public') - throw new ERR_INVALID_ARG_VALUE('pkey', pkey); + if (pkey.type !== 'public') throw new ERR_INVALID_ARG_VALUE('pkey', pkey); return this.#handle!.verify(pkey[kHandle]); } diff --git a/src/node/internal/debuglog.ts b/src/node/internal/debuglog.ts index 038416be537..7a88f94a315 100644 --- a/src/node/internal/debuglog.ts +++ b/src/node/internal/debuglog.ts @@ -25,17 +25,14 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - format, - formatWithOptions, -} from 'node-internal:internal_inspect'; +import { format, formatWithOptions } from 'node-internal:internal_inspect'; -let debugImpls : object = {}; +let debugImpls: object = {}; function debuglogImpl(set: string) { if ((debugImpls as any)[set] === undefined) { - (debugImpls as any)[set] = function debug(...args : any[]) { - const msg = formatWithOptions({ }, ...args); + (debugImpls as any)[set] = function debug(...args: any[]) { + const msg = formatWithOptions({}, ...args); console.log(format('%s: %s\n', set, msg)); }; } @@ -45,31 +42,42 @@ function debuglogImpl(set: string) { // In Node.js' implementation, debuglog availability is determined by the NODE_DEBUG // environment variable. However, we don't have access to the environment variables // in the same way. Instead, we'll just always enable debuglog on the requested sets. -export function debuglog(set : string, cb? : (debug : (...args : any[]) => void) => void): any { +export function debuglog( + set: string, + cb?: (debug: (...args: any[]) => void) => void +): any { function init() { set = set.toUpperCase(); } - let debug = (...args : any[]): void => { + let debug = (...args: any[]): void => { init(); debug = debuglogImpl(set); if (typeof cb === 'function') { cb(debug); } switch (args.length) { - case 1: return debug(args[0]); - case 2: return debug(args[0], args[1]); - default: return debug(...args); + case 1: + return debug(args[0]); + case 2: + return debug(args[0], args[1]); + default: + return debug(...args); } }; - const logger = (...args : any[]) => { + const logger = (...args: any[]) => { switch (args.length) { - case 1: return debug(args[0]); - case 2: return debug(args[0], args[1]); - default: return debug(...args); + case 1: + return debug(args[0]); + case 2: + return debug(args[0], args[1]); + default: + return debug(...args); } }; Object.defineProperty(logger, 'enabled', { - get() { return true; }, + get() { + return true; + }, configurable: true, enumerable: true, }); diff --git a/src/node/internal/diagnostics_channel.d.ts b/src/node/internal/diagnostics_channel.d.ts index 151201a47e8..2780657528d 100644 --- a/src/node/internal/diagnostics_channel.d.ts +++ b/src/node/internal/diagnostics_channel.d.ts @@ -5,7 +5,7 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { AsyncLocalStorage } from "node-internal:async_hooks"; +import { AsyncLocalStorage } from 'node-internal:async_hooks'; export type TransformCallback = (value: any) => any; @@ -14,17 +14,27 @@ export abstract class Channel { publish(message: any): void; subscribe(callback: MessageCallback): void; unsubscribe(callback: MessageCallback): void; - bindStore(context: AsyncLocalStorage, - transform?: TransformCallback): void; + bindStore( + context: AsyncLocalStorage, + transform?: TransformCallback + ): void; unbindStore(context: AsyncLocalStorage): void; - runStores(context: any, - fn: (...args: any[]) => any, - receiver?: any, - ...args: any[]): any; + runStores( + context: any, + fn: (...args: any[]) => any, + receiver?: any, + ...args: any[] + ): any; } -export type MessageCallback = (message: any, name: string|symbol) => void; -export function hasSubscribers(name: string|symbol) : boolean; -export function channel(name: string|symbol) : Channel; -export function subscribe(name: string|symbol, callback: MessageCallback) : void; -export function unsubscribe(name: string|symbol, callback: MessageCallback) : void; +export type MessageCallback = (message: any, name: string | symbol) => void; +export function hasSubscribers(name: string | symbol): boolean; +export function channel(name: string | symbol): Channel; +export function subscribe( + name: string | symbol, + callback: MessageCallback +): void; +export function unsubscribe( + name: string | symbol, + callback: MessageCallback +): void; diff --git a/src/node/internal/events.ts b/src/node/internal/events.ts index 81f358a8db2..fcf3e191263 100644 --- a/src/node/internal/events.ts +++ b/src/node/internal/events.ts @@ -33,41 +33,41 @@ import { ERR_INVALID_THIS, ERR_OUT_OF_RANGE, ERR_UNHANDLED_ERROR, -} from "node-internal:internal_errors"; +} from 'node-internal:internal_errors'; import { validateAbortSignal, validateBoolean, validateFunction, -} from "node-internal:validators"; +} from 'node-internal:validators'; +import * as process from 'node-internal:process'; -import * as process from "node-internal:process"; +import { spliceOne } from 'node-internal:internal_utils'; -import { spliceOne } from "node-internal:internal_utils"; - -import { default as async_hooks } from "node-internal:async_hooks"; +import { default as async_hooks } from 'node-internal:async_hooks'; const { AsyncResource } = async_hooks; -import { inspect } from "node-internal:internal_inspect"; - -const kRejection = Symbol.for("nodejs.rejection"); -const kCapture = Symbol("kCapture"); -const kErrorMonitor = Symbol("events.errorMonitor"); -const kMaxEventTargetListeners = Symbol("events.maxEventTargetListeners"); -const kMaxEventTargetListenersWarned = Symbol("events.maxEventTargetListenersWarned"); +import { inspect } from 'node-internal:internal_inspect'; +const kRejection = Symbol.for('nodejs.rejection'); +const kCapture = Symbol('kCapture'); +const kErrorMonitor = Symbol('events.errorMonitor'); +const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners'); +const kMaxEventTargetListenersWarned = Symbol( + 'events.maxEventTargetListenersWarned' +); export interface EventEmitterOptions { - captureRejections? : boolean; -}; + captureRejections?: boolean; +} -export type EventName = string|symbol; +export type EventName = string | symbol; export type EventCallback = (...args: any[]) => unknown; export interface EventEmitter { addListener(eventName: EventName, listener: EventCallback): EventEmitter; emit(eventName: EventName, ...args: unknown[]): void; - eventNames() : EventName[]; + eventNames(): EventName[]; getMaxListeners(): number; listenerCount(eventName: EventName): number; listeners(eventName: EventName): EventCallback[]; @@ -75,25 +75,28 @@ export interface EventEmitter { on(eventName: EventName, listener: EventCallback): EventEmitter; once(eventName: EventName, listener: EventCallback): EventEmitter; prependListener(eventName: EventName, listener: EventCallback): EventEmitter; - prependOnceListener(eventName: EventName, listener: EventCallback): EventEmitter; + prependOnceListener( + eventName: EventName, + listener: EventCallback + ): EventEmitter; removeAllListeners(eventName?: EventName): EventEmitter; removeListener(eventName: EventName, listener: EventCallback): EventEmitter; setMaxListeners(n: number): EventEmitter; rawListeners(eventName: EventName): EventCallback[]; - [kRejection](err: unknown, eventName: EventName, ...args: unknown[]) : void; -}; + [kRejection](err: unknown, eventName: EventName, ...args: unknown[]): void; +} type AsyncResource = typeof AsyncResource; -declare var EventTarget : Function; +declare var EventTarget: Function; -export function EventEmitter(this : EventEmitter, opts? : EventEmitterOptions) { +export function EventEmitter(this: EventEmitter, opts?: EventEmitterOptions) { EventEmitter.init.call(this, opts); } class EventEmitterReferencingAsyncResource extends AsyncResource { - #eventEmitter : EventEmitter; - constructor(emitter : EventEmitter) { + #eventEmitter: EventEmitter; + constructor(emitter: EventEmitter) { super(''); this.#eventEmitter = emitter; } @@ -107,38 +110,41 @@ class EventEmitterReferencingAsyncResource extends AsyncResource { // @ts-ignore -- TODO(soon) Properly handle the extends EventEmitter here export class EventEmitterAsyncResource extends EventEmitter { - #asyncResource : EventEmitterReferencingAsyncResource; + #asyncResource: EventEmitterReferencingAsyncResource; - constructor(options? : EventEmitterOptions) { + constructor(options?: EventEmitterOptions) { super(options); // @ts-ignore this.#asyncResource = new EventEmitterReferencingAsyncResource(this); } - get asyncResource() : AsyncResource { + get asyncResource(): AsyncResource { if (this.#asyncResource === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); - // @ts-ignore + // @ts-ignore return this.#asyncResource; } - emit(event : string | symbol, ...args : any[]) : void { + emit(event: string | symbol, ...args: any[]): void { if (this.#asyncResource === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); args.unshift(super.emit, this, event); - Reflect.apply(this.#asyncResource.runInAsyncScope, - this.#asyncResource, args); + Reflect.apply( + this.#asyncResource.runInAsyncScope, + this.#asyncResource, + args + ); } } -export function addAbortListener(signal : AbortSignal, listener : any) { +export function addAbortListener(signal: AbortSignal, listener: any) { if (signal === undefined) { - throw new ERR_INVALID_ARG_TYPE("signal", "AbortSignal", signal); + throw new ERR_INVALID_ARG_TYPE('signal', 'AbortSignal', signal); } validateAbortSignal(signal, 'signal'); validateFunction(listener, 'listener'); - let removeEventListener : Function; + let removeEventListener: Function; if (signal.aborted) { queueMicrotask(() => listener()); } else { @@ -180,7 +186,7 @@ Object.defineProperties(EventEmitter, { return EventEmitter.prototype[kCapture]; }, set(value) { - validateBoolean(value, "EventEmitter.captureRejections"); + validateBoolean(value, 'EventEmitter.captureRejections'); EventEmitter.prototype[kCapture] = value; }, @@ -192,11 +198,11 @@ Object.defineProperties(EventEmitter, { return defaultMaxListeners; }, set: function (arg) { - if (typeof arg !== "number" || arg < 0 || Number.isNaN(arg)) { + if (typeof arg !== 'number' || arg < 0 || Number.isNaN(arg)) { throw new ERR_OUT_OF_RANGE( - "defaultMaxListeners", - "a non-negative number", - arg, + 'defaultMaxListeners', + 'a non-negative number', + arg ); } defaultMaxListeners = arg; @@ -223,8 +229,11 @@ Object.defineProperty(EventEmitter.prototype, kCapture, { enumerable: false, }); -EventEmitter.init = function (this: any, opts? : EventEmitterOptions) { - if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { +EventEmitter.init = function (this: any, opts?: EventEmitterOptions) { + if ( + this._events === undefined || + this._events === Object.getPrototypeOf(this)._events + ) { this._events = Object.create(null); this._eventsCount = 0; } @@ -232,7 +241,7 @@ EventEmitter.init = function (this: any, opts? : EventEmitterOptions) { (this as any)._maxListeners ??= undefined; if (opts?.captureRejections) { - validateBoolean(opts.captureRejections, "options.captureRejections"); + validateBoolean(opts.captureRejections, 'options.captureRejections'); (this as any)[kCapture] = Boolean(opts.captureRejections); } else { // Assigning the kCapture property directly saves an expensive @@ -243,9 +252,10 @@ EventEmitter.init = function (this: any, opts? : EventEmitterOptions) { export function setMaxListeners( n = defaultMaxListeners, - ...eventTargets : any[]) { - if (typeof n !== "number" || n < 0 || Number.isNaN(n)) { - throw new ERR_OUT_OF_RANGE("n", "a non-negative number", n); + ...eventTargets: any[] +) { + if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) { + throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); } if (eventTargets.length === 0) { defaultMaxListeners = n; @@ -255,13 +265,13 @@ export function setMaxListeners( if (target instanceof EventTarget) { (target as any)[kMaxEventTargetListeners] = n; (target as any)[kMaxEventTargetListenersWarned] = false; - } else if (typeof target.setMaxListeners === "function") { + } else if (typeof target.setMaxListeners === 'function') { target.setMaxListeners(n); } else { throw new ERR_INVALID_ARG_TYPE( - "eventTargets", - ["EventEmitter", "EventTarget"], - target, + 'eventTargets', + ['EventEmitter', 'EventTarget'], + target ); } } @@ -273,7 +283,12 @@ EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; EventEmitter.addAbortListener = addAbortListener; -function addCatch(that : any, promise : Promise, type : string | symbol, args : any[]) { +function addCatch( + that: any, + promise: Promise, + type: string | symbol, + args: any[] +) { if (!that[kCapture]) { return; } @@ -283,7 +298,7 @@ function addCatch(that : any, promise : Promise, type : string | symbol try { const then = promise.then; - if (typeof then === "function") { + if (typeof then === 'function') { then.call(promise, undefined, function (err) { // The callback is called with nextTick to avoid a follow-up // rejection from this promise. @@ -291,12 +306,17 @@ function addCatch(that : any, promise : Promise, type : string | symbol }); } } catch (err) { - that.emit("error", err); + that.emit('error', err); } } -function emitUnhandledRejectionOrErr(ee : any, err : any, type: string | symbol, args : any[]) { - if (typeof ee[kRejection] === "function") { +function emitUnhandledRejectionOrErr( + ee: any, + err: any, + type: string | symbol, + args: any[] +) { + if (typeof ee[kRejection] === 'function') { ee[kRejection](err, type, ...args); } else { // We have to disable the capture rejections mechanism, otherwise @@ -309,22 +329,22 @@ function emitUnhandledRejectionOrErr(ee : any, err : any, type: string | symbol, // and the exception is handled. try { ee[kCapture] = false; - ee.emit("error", err); + ee.emit('error', err); } finally { ee[kCapture] = prev; } } } -EventEmitter.prototype.setMaxListeners = function setMaxListeners(n : number) { - if (typeof n !== "number" || n < 0 || Number.isNaN(n)) { - throw new ERR_OUT_OF_RANGE("n", "a non-negative number", n); +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n: number) { + if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) { + throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); } this._maxListeners = n; return this; }; -function _getMaxListeners(that : any) { +function _getMaxListeners(that: any) { if (that._maxListeners === undefined) { return (EventEmitter as any).defaultMaxListeners; } @@ -335,8 +355,11 @@ EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; -EventEmitter.prototype.emit = function emit(type : string | symbol, ...args: any[]) { - let doError = type === "error"; +EventEmitter.prototype.emit = function emit( + type: string | symbol, + ...args: any[] +) { + let doError = type === 'error'; const events = this._events; if (events !== undefined) { @@ -386,7 +409,7 @@ EventEmitter.prototype.emit = function emit(type : string | symbol, ...args: any return false; } - if (typeof handler === "function") { + if (typeof handler === 'function') { const result = handler.apply(this, args); // We check if result is undefined first because that @@ -415,12 +438,17 @@ EventEmitter.prototype.emit = function emit(type : string | symbol, ...args: any return true; }; -function _addListener(target : any, type : string | symbol, listener : unknown, prepend : boolean) { +function _addListener( + target: any, + type: string | symbol, + listener: unknown, + prepend: boolean +) { let m; let events; let existing; - validateFunction(listener, "listener"); + validateFunction(listener, 'listener'); events = target._events; if (events === undefined) { @@ -430,7 +458,7 @@ function _addListener(target : any, type : string | symbol, listener : unknown, // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { - target.emit("newListener", type, (listener as any).listener ?? listener); + target.emit('newListener', type, (listener as any).listener ?? listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object @@ -444,7 +472,7 @@ function _addListener(target : any, type : string | symbol, listener : unknown, events[type] = listener; ++target._eventsCount; } else { - if (typeof existing === "function") { + if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] @@ -461,10 +489,10 @@ function _addListener(target : any, type : string | symbol, listener : unknown, if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; console.log( - "Possible EventEmitter memory leak detected. " + - `${existing.length} ${String(type)} listeners ` + - `added to an EventEmitter. Use ` + - "emitter.setMaxListeners() to increase limit", + 'Possible EventEmitter memory leak detected. ' + + `${existing.length} ${String(type)} listeners ` + + `added to an EventEmitter. Use ` + + 'emitter.setMaxListeners() to increase limit' ); // TODO(soon): Implement process.emitWarning and inspect // // No error code for this since it is a Warning @@ -486,15 +514,18 @@ function _addListener(target : any, type : string | symbol, listener : unknown, return target; } -EventEmitter.prototype.addListener = function addListener(type : string | symbol, listener : unknown) { +EventEmitter.prototype.addListener = function addListener( + type: string | symbol, + listener: unknown +) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener( - type : string | symbol, - listener : unknown, + type: string | symbol, + listener: unknown ) { return _addListener(this, type, listener, true); }; @@ -510,7 +541,7 @@ function onceWrapper(this: any) { } } -function _onceWrap(target : any, type : string | symbol, listener : unknown) { +function _onceWrap(target: any, type: string | symbol, listener: unknown) { const state = { fired: false, wrapFn: undefined, target, type, listener }; const wrapped = onceWrapper.bind(state); (wrapped as any).listener = listener; @@ -518,28 +549,31 @@ function _onceWrap(target : any, type : string | symbol, listener : unknown) { return wrapped; } -EventEmitter.prototype.once = function once(type : string | symbol, listener : unknown) { - validateFunction(listener, "listener"); +EventEmitter.prototype.once = function once( + type: string | symbol, + listener: unknown +) { + validateFunction(listener, 'listener'); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener( - type : string | symbol, - listener : unknown, + type: string | symbol, + listener: unknown ) { - validateFunction(listener, "listener"); + validateFunction(listener, 'listener'); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.removeListener = function removeListener( - type : string | symbol, - listener : unknown, + type: string | symbol, + listener: unknown ) { - validateFunction(listener, "listener"); + validateFunction(listener, 'listener'); const events = this._events; if (events === undefined) { @@ -557,10 +591,10 @@ EventEmitter.prototype.removeListener = function removeListener( } else { delete events[type]; if (events.removeListener) { - this.emit("removeListener", type, list.listener || listener); + this.emit('removeListener', type, list.listener || listener); } } - } else if (typeof list !== "function") { + } else if (typeof list !== 'function') { let position = -1; for (let i = list.length - 1; i >= 0; i--) { @@ -585,7 +619,7 @@ EventEmitter.prototype.removeListener = function removeListener( } if (events.removeListener !== undefined) { - this.emit("removeListener", type, listener); + this.emit('removeListener', type, listener); } } @@ -594,7 +628,9 @@ EventEmitter.prototype.removeListener = function removeListener( EventEmitter.prototype.off = EventEmitter.prototype.removeListener; -EventEmitter.prototype.removeAllListeners = function removeAllListeners(type : string | symbol) { +EventEmitter.prototype.removeAllListeners = function removeAllListeners( + type: string | symbol +) { const events = this._events; if (events === undefined) { return this; @@ -618,10 +654,10 @@ EventEmitter.prototype.removeAllListeners = function removeAllListeners(type : s // Emit removeListener for all listeners on all events if (arguments.length === 0) { for (const key of Reflect.ownKeys(events)) { - if (key === "removeListener") continue; + if (key === 'removeListener') continue; this.removeAllListeners(key); } - this.removeAllListeners("removeListener"); + this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; @@ -629,7 +665,7 @@ EventEmitter.prototype.removeAllListeners = function removeAllListeners(type : s const listeners = events[type]; - if (typeof listeners === "function") { + if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order @@ -641,7 +677,7 @@ EventEmitter.prototype.removeAllListeners = function removeAllListeners(type : s return this; }; -function _listeners(target : any, type : string | symbol, unwrap : boolean) { +function _listeners(target: any, type: string | symbol, unwrap: boolean) { const events = target._events; if (events === undefined) { @@ -653,28 +689,33 @@ function _listeners(target : any, type : string | symbol, unwrap : boolean) { return []; } - if (typeof evlistener === "function") { + if (typeof evlistener === 'function') { return unwrap ? [evlistener.listener || evlistener] : [evlistener]; } return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener); } -EventEmitter.prototype.listeners = function listeners(type : string | symbol) { +EventEmitter.prototype.listeners = function listeners(type: string | symbol) { return _listeners(this, type, true); }; -EventEmitter.prototype.rawListeners = function rawListeners(type : string | symbol) { +EventEmitter.prototype.rawListeners = function rawListeners( + type: string | symbol +) { return _listeners(this, type, false); }; -const _listenerCount = function listenerCount(this : any, type : string | symbol) { +const _listenerCount = function listenerCount( + this: any, + type: string | symbol +) { const events = this._events; if (events !== undefined) { const evlistener = events[type]; - if (typeof evlistener === "function") { + if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; @@ -686,8 +727,8 @@ const _listenerCount = function listenerCount(this : any, type : string | symbol EventEmitter.prototype.listenerCount = _listenerCount; -export function listenerCount(emitter : any, type : string | symbol) { - if (typeof emitter.listenerCount === "function") { +export function listenerCount(emitter: any, type: string | symbol) { + if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } return _listenerCount.call(emitter, type); @@ -697,7 +738,7 @@ EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }; -function arrayClone(arr : any[]) { +function arrayClone(arr: any[]) { // At least since V8 8.3, this implementation is faster than the previous // which always used a simple for-loop switch (arr.length) { @@ -715,20 +756,20 @@ function arrayClone(arr : any[]) { return arr.slice(); } -function unwrapListeners(arr : any[]) { +function unwrapListeners(arr: any[]) { const ret = arrayClone(arr); for (let i = 0; i < ret.length; ++i) { const orig = ret[i].listener; - if (typeof orig === "function") { + if (typeof orig === 'function') { ret[i] = orig; } } return ret; } -export function getEventListeners(emitterOrTarget : any, type : string | symbol) { +export function getEventListeners(emitterOrTarget: any, type: string | symbol) { // First check if EventEmitter - if (typeof emitterOrTarget.listeners === "function") { + if (typeof emitterOrTarget.listeners === 'function') { return emitterOrTarget.listeners(type); } if (emitterOrTarget instanceof EventTarget) { @@ -737,96 +778,111 @@ export function getEventListeners(emitterOrTarget : any, type : string | symbol) return []; } throw new ERR_INVALID_ARG_TYPE( - "emitter", - ["EventEmitter", "EventTarget"], - emitterOrTarget, + 'emitter', + ['EventEmitter', 'EventTarget'], + emitterOrTarget ); } export interface OnceOptions { signal?: AbortSignal; -}; +} -export async function once(emitter : any, name : string | symbol, options : OnceOptions = {}) { +export async function once( + emitter: any, + name: string | symbol, + options: OnceOptions = {} +) { const signal = options?.signal; - validateAbortSignal(signal, "options.signal"); + validateAbortSignal(signal, 'options.signal'); if (signal?.aborted) { throw new AbortError(); } return new Promise((resolve, reject) => { - const errorListener = (err : any) => { + const errorListener = (err: any) => { emitter.removeListener(name, resolver); if (signal != null) { - eventTargetAgnosticRemoveListener(signal, "abort", abortListener); + eventTargetAgnosticRemoveListener(signal, 'abort', abortListener); } reject(err); }; - const resolver = (...args : any[]) => { - if (typeof emitter.removeListener === "function") { - emitter.removeListener("error", errorListener); + const resolver = (...args: any[]) => { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); } if (signal != null) { - eventTargetAgnosticRemoveListener(signal, "abort", abortListener); + eventTargetAgnosticRemoveListener(signal, 'abort', abortListener); } resolve(args); }; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); - if (name !== "error" && typeof emitter.once === "function") { - emitter.once("error", errorListener); + if (name !== 'error' && typeof emitter.once === 'function') { + emitter.once('error', errorListener); } function abortListener() { eventTargetAgnosticRemoveListener(emitter, name, resolver); - eventTargetAgnosticRemoveListener(emitter, "error", errorListener); + eventTargetAgnosticRemoveListener(emitter, 'error', errorListener); reject(new AbortError()); } if (signal != null) { - eventTargetAgnosticAddListener( - signal, - "abort", - abortListener, - { once: true }, - ); + eventTargetAgnosticAddListener(signal, 'abort', abortListener, { + once: true, + }); } }); } const AsyncIteratorPrototype = Object.getPrototypeOf( - Object.getPrototypeOf(async function* () {}).prototype, + Object.getPrototypeOf(async function* () {}).prototype ); function createIterResult(value: any, done: boolean) { return { value, done }; } -function eventTargetAgnosticRemoveListener(emitter : any, name : string | symbol, listener : unknown, flags : unknown = undefined) { - if (typeof emitter.removeListener === "function") { +function eventTargetAgnosticRemoveListener( + emitter: any, + name: string | symbol, + listener: unknown, + flags: unknown = undefined +) { + if (typeof emitter.removeListener === 'function') { emitter.removeListener(name, listener); - } else if (typeof emitter.removeEventListener === "function") { + } else if (typeof emitter.removeEventListener === 'function') { emitter.removeEventListener(name, listener, flags); } else { - throw new ERR_INVALID_ARG_TYPE("emitter", "EventEmitter", emitter); + throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter); } } interface AddListenerFlags { - once? : boolean; + once?: boolean; } -function eventTargetAgnosticAddListener(emitter : any, name : string | symbol, listener : unknown, flags : AddListenerFlags = {}) { - if (typeof emitter.on === "function") { +function eventTargetAgnosticAddListener( + emitter: any, + name: string | symbol, + listener: unknown, + flags: AddListenerFlags = {} +) { + if (typeof emitter.on === 'function') { if (flags?.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } - } else if (typeof emitter.addEventListener === "function") { + } else if (typeof emitter.addEventListener === 'function') { // EventTarget does not have `error` event semantics like Node // EventEmitters, we do not listen to `error` events here. - emitter.addEventListener(name, (arg : unknown) => { - (listener as any)(arg); - }, flags); + emitter.addEventListener( + name, + (arg: unknown) => { + (listener as any)(arg); + }, + flags + ); } else { - throw new ERR_INVALID_ARG_TYPE("emitter", "EventEmitter", emitter); + throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter); } } @@ -834,99 +890,100 @@ interface OnOptions { signal?: AbortSignal; } -export function on(emitter : any, event : string | symbol, options : OnOptions = {}) { +export function on( + emitter: any, + event: string | symbol, + options: OnOptions = {} +) { const signal = options?.signal; - validateAbortSignal(signal, "options.signal"); + validateAbortSignal(signal, 'options.signal'); if (signal?.aborted) { throw new AbortError(); } - const unconsumedEvents : any[] = []; - const unconsumedPromises : any[] = []; - let error : any = null; + const unconsumedEvents: any[] = []; + const unconsumedPromises: any[] = []; + let error: any = null; let finished = false; - const iterator = Object.setPrototypeOf({ - next() { - // First, we consume all unread events - const value = unconsumedEvents.shift(); - if (value) { - return Promise.resolve(createIterResult(value, false)); - } - - // Then we error, if an error happened - // This happens one time if at all, because after 'error' - // we stop listening - if (error) { - const p = Promise.reject(error); - // Only the first element errors - error = null; - return p; - } + const iterator = Object.setPrototypeOf( + { + next() { + // First, we consume all unread events + const value = unconsumedEvents.shift(); + if (value) { + return Promise.resolve(createIterResult(value, false)); + } + + // Then we error, if an error happened + // This happens one time if at all, because after 'error' + // we stop listening + if (error) { + const p = Promise.reject(error); + // Only the first element errors + error = null; + return p; + } + + // If the iterator is finished, resolve to done + if (finished) { + return Promise.resolve(createIterResult(undefined, true)); + } + + // Wait until an event happens + return new Promise(function (resolve, reject) { + unconsumedPromises.push({ resolve, reject }); + }); + }, + + return() { + eventTargetAgnosticRemoveListener(emitter, event, eventHandler); + eventTargetAgnosticRemoveListener(emitter, 'error', errorHandler); + + if (signal) { + eventTargetAgnosticRemoveListener(signal, 'abort', abortListener, { + once: true, + }); + } + + finished = true; + + for (const promise of unconsumedPromises) { + promise.resolve(createIterResult(undefined, true)); + } - // If the iterator is finished, resolve to done - if (finished) { return Promise.resolve(createIterResult(undefined, true)); - } - - // Wait until an event happens - return new Promise(function (resolve, reject) { - unconsumedPromises.push({ resolve, reject }); - }); + }, + + throw(err: any) { + if (!err || !(err instanceof Error)) { + throw new ERR_INVALID_ARG_TYPE( + 'EventEmitter.AsyncIterator', + 'Error', + err + ); + } + error = err; + eventTargetAgnosticRemoveListener(emitter, event, eventHandler); + eventTargetAgnosticRemoveListener(emitter, 'error', errorHandler); + }, + + [Symbol.asyncIterator]() { + return this; + }, }, - - return() { - eventTargetAgnosticRemoveListener(emitter, event, eventHandler); - eventTargetAgnosticRemoveListener(emitter, "error", errorHandler); - - if (signal) { - eventTargetAgnosticRemoveListener( - signal, - "abort", - abortListener, - { once: true }, - ); - } - - finished = true; - - for (const promise of unconsumedPromises) { - promise.resolve(createIterResult(undefined, true)); - } - - return Promise.resolve(createIterResult(undefined, true)); - }, - - throw(err : any) { - if (!err || !(err instanceof Error)) { - throw new ERR_INVALID_ARG_TYPE( - "EventEmitter.AsyncIterator", - "Error", - err, - ); - } - error = err; - eventTargetAgnosticRemoveListener(emitter, event, eventHandler); - eventTargetAgnosticRemoveListener(emitter, "error", errorHandler); - }, - - [Symbol.asyncIterator]() { - return this; - }, - }, AsyncIteratorPrototype); + AsyncIteratorPrototype + ); eventTargetAgnosticAddListener(emitter, event, eventHandler); - if (event !== "error" && typeof emitter.on === "function") { - emitter.on("error", errorHandler); + if (event !== 'error' && typeof emitter.on === 'function') { + emitter.on('error', errorHandler); } if (signal) { - eventTargetAgnosticAddListener( - signal, - "abort", - abortListener, - { once: true }, - ); + eventTargetAgnosticAddListener(signal, 'abort', abortListener, { + once: true, + }); } return iterator; @@ -935,7 +992,7 @@ export function on(emitter : any, event : string | symbol, options : OnOptions = errorHandler(new AbortError()); } - function eventHandler(...args : any[]) { + function eventHandler(...args: any[]) { const promise = unconsumedPromises.shift(); if (promise) { promise.resolve(createIterResult(args, false)); @@ -944,7 +1001,7 @@ export function on(emitter : any, event : string | symbol, options : OnOptions = } } - function errorHandler(err : any) { + function errorHandler(err: any) { finished = true; const toError = unconsumedPromises.shift(); diff --git a/src/node/internal/internal_assert.ts b/src/node/internal/internal_assert.ts index eb0e36447b1..a23e9759e15 100644 --- a/src/node/internal/internal_assert.ts +++ b/src/node/internal/internal_assert.ts @@ -32,15 +32,9 @@ import { AssertionErrorConstructorOptions, } from 'node-internal:internal_assertionerror'; -import { - diffstr, - diff, - buildMessage, -} from 'node-internal:internal_diffs'; +import { diffstr, diff, buildMessage } from 'node-internal:internal_diffs'; -import { - isDeepStrictEqual, -} from 'node-internal:internal_comparisons'; +import { isDeepStrictEqual } from 'node-internal:internal_comparisons'; import { ERR_AMBIGUOUS_ARGUMENT, @@ -50,7 +44,7 @@ import { ERR_MISSING_ARGS, } from 'node-internal:internal_errors'; -import { inspect } from "node-internal:internal_inspect"; +import { inspect } from 'node-internal:internal_inspect'; interface ExtendedAssertionErrorConstructorOptions extends AssertionErrorConstructorOptions { @@ -58,7 +52,7 @@ interface ExtendedAssertionErrorConstructorOptions } function createAssertionError( - options: ExtendedAssertionErrorConstructorOptions, + options: ExtendedAssertionErrorConstructorOptions ): AssertionError { const error = new AssertionError(options); if (options.generatedMessage) { @@ -71,7 +65,7 @@ function createAssertionError( function assert(actual: unknown, message?: string | Error): asserts actual { if (arguments.length === 0) { throw new AssertionError({ - message: "No value argument passed to `assert.ok()`", + message: 'No value argument passed to `assert.ok()`', }); } if (!actual) { @@ -79,8 +73,8 @@ function assert(actual: unknown, message?: string | Error): asserts actual { message, actual, expected: true, - operator: "==" - } as AssertionErrorConstructorOptions ); + operator: '==', + } as AssertionErrorConstructorOptions); } } export const ok = assert; @@ -88,48 +82,52 @@ export const ok = assert; export function throws( fn: () => void, error?: RegExp | Function | Error, - message?: string, + message?: string ) { // Check arg types - if (typeof fn !== "function") { - throw new ERR_INVALID_ARG_TYPE("fn", "function", fn); + if (typeof fn !== 'function') { + throw new ERR_INVALID_ARG_TYPE('fn', 'function', fn); } if ( - typeof error === "object" && error !== null && + typeof error === 'object' && + error !== null && Object.getPrototypeOf(error) === Object.prototype && Object.keys(error).length === 0 ) { // error is an empty object throw new ERR_INVALID_ARG_VALUE( - "error", + 'error', error, - "may not be an empty object", + 'may not be an empty object' ); } - if (typeof message === "string") { + if (typeof message === 'string') { if ( - !(error instanceof RegExp) && typeof error !== "function" && - !(error instanceof Error) && typeof error !== "object" + !(error instanceof RegExp) && + typeof error !== 'function' && + !(error instanceof Error) && + typeof error !== 'object' ) { - throw new ERR_INVALID_ARG_TYPE("error", [ - "Function", - "Error", - "RegExp", - "Object", - ], error); + throw new ERR_INVALID_ARG_TYPE( + 'error', + ['Function', 'Error', 'RegExp', 'Object'], + error + ); } } else { if ( - typeof error !== "undefined" && typeof error !== "string" && - !(error instanceof RegExp) && typeof error !== "function" && - !(error instanceof Error) && typeof error !== "object" + typeof error !== 'undefined' && + typeof error !== 'string' && + !(error instanceof RegExp) && + typeof error !== 'function' && + !(error instanceof Error) && + typeof error !== 'object' ) { - throw new ERR_INVALID_ARG_TYPE("error", [ - "Function", - "Error", - "RegExp", - "Object", - ], error); + throw new ERR_INVALID_ARG_TYPE( + 'error', + ['Function', 'Error', 'RegExp', 'Object'], + error + ); } } @@ -147,67 +145,66 @@ export function throws( } if (message) { let msg = `Missing expected exception: ${message}`; - if (typeof error === "function" && error?.name) { + if (typeof error === 'function' && error?.name) { msg = `Missing expected exception (${error.name}): ${message}`; } throw new AssertionError({ message: msg, - operator: "throws", + operator: 'throws', actual: undefined, expected: error, }); - } else if (typeof error === "string") { + } else if (typeof error === 'string') { // Use case of throws(fn, message) throw new AssertionError({ message: `Missing expected exception: ${error}`, - operator: "throws", + operator: 'throws', actual: undefined, expected: undefined, }); - } else if (typeof error === "function" && error?.prototype !== undefined) { + } else if (typeof error === 'function' && error?.prototype !== undefined) { throw new AssertionError({ message: `Missing expected exception (${error.name}).`, - operator: "throws", + operator: 'throws', actual: undefined, expected: error, }); } else { throw new AssertionError({ - message: "Missing expected exception.", - operator: "throws", + message: 'Missing expected exception.', + operator: 'throws', actual: undefined, expected: error, }); } } -export function doesNotThrow( - fn: () => void, - message?: string, -): void; +export function doesNotThrow(fn: () => void, message?: string): void; export function doesNotThrow( fn: () => void, error?: Function, - message?: string | Error, + message?: string | Error ): void; export function doesNotThrow( fn: () => void, error?: RegExp, - message?: string, + message?: string ): void; export function doesNotThrow( fn: () => void, expected?: Function | RegExp | string, - message?: string | Error, + message?: string | Error ) { // Check arg type - if (typeof fn !== "function") { - throw new ERR_INVALID_ARG_TYPE("fn", "function", fn); + if (typeof fn !== 'function') { + throw new ERR_INVALID_ARG_TYPE('fn', 'function', fn); } else if ( - !(expected instanceof RegExp) && typeof expected !== "function" && - typeof expected !== "string" && typeof expected !== "undefined" + !(expected instanceof RegExp) && + typeof expected !== 'function' && + typeof expected !== 'string' && + typeof expected !== 'undefined' ) { - throw new ERR_INVALID_ARG_TYPE("expected", ["Function", "RegExp"], fn); + throw new ERR_INVALID_ARG_TYPE('expected', ['Function', 'RegExp'], fn); } // Checks test function @@ -221,7 +218,7 @@ export function doesNotThrow( export function equal( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { return strictEqual(actual, expected, message); } @@ -229,7 +226,7 @@ export function equal( export function notEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { return notStrictEqual(actual, expected, message); } @@ -237,10 +234,10 @@ export function notEqual( export function strictEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("actual", "expected"); + throw new ERR_MISSING_ARGS('actual', 'expected'); } if (Object.is(actual, expected)) { @@ -255,21 +252,18 @@ export function strictEqual( if (actualString === expectedString) { const withOffset = actualString - .split("\n") + .split('\n') .map((l) => ` ${l}`) - .join("\n"); - message = - `Values have the same structure but are not reference-equal:\n\n${ - withOffset - }\n`; + .join('\n'); + message = `Values have the same structure but are not reference-equal:\n\n${withOffset}\n`; } else { try { - const stringDiff = (typeof actual === "string") && - (typeof expected === "string"); + const stringDiff = + typeof actual === 'string' && typeof expected === 'string'; const diffResult = stringDiff ? diffstr(actual as string, expected as string) - : diff(actualString.split("\n"), expectedString.split("\n")); - const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n"); + : diff(actualString.split('\n'), expectedString.split('\n')); + const diffMsg = buildMessage(diffResult, { stringDiff }).join('\n'); message = `Values are not strictly equal:\n${diffMsg}`; } catch { message = '\n$[Cannot display] + \n\n'; @@ -288,10 +282,10 @@ export function strictEqual( export function notStrictEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("actual", "expected"); + throw new ERR_MISSING_ARGS('actual', 'expected'); } if (!Object.is(actual, expected)) { @@ -315,7 +309,7 @@ export function notStrictEqual( export function deepEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { return deepStrictEqual(actual, expected, message); } @@ -323,7 +317,7 @@ export function deepEqual( export function notDeepEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { return notDeepStrictEqual(actual, expected, message); } @@ -331,10 +325,10 @@ export function notDeepEqual( export function deepStrictEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("actual", "expected"); + throw new ERR_MISSING_ARGS('actual', 'expected'); } if (isDeepStrictEqual(actual, expected)) { @@ -356,10 +350,10 @@ export function deepStrictEqual( export function notDeepStrictEqual( actual: unknown, expected: unknown, - message?: string | Error, + message?: string | Error ) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("actual", "expected"); + throw new ERR_MISSING_ARGS('actual', 'expected'); } if (isDeepStrictEqual(actual, expected)) { @@ -379,10 +373,10 @@ export function notDeepStrictEqual( } export function fail(message?: string | Error): never { - if (typeof message === "string" || message == null) { + if (typeof message === 'string' || message == null) { throw createAssertionError({ - message: message ?? "Failed", - operator: "fail", + message: message ?? 'Failed', + operator: 'fail', generatedMessage: message == null, }); } else { @@ -390,12 +384,16 @@ export function fail(message?: string | Error): never { } } -export function match(actual: string, regexp: RegExp, message?: string | Error) { +export function match( + actual: string, + regexp: RegExp, + message?: string | Error +) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("actual", "regexp"); + throw new ERR_MISSING_ARGS('actual', 'regexp'); } if (!(regexp instanceof RegExp)) { - throw new ERR_INVALID_ARG_TYPE("regexp", "RegExp", regexp); + throw new ERR_INVALID_ARG_TYPE('regexp', 'RegExp', regexp); } if (!regexp.test(actual)) { @@ -416,26 +414,27 @@ export function match(actual: string, regexp: RegExp, message?: string | Error) export function doesNotMatch( string: string, regexp: RegExp, - message?: string | Error, + message?: string | Error ) { if (arguments.length < 2) { - throw new ERR_MISSING_ARGS("string", "regexp"); + throw new ERR_MISSING_ARGS('string', 'regexp'); } if (!(regexp instanceof RegExp)) { - throw new ERR_INVALID_ARG_TYPE("regexp", "RegExp", regexp); + throw new ERR_INVALID_ARG_TYPE('regexp', 'RegExp', regexp); } - if (typeof string !== "string") { + if (typeof string !== 'string') { if (message instanceof Error) { throw message; } throw new AssertionError({ - message: message || - `The "string" argument must be of type string. Received type ${typeof string} (${ - inspect(string) - })`, + message: + message || + `The "string" argument must be of type string. Received type ${typeof string} (${inspect( + string + )})`, actual: string, expected: regexp, - operator: "doesNotMatch", + operator: 'doesNotMatch', }); } @@ -454,10 +453,13 @@ export function doesNotMatch( } } -export function strict(actual: unknown, message?: string | Error): asserts actual { +export function strict( + actual: unknown, + message?: string | Error +): asserts actual { if (arguments.length === 0) { throw new AssertionError({ - message: "No value argument passed to `assert.ok()`", + message: 'No value argument passed to `assert.ok()`', }); } assert(actual, message); @@ -465,21 +467,21 @@ export function strict(actual: unknown, message?: string | Error): asserts actua export function rejects( asyncFn: Promise | (() => Promise), - error?: RegExp | Function | Error, + error?: RegExp | Function | Error ): Promise; export function rejects( asyncFn: Promise | (() => Promise), - message?: string, + message?: string ): Promise; export function rejects( asyncFn: Promise | (() => Promise), error?: RegExp | Function | Error | string, - message?: string, + message?: string ) { let promise: Promise; - if (typeof asyncFn === "function") { + if (typeof asyncFn === 'function') { try { promise = asyncFn(); } catch (err) { @@ -489,41 +491,43 @@ export function rejects( if (!isValidThenable(promise)) { return Promise.reject( new ERR_INVALID_RETURN_VALUE( - "instance of Promise", - "promiseFn", - promise, - ), + 'instance of Promise', + 'promiseFn', + promise + ) ); } } else if (!isValidThenable(asyncFn)) { return Promise.reject( - new ERR_INVALID_ARG_TYPE("promiseFn", ["function", "Promise"], asyncFn), + new ERR_INVALID_ARG_TYPE('promiseFn', ['function', 'Promise'], asyncFn) ); } else { promise = asyncFn; } function onFulfilled() { - let message = "Missing expected rejection"; - if (typeof error === "string") { + let message = 'Missing expected rejection'; + if (typeof error === 'string') { message += `: ${error}`; - } else if (typeof error === "function" && error.prototype !== undefined) { + } else if (typeof error === 'function' && error.prototype !== undefined) { message += ` (${error.name}).`; } else { - message += "."; + message += '.'; } - return Promise.reject(createAssertionError({ - message, - operator: "rejects", - generatedMessage: true, - })); + return Promise.reject( + createAssertionError({ + message, + operator: 'rejects', + generatedMessage: true, + }) + ); } function rejects_onRejected(e: Error) { if ( validateThrownError(e, error, message, { operator: rejects, - validationFunctionName: "validate", + validationFunctionName: 'validate', }) ) { return; @@ -535,30 +539,30 @@ export function rejects( export function doesNotReject( asyncFn: Promise | (() => Promise), - error?: RegExp | Function, + error?: RegExp | Function ): Promise; export function doesNotReject( asyncFn: Promise | (() => Promise), - message?: string, + message?: string ): Promise; export function doesNotReject( asyncFn: Promise | (() => Promise), error?: RegExp | Function | string, - message?: string, + message?: string ) { let promise: Promise; - if (typeof asyncFn === "function") { + if (typeof asyncFn === 'function') { try { const value = asyncFn(); if (!isValidThenable(value)) { return Promise.reject( new ERR_INVALID_RETURN_VALUE( - "instance of Promise", - "promiseFn", - value, - ), + 'instance of Promise', + 'promiseFn', + value + ) ); } promise = value; @@ -567,7 +571,7 @@ export function doesNotReject( } } else if (!isValidThenable(asyncFn)) { return Promise.reject( - new ERR_INVALID_ARG_TYPE("promiseFn", ["function", "Promise"], asyncFn), + new ERR_INVALID_ARG_TYPE('promiseFn', ['function', 'Promise'], asyncFn) ); } else { promise = asyncFn; @@ -575,7 +579,7 @@ export function doesNotReject( return promise.then( () => {}, - (e) => gotUnwantedException(e, error, message, doesNotReject), + (e) => gotUnwantedException(e, error, message, doesNotReject) ); } @@ -583,17 +587,17 @@ function gotUnwantedException( e: any, expected: RegExp | Function | string | null | undefined, message: string | Error | null | undefined, - operator: Function, + operator: Function ): never { - if (typeof expected === "string") { + if (typeof expected === 'string') { // The use case of doesNotThrow(fn, message); throw new AssertionError({ - message: - `Got unwanted exception: ${expected}\nActual message: "${e.message}"`, + message: `Got unwanted exception: ${expected}\nActual message: "${e.message}"`, operator: operator.name, }); } else if ( - typeof expected === "function" && expected.prototype !== undefined + typeof expected === 'function' && + expected.prototype !== undefined ) { // The use case of doesNotThrow(fn, Error, message); if (e instanceof expected) { @@ -641,9 +645,9 @@ function gotUnwantedException( export function ifError(err: any) { if (err !== null && err !== undefined) { - let message = "ifError got unwanted exception: "; + let message = 'ifError got unwanted exception: '; - if (typeof err === "object" && typeof err.message === "string") { + if (typeof err === 'object' && typeof err.message === 'string') { if (err.message.length === 0 && err.constructor) { message += err.constructor.name; } else { @@ -656,7 +660,7 @@ export function ifError(err: any) { const newErr = new AssertionError({ actual: err, expected: null, - operator: "ifError", + operator: 'ifError', message, stackStartFn: ifError, }); @@ -664,10 +668,10 @@ export function ifError(err: any) { // Make sure we actually have a stack trace! const origStack = err.stack; - if (typeof origStack === "string") { - const tmp2 = origStack.split("\n"); + if (typeof origStack === 'string') { + const tmp2 = origStack.split('\n'); tmp2.shift(); - let tmp1 = newErr!.stack?.split("\n"); + let tmp1 = newErr!.stack?.split('\n'); for (const errFrame of tmp2) { const pos = tmp1?.indexOf(errFrame); @@ -679,7 +683,7 @@ export function ifError(err: any) { } } - newErr.stack = `${tmp1?.join("\n")}\n${tmp2.join("\n")}`; + newErr.stack = `${tmp1?.join('\n')}\n${tmp2.join('\n')}`; } throw newErr; @@ -695,33 +699,34 @@ function validateThrownError( e: any, error: RegExp | Function | Error | string | null | undefined, message: string | undefined | null, - options: ValidateThrownErrorOptions, + options: ValidateThrownErrorOptions ): boolean { - if (typeof error === "string") { + if (typeof error === 'string') { if (message != null) { throw new ERR_INVALID_ARG_TYPE( - "error", - ["Object", "Error", "Function", "RegExp"], - error, + 'error', + ['Object', 'Error', 'Function', 'RegExp'], + error ); - } else if (typeof e === "object" && e !== null) { + } else if (typeof e === 'object' && e !== null) { if (e.message === error) { throw new ERR_AMBIGUOUS_ARGUMENT( - "error/message", - `The error message "${e.message}" is identical to the message.`, + 'error/message', + `The error message "${e.message}" is identical to the message.` ); } } else if (e === error) { throw new ERR_AMBIGUOUS_ARGUMENT( - "error/message", - `The error "${e}" is identical to the message.`, + 'error/message', + `The error "${e}" is identical to the message.` ); } message = error; error = undefined; } if ( - error instanceof Function && error.prototype !== undefined && + error instanceof Function && + error.prototype !== undefined && error.prototype instanceof Error ) { // error is a constructor @@ -729,8 +734,7 @@ function validateThrownError( return true; } throw createAssertionError({ - message: - `The error is expected to be an instance of "${error.name}". Received "${e?.constructor?.name}"\n\nError message:\n\n${e?.message}`, + message: `The error is expected to be an instance of "${error.name}". Received "${e?.constructor?.name}"\n\nError message:\n\n${e?.message}`, actual: e, expected: error, operator: options.operator.name, @@ -746,10 +750,10 @@ function validateThrownError( message: `The ${ options.validationFunctionName ? `"${options.validationFunctionName}" validation` - : "validation" - } function is expected to return "true". Received ${ - inspect(received) - }\n\nCaught error:\n\n${e}`, + : 'validation' + } function is expected to return "true". Received ${inspect( + received + )}\n\nCaught error:\n\n${e}`, actual: e, expected: error, operator: options.operator.name, @@ -761,25 +765,24 @@ function validateThrownError( return true; } throw createAssertionError({ - message: - `The input did not match the regular expression ${error.toString()}. Input:\n\n'${ - String(e) - }'\n`, + message: `The input did not match the regular expression ${error.toString()}. Input:\n\n'${String( + e + )}'\n`, actual: e, expected: error, operator: options.operator.name, generatedMessage: true, }); } - if (typeof error === "object" && error !== null) { + if (typeof error === 'object' && error !== null) { const keys = Object.keys(error); if (error instanceof Error) { - keys.push("name", "message"); + keys.push('name', 'message'); } for (const k of keys) { if (e == null) { throw createAssertionError({ - message: message || "object is expected to thrown, but got null", + message: message || 'object is expected to thrown, but got null', actual: e, expected: error, operator: options.operator.name, @@ -787,20 +790,20 @@ function validateThrownError( }); } - if (typeof e === "string") { + if (typeof e === 'string') { throw createAssertionError({ - message: message || - `object is expected to thrown, but got string: ${e}`, + message: + message || `object is expected to thrown, but got string: ${e}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: message == null, }); } - if (typeof e === "number") { + if (typeof e === 'number') { throw createAssertionError({ - message: message || - `object is expected to thrown, but got number: ${e}`, + message: + message || `object is expected to thrown, but got number: ${e}`, actual: e, expected: error, operator: options.operator.name, @@ -819,7 +822,7 @@ function validateThrownError( const actual = e[k]; const expected = (error as any)[k]; - if (typeof actual === "string" && expected instanceof RegExp) { + if (typeof actual === 'string' && expected instanceof RegExp) { match(actual, expected); } else { deepStrictEqual(actual, expected); @@ -827,7 +830,7 @@ function validateThrownError( } return true; } - if (typeof error === "undefined") { + if (typeof error === 'undefined') { return true; } throw createAssertionError({ @@ -846,7 +849,7 @@ function isValidThenable(maybeThennable: any): boolean { return true; } - return typeof maybeThennable.then === "function"; + return typeof maybeThennable.then === 'function'; } export { AssertionError }; diff --git a/src/node/internal/internal_assertionerror.ts b/src/node/internal/internal_assertionerror.ts index 0fabb52da0c..cd2a68aa825 100644 --- a/src/node/internal/internal_assertionerror.ts +++ b/src/node/internal/internal_assertionerror.ts @@ -28,23 +28,23 @@ import { ERR_INVALID_ARG_TYPE } from 'node-internal:internal_errors'; import { inspect } from 'node-internal:internal_inspect'; -let blue = ""; -let green = ""; -let red = ""; -let defaultColor = ""; +let blue = ''; +let green = ''; +let red = ''; +let defaultColor = ''; const kReadableOperator: { [key: string]: string } = { - deepStrictEqual: "Expected values to be strictly deep-equal:", - strictEqual: "Expected values to be strictly equal:", + deepStrictEqual: 'Expected values to be strictly deep-equal:', + strictEqual: 'Expected values to be strictly equal:', strictEqualObject: 'Expected "actual" to be reference-equal to "expected":', - deepEqual: "Expected values to be loosely deep-equal:", + deepEqual: 'Expected values to be loosely deep-equal:', notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal to:', notStrictEqual: 'Expected "actual" to be strictly unequal to:', notStrictEqualObject: 'Expected "actual" not to be reference-equal to "expected":', notDeepEqual: 'Expected "actual" not to be loosely deep-equal to:', - notIdentical: "Values have same structure but are not reference-equal:", - notDeepEqualUnequal: "Expected values not to be loosely deep-equal:", + notIdentical: 'Values have same structure but are not reference-equal:', + notDeepEqualUnequal: 'Expected values not to be loosely deep-equal:', }; // Comparing short primitives should just show === / !== instead of using the @@ -61,78 +61,82 @@ export function copyError(source: any): Error { Object.defineProperty(target, key, desc); } } - Object.defineProperty(target, "message", { value: source.message }); + Object.defineProperty(target, 'message', { value: source.message }); return target; } export function inspectValue(val: unknown): string { - return inspect( - val, - { - compact: true, - customInspect: false, - depth: 1000, - maxArrayLength: Infinity, - // Assert compares only enumerable properties (with a few exceptions). - showHidden: false, - // Assert does not detect proxies currently. - showProxy: false, - sorted: true, - // Inspect getters as we also check them when comparing entries. - getters: true, - }, - ); + return inspect(val, { + compact: true, + customInspect: false, + depth: 1000, + maxArrayLength: Infinity, + // Assert compares only enumerable properties (with a few exceptions). + showHidden: false, + // Assert does not detect proxies currently. + showProxy: false, + sorted: true, + // Inspect getters as we also check them when comparing entries. + getters: true, + }); } export function createErrDiff( actual: unknown, expected: unknown, - operator: string, + operator: string ): string { - let other = ""; - let res = ""; - let end = ""; + let other = ''; + let res = ''; + let end = ''; let skipped = false; const actualInspected = inspectValue(actual); - const actualLines = actualInspected.split("\n"); - const expectedLines = inspectValue(expected).split("\n"); + const actualLines = actualInspected.split('\n'); + const expectedLines = inspectValue(expected).split('\n'); let i = 0; - let indicator = ""; + let indicator = ''; // In case both values are objects or functions explicitly mark them as not // reference equal for the `strictEqual` operator. if ( - operator === "strictEqual" && - ((typeof actual === "object" && actual !== null && - typeof expected === "object" && expected !== null) || - (typeof actual === "function" && typeof expected === "function")) + operator === 'strictEqual' && + ((typeof actual === 'object' && + actual !== null && + typeof expected === 'object' && + expected !== null) || + (typeof actual === 'function' && typeof expected === 'function')) ) { - operator = "strictEqualObject"; + operator = 'strictEqualObject'; } // If "actual" and "expected" fit on a single line and they are not strictly // equal, check further special handling. if ( - actualLines.length === 1 && expectedLines.length === 1 && + actualLines.length === 1 && + expectedLines.length === 1 && actualLines[0] !== expectedLines[0] ) { const actualRaw = actualLines[0]; const expectedRaw = expectedLines[0]; - const inputLength = (actualRaw as string).length + (expectedRaw as string).length; + const inputLength = + (actualRaw as string).length + (expectedRaw as string).length; // If the character length of "actual" and "expected" together is less than // kMaxShortLength and if neither is an object and at least one of them is // not `zero`, use the strict equal comparison to visualize the output. if (inputLength <= kMaxShortLength) { if ( - (typeof actual !== "object" || actual === null) && - (typeof expected !== "object" || expected === null) && + (typeof actual !== 'object' || actual === null) && + (typeof expected !== 'object' || expected === null) && (actual !== 0 || expected !== 0) - ) { // -0 === +0 - return `${kReadableOperator[operator]}\n\n` + - `${actualLines[0]} !== ${expectedLines[0]}\n`; + ) { + // -0 === +0 + return ( + `${kReadableOperator[operator]}\n\n` + + `${actualLines[0]} !== ${expectedLines[0]}\n` + ); } - } else if (operator !== "strictEqualObject") { + } else if (operator !== 'strictEqualObject') { // If the stderr is a tty and the input length is lower than the current // columns per line, add a mismatch indicator below the output. If it is // not a tty, use a default value of 80 characters. @@ -145,7 +149,7 @@ export function createErrDiff( if (i > 2) { // Add position indicator for the first mismatch in case it is a // single line and the input length is less than the column length. - indicator = `\n ${" ".repeat(i)}^`; + indicator = `\n ${' '.repeat(i)}^`; i = 0; } } @@ -176,7 +180,7 @@ export function createErrDiff( // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) if (maxLines === 0) { // We have to get the result again. The lines were all removed before. - const actualLines = actualInspected.split("\n"); + const actualLines = actualInspected.split('\n'); // Only remove lines in case it makes sense to collapse those. if (actualLines.length > 50) { @@ -186,7 +190,7 @@ export function createErrDiff( } } - return `${kReadableOperator['notIdentical']}\n\n${actualLines.join("\n")}\n`; + return `${kReadableOperator['notIdentical']}\n\n${actualLines.join('\n')}\n`; } // There were at least five identical lines at the end. Mark a couple of @@ -195,14 +199,15 @@ export function createErrDiff( end = `\n${blue}...${defaultColor}${end}`; skipped = true; } - if (other !== "") { + if (other !== '') { end = `\n ${other}${end}`; - other = ""; + other = ''; } let printedLines = 0; let identical = 0; - const msg = kReadableOperator[operator] + + const msg = + kReadableOperator[operator] + `\n${green}+ actual${defaultColor} ${red}- expected${defaultColor}`; const skippedMsg = ` ${blue}...${defaultColor} Lines skipped`; @@ -253,8 +258,9 @@ export function createErrDiff( // If the lines diverge, specifically check for lines that only diverge by // a trailing comma. In that case it is actually identical and we should // mark it as such. - let divergingLines = actualLine !== expectedLine && - (!(actualLine as string).endsWith(",") || + let divergingLines = + actualLine !== expectedLine && + (!(actualLine as string).endsWith(',') || (actualLine as string).slice(0, -1) !== expectedLine); // If the expected line has a trailing comma but is otherwise identical, // add a comma at the end of the actual line. Otherwise the output could @@ -267,11 +273,11 @@ export function createErrDiff( // if ( divergingLines && - (expectedLine as string).endsWith(",") && + (expectedLine as string).endsWith(',') && (expectedLine as string).slice(0, -1) === actualLine ) { divergingLines = false; - actualLine += ","; + actualLine += ','; } if (divergingLines) { // If more than two former lines are identical, print them. Collapse @@ -305,7 +311,7 @@ export function createErrDiff( // Add all cached information to the result before adding other things // and reset the cache. res += other; - other = ""; + other = ''; identical++; // The very first identical line since the last diverging line is be // added to the result. @@ -317,12 +323,14 @@ export function createErrDiff( } // Inspected object to big (Show ~50 rows max) if (printedLines > 50 && i < maxLines - 2) { - return `${msg}${skippedMsg}\n${res}\n${blue}...${defaultColor}${other}\n` + - `${blue}...${defaultColor}`; + return ( + `${msg}${skippedMsg}\n${res}\n${blue}...${defaultColor}${other}\n` + + `${blue}...${defaultColor}` + ); } } - return `${msg}${skipped ? skippedMsg : ""}\n${res}${other}${end}${indicator}`; + return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}${indicator}`; } export interface AssertionErrorDetailsDescriptor { @@ -355,8 +363,8 @@ export class AssertionError extends Error { // deno-lint-ignore constructor-super constructor(options: AssertionErrorConstructorOptions) { - if (typeof options !== "object" || options === null) { - throw new ERR_INVALID_ARG_TYPE("options", "Object", options); + if (typeof options !== 'object' || options === null) { + throw new ERR_INVALID_ARG_TYPE('options', 'Object', options); } const { message, @@ -366,10 +374,7 @@ export class AssertionError extends Error { // Compatibility with older versions. stackStartFunction, } = options; - let { - actual, - expected, - } = options; + let { actual, expected } = options; // TODO(schwarzkopfb): `stackTraceLimit` should be added to `ErrorConstructor` in // cli/dts/lib.deno.shared_globals.d.ts @@ -383,32 +388,36 @@ export class AssertionError extends Error { // in a very close way to the original in case both sides are actually // instances of Error. if ( - typeof actual === "object" && actual !== null && - typeof expected === "object" && expected !== null && - "stack" in actual && actual instanceof Error && - "stack" in expected && expected instanceof Error + typeof actual === 'object' && + actual !== null && + typeof expected === 'object' && + expected !== null && + 'stack' in actual && + actual instanceof Error && + 'stack' in expected && + expected instanceof Error ) { actual = copyError(actual); expected = copyError(expected); } - if (operator === "deepStrictEqual" || operator === "strictEqual") { + if (operator === 'deepStrictEqual' || operator === 'strictEqual') { super(createErrDiff(actual, expected, operator)); } else if ( - operator === "notDeepStrictEqual" || - operator === "notStrictEqual" + operator === 'notDeepStrictEqual' || + operator === 'notStrictEqual' ) { // In case the objects are equal but the operator requires unequal, show // the first object and say A equals B let base = kReadableOperator[operator]; - const res = inspectValue(actual).split("\n"); + const res = inspectValue(actual).split('\n'); // In case "actual" is an object or a function, it should not be // reference equal. if ( - operator === "notStrictEqual" && - ((typeof actual === "object" && actual !== null) || - typeof actual === "function") + operator === 'notStrictEqual' && + ((typeof actual === 'object' && actual !== null) || + typeof actual === 'function') ) { base = kReadableOperator['notStrictEqualObject']; } @@ -423,15 +432,15 @@ export class AssertionError extends Error { // Only print a single input. if (res.length === 1) { - super(`${base}${res[0]!.length > 5 ? "\n\n" : " "}${res[0]}`); + super(`${base}${res[0]!.length > 5 ? '\n\n' : ' '}${res[0]}`); } else { - super(`${base}\n\n${res.join("\n")}\n`); + super(`${base}\n\n${res.join('\n')}\n`); } } else { let res = inspectValue(actual); let other = inspectValue(expected); - const knownOperator = kReadableOperator[operator ?? ""]; - if (operator === "notDeepEqual" && res === other) { + const knownOperator = kReadableOperator[operator ?? '']; + if (operator === 'notDeepEqual' && res === other) { res = `${knownOperator}\n\n${res}`; if (res.length > 1024) { res = `${res.slice(0, 1021)}...`; @@ -444,7 +453,7 @@ export class AssertionError extends Error { if (other.length > 512) { other = `${other.slice(0, 509)}...`; } - if (operator === "deepEqual") { + if (operator === 'deepEqual') { res = `${knownOperator}\n\n${res}\n\nshould loosely deep-equal\n\n`; } else { const newOp = kReadableOperator[`${operator}Unequal`]; @@ -462,15 +471,15 @@ export class AssertionError extends Error { (Error as ErrorWithStackTraceLimit).stackTraceLimit = limit; (this as any).generatedMessage = !message; - Object.defineProperty(this, "name", { + Object.defineProperty(this, 'name', { __proto__: null, - value: "AssertionError [ERR_ASSERTION]", + value: 'AssertionError [ERR_ASSERTION]', enumerable: false, writable: true, configurable: true, // deno-lint-ignore no-explicit-any } as any); - (this as any).code = "ERR_ASSERTION"; + (this as any).code = 'ERR_ASSERTION'; if (details) { (this as any).actual = undefined; @@ -478,11 +487,11 @@ export class AssertionError extends Error { (this as any).operator = undefined; for (let i = 0; i < details.length; i++) { - this["message " + i] = (details[i] as any).message; - this["actual " + i] = (details[i] as any).actual; - this["expected " + i] = (details[i] as any).expected; - this["operator " + i] = (details[i] as any).operator; - this["stack trace " + i] = (details[i] as any).stack; + this['message ' + i] = (details[i] as any).message; + this['actual ' + i] = (details[i] as any).actual; + this['expected ' + i] = (details[i] as any).expected; + this['operator ' + i] = (details[i] as any).operator; + this['stack trace ' + i] = (details[i] as any).stack; } } else { (this as any).actual = actual; @@ -495,7 +504,7 @@ export class AssertionError extends Error { // Create error message including the error code in the name. this.stack; // Reset the name. - this.name = "AssertionError"; + this.name = 'AssertionError'; } override toString() { @@ -507,13 +516,13 @@ export class AssertionError extends Error { const tmpActual = (this as any).actual; const tmpExpected = (this as any).expected; - for (const name of ["actual", "expected"]) { - if (typeof this[name] === "string") { + for (const name of ['actual', 'expected']) { + if (typeof this[name] === 'string') { const value = this[name] as string; - const lines = value.split("\n"); + const lines = value.split('\n'); if (lines.length > 10) { lines.length = 10; - this[name] = `${lines.join("\n")}\n...`; + this[name] = `${lines.join('\n')}\n...`; } else if (value.length > 512) { this[name] = `${value.slice(512)}...`; } diff --git a/src/node/internal/internal_buffer.ts b/src/node/internal/internal_buffer.ts index 6056a2ca03e..41af0f77056 100644 --- a/src/node/internal/internal_buffer.ts +++ b/src/node/internal/internal_buffer.ts @@ -28,13 +28,9 @@ import { isUint8Array, } from 'node-internal:internal_types'; -import { - normalizeEncoding, -} from 'node-internal:internal_utils'; +import { normalizeEncoding } from 'node-internal:internal_utils'; -import { - validateString, -} from 'node-internal:validators'; +import { validateString } from 'node-internal:validators'; import internalUtil from 'node-internal:util'; import { @@ -64,8 +60,8 @@ const MAX_UINT32 = 2 ** 32; const kIsBuffer = Symbol('kIsBuffer'); const customInspectSymbol = - typeof Symbol === "function" && typeof Symbol["for"] === "function" - ? Symbol["for"]("nodejs.util.inspect.custom") + typeof Symbol === 'function' && typeof Symbol['for'] === 'function' + ? Symbol['for']('nodejs.util.inspect.custom') : null; const INSPECT_MAX_BYTES = 50; @@ -75,34 +71,48 @@ export const constants = { MAX_STRING_LENGTH: kStringMaxLength, }; -function createBuffer(length: number) : Buffer { +function createBuffer(length: number): Buffer { if (length > kMaxLength) { - throw new ERR_OUT_OF_RANGE('The given length is invalid', `0 to ${kMaxLength}`, length); + throw new ERR_OUT_OF_RANGE( + 'The given length is invalid', + `0 to ${kMaxLength}`, + length + ); } const buf = new Uint8Array(length); Object.setPrototypeOf(buf, Buffer.prototype); return buf as Buffer; } -type WithImplicitCoercion = | T | { valueOf(): T; }; -export type StringLike = WithImplicitCoercion | { [Symbol.toPrimitive](hint: "string"): string; }; -type ArrayBufferLike = WithImplicitCoercion; -type BufferSource = StringLike|ArrayBufferLike|Uint8Array|ReadonlyArray; +type WithImplicitCoercion = T | { valueOf(): T }; +export type StringLike = + | WithImplicitCoercion + | { [Symbol.toPrimitive](hint: 'string'): string }; +type ArrayBufferLike = WithImplicitCoercion; +type BufferSource = + | StringLike + | ArrayBufferLike + | Uint8Array + | ReadonlyArray; export interface Buffer extends Uint8Array { readonly buffer: ArrayBuffer; readonly parent: ArrayBuffer; readonly byteOffset: number; readonly length: number; - compare(target: Uint8Array, - targetStart?: number, - targetEnd?: number, - sourceStart?: number, - sourceEnd?: number): number; - copy(target: Uint8Array, - targetStart?: number, - sourceStart?: number, - sourceEnd?: number): number; + compare( + target: Uint8Array, + targetStart?: number, + targetEnd?: number, + sourceStart?: number, + sourceEnd?: number + ): number; + copy( + target: Uint8Array, + targetStart?: number, + sourceStart?: number, + sourceEnd?: number + ): number; equals(other: Uint8Array): boolean; fill(value: number, offset?: number, end?: number): this; fill(value: string, encoding?: string): this; @@ -120,36 +130,41 @@ export interface Buffer extends Uint8Array { lastIndexOf(value: string, encoding?: string): number; lastIndexOf(value: string, byteOffset?: number, encoding?: string): number; lastIndexOf(value: Uint8Array, byteOffset?: number): number; - readBigInt64BE(offset?: number) : bigint; - readBigInt64LE(offset?: number) : bigint; - readBigUInt64BE(offset?: number) : bigint; - readBigUInt64LE(offset?: number) : bigint; - readDoubleBE(offset?: number) : number; - readDoubleLE(offset?: number) : number; - readFloatBE(offset?: number) : number; - readFloatLE(offset?: number) : number; - readInt8(offset?: number) : number; - readInt16BE(offset?: number) : number; - readInt16LE(offset?: number) : number; - readInt32BE(offset?: number) : number; - readInt32LE(offset?: number) : number; - readIntBE(offset?: number, byteLength?: number) : number; - readIntLE(offset?: number, byteLength?: number) : number; - readUInt8(offset?: number) : number; - readUInt16BE(offset?: number) : number; - readUInt16LE(offset?: number) : number; - readUInt32BE(offset?: number) : number; - readUInt32LE(offset?: number) : number; - readUIntBE(offset?: number, byteLength?: number) : number; - readUIntLE(offset?: number, byteLength?: number) : number; + readBigInt64BE(offset?: number): bigint; + readBigInt64LE(offset?: number): bigint; + readBigUInt64BE(offset?: number): bigint; + readBigUInt64LE(offset?: number): bigint; + readDoubleBE(offset?: number): number; + readDoubleLE(offset?: number): number; + readFloatBE(offset?: number): number; + readFloatLE(offset?: number): number; + readInt8(offset?: number): number; + readInt16BE(offset?: number): number; + readInt16LE(offset?: number): number; + readInt32BE(offset?: number): number; + readInt32LE(offset?: number): number; + readIntBE(offset?: number, byteLength?: number): number; + readIntLE(offset?: number, byteLength?: number): number; + readUInt8(offset?: number): number; + readUInt16BE(offset?: number): number; + readUInt16LE(offset?: number): number; + readUInt32BE(offset?: number): number; + readUInt32LE(offset?: number): number; + readUIntBE(offset?: number, byteLength?: number): number; + readUIntLE(offset?: number, byteLength?: number): number; swap16(): this; swap32(): this; swap64(): this; - toJSON(): {type: 'Buffer', data: number[]}; + toJSON(): { type: 'Buffer'; data: number[] }; toString(encoding?: string, start?: number, end?: number): string; write(string: string, encoding?: string): number; write(string: string, offset?: number, encoding?: string): number; - write(string: string, offset?: number, length?: number, encoding?: string): number; + write( + string: string, + offset?: number, + length?: number, + encoding?: string + ): number; writeBigInt64BE(value: bigint, offset?: number): number; writeBigInt64LE(value: bigint, offset?: number): number; writeBigUInt64BE(value: bigint, offset?: number): number; @@ -172,29 +187,40 @@ export interface Buffer extends Uint8Array { writeUInt32LE(value: number, offset?: number): number; writeUIntBE(value: number, offset?: number, byteLength?: number): number; writeUIntLE(value: number, offset?: number, byteLength?: number): number; - new (array:Iterable): Buffer; - new (arrayBuffer: ArrayBufferLike, byteOffset?: number, length?: number): Buffer; + new (array: Iterable): Buffer; + new ( + arrayBuffer: ArrayBufferLike, + byteOffset?: number, + length?: number + ): Buffer; new (buffer: ArrayBufferView): Buffer; new (size: number): Buffer; new (string: string, encoding?: string): Buffer; -}; +} -type FillValue = string|number|ArrayBufferView; - -export function Buffer(value: number) : Buffer; -export function Buffer(value: StringLike, encoding?: string) : Buffer; -export function Buffer(value: ArrayBufferLike, byteOffset?: number, length?: number) : Buffer; -export function Buffer(value: Uint8Array|ReadonlyArray, - byteOffset?: number, - length?: number) : Buffer; - export function Buffer(value: StringLike, - encoding?: string) : Buffer; -export function Buffer(value: number|BufferSource, - encodingOrOffset? : string|number, - length?: number) : Buffer { - if (typeof value === "number") { - if (typeof encodingOrOffset === "string") { - throw new ERR_INVALID_ARG_TYPE("string", "string", value); +type FillValue = string | number | ArrayBufferView; + +export function Buffer(value: number): Buffer; +export function Buffer(value: StringLike, encoding?: string): Buffer; +export function Buffer( + value: ArrayBufferLike, + byteOffset?: number, + length?: number +): Buffer; +export function Buffer( + value: Uint8Array | ReadonlyArray, + byteOffset?: number, + length?: number +): Buffer; +export function Buffer(value: StringLike, encoding?: string): Buffer; +export function Buffer( + value: number | BufferSource, + encodingOrOffset?: string | number, + length?: number +): Buffer { + if (typeof value === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new ERR_INVALID_ARG_TYPE('string', 'string', value); } return allocUnsafe(value); } @@ -216,7 +242,7 @@ Object.defineProperties(Buffer, { enumerable: true, value: 0, writable: false, - } + }, }); Object.defineProperties(Buffer.prototype, { @@ -245,75 +271,100 @@ Object.defineProperties(Buffer.prototype, { }, }); -function _from(value: BufferSource, - encodingOrOffset? : string|number, - length?: number) : Buffer { - if (typeof value === "string") { +function _from( + value: BufferSource, + encodingOrOffset?: string | number, + length?: number +): Buffer { + if (typeof value === 'string') { return fromString(value, encodingOrOffset as string | undefined) as Buffer; } - if (typeof value === "object" && value != null) { + if (typeof value === 'object' && value != null) { if (isAnyArrayBuffer(value)) { - return fromArrayBuffer(value as ArrayBufferLike, encodingOrOffset as number, length) as Buffer; + return fromArrayBuffer( + value as ArrayBufferLike, + encodingOrOffset as number, + length + ) as Buffer; } const valueOf = value?.valueOf(); - if (valueOf != null && valueOf !== value && - (typeof valueOf === "string" || typeof valueOf === "object")) { + if ( + valueOf != null && + valueOf !== value && + (typeof valueOf === 'string' || typeof valueOf === 'object') + ) { return _from(valueOf as BufferSource, encodingOrOffset, length); } - if ((value as any).length !== undefined || isAnyArrayBuffer((value as any).buffer)) { - if (typeof (value as any).length !== "number") { + if ( + (value as any).length !== undefined || + isAnyArrayBuffer((value as any).buffer) + ) { + if (typeof (value as any).length !== 'number') { return createBuffer(0); } return fromArrayLike(value as any) as Buffer; } - if ((value as any).type === "Buffer" && Array.isArray((value as any).data)) { + if ( + (value as any).type === 'Buffer' && + Array.isArray((value as any).data) + ) { return fromArrayLike((value as any).data) as Buffer; } const toPrimitive = (value as any)[Symbol.toPrimitive]; - if (typeof toPrimitive === "function") { - const primitive = toPrimitive("string"); - if (typeof primitive === "string") { - return fromString(primitive, encodingOrOffset as string | undefined) as Buffer; + if (typeof toPrimitive === 'function') { + const primitive = toPrimitive('string'); + if (typeof primitive === 'string') { + return fromString( + primitive, + encodingOrOffset as string | undefined + ) as Buffer; } } } throw new ERR_INVALID_ARG_TYPE( - "first argument", + 'first argument', [ - "string", - "Buffer", - "TypedArray", - "ArrayBuffer", - "SharedArrayBuffer", - "Array", - "Array-like Object" + 'string', + 'Buffer', + 'TypedArray', + 'ArrayBuffer', + 'SharedArrayBuffer', + 'Array', + 'Array-like Object', ], - value, + value ); } -function from(value: StringLike, - encoding?: string) : Buffer; -function from(value: ArrayBufferLike, - byteOffset?: number, - length?: number) : Buffer; -function from(value: Uint8Array|ReadonlyArray, - byteOffset?: number, - length?: number) : Buffer; -function from(value: BufferSource, encodingOrOffset?: string|number, length?: number) { +function from(value: StringLike, encoding?: string): Buffer; +function from( + value: ArrayBufferLike, + byteOffset?: number, + length?: number +): Buffer; +function from( + value: Uint8Array | ReadonlyArray, + byteOffset?: number, + length?: number +): Buffer; +function from( + value: BufferSource, + encodingOrOffset?: string | number, + length?: number +) { return _from(value, encodingOrOffset, length); -}; +} function fromString(string: StringLike, encoding?: string) { - if (typeof encoding !== "string" || encoding === "") { - encoding = "utf8"; + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8'; } const normalizedEncoding = normalizeEncoding(encoding); if (normalizedEncoding === undefined) { @@ -322,20 +373,25 @@ function fromString(string: StringLike, encoding?: string) { const ab = bufferUtil.decodeString(`${string}`, normalizedEncoding); if (ab === undefined) { - throw new ERR_INVALID_ARG_VALUE('string', string, - `Unable to decode string using encoding ${encoding}`); + throw new ERR_INVALID_ARG_VALUE( + 'string', + string, + `Unable to decode string using encoding ${encoding}` + ); } return fromArrayBuffer(ab, 0, ab.byteLength); } -function fromArrayLike(array: Uint8Array|ReadonlyArray) { +function fromArrayLike(array: Uint8Array | ReadonlyArray) { const u8 = Uint8Array.from(array); return fromArrayBuffer(u8.buffer, u8.byteOffset, u8.byteLength); } -function fromArrayBuffer(obj: ArrayBufferLike, - byteOffset: number, - length?: number) { +function fromArrayBuffer( + obj: ArrayBufferLike, + byteOffset: number, + length?: number +) { // Convert byteOffset to integer if (byteOffset === undefined) { byteOffset = 0; @@ -349,7 +405,7 @@ function fromArrayBuffer(obj: ArrayBufferLike, const maxLength = (obj as ArrayBuffer).byteLength - byteOffset; if (maxLength < 0) { - throw new ERR_BUFFER_OUT_OF_BOUNDS("offset"); + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } if (length === undefined) { @@ -359,7 +415,7 @@ function fromArrayBuffer(obj: ArrayBufferLike, length = +length; if (length > 0) { if (length > maxLength) { - throw new ERR_BUFFER_OUT_OF_BOUNDS("length"); + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); } } else { length = 0; @@ -375,20 +431,19 @@ Buffer.from = from; function of(...args: number[]) { const buf = Buffer.alloc(args.length); - for (let k = 0; k < args.length; k++) - buf[k] = args[k]!; + for (let k = 0; k < args.length; k++) buf[k] = args[k]!; return buf; } Buffer.of = of; -function alloc(size: number, fill?: FillValue, encoding?: string) : Buffer { - validateNumber(size, "size"); +function alloc(size: number, fill?: FillValue, encoding?: string): Buffer { + validateNumber(size, 'size'); if (Number.isNaN(size)) { throw new ERR_INVALID_ARG_VALUE.RangeError('size', size); } if (size >= kMaxLength) { - throw new ERR_OUT_OF_RANGE("size", `0 to ${kMaxLength}`, size); + throw new ERR_OUT_OF_RANGE('size', `0 to ${kMaxLength}`, size); } const buffer = createBuffer(size); @@ -403,7 +458,7 @@ function alloc(size: number, fill?: FillValue, encoding?: string) : Buffer { Buffer.alloc = alloc; -function allocUnsafe(size: number) : Buffer { +function allocUnsafe(size: number): Buffer { return alloc(size); } @@ -421,7 +476,7 @@ Buffer.isBuffer = function isBuffer(b: unknown) { return b != null && (b as any)[kIsBuffer] && b !== Buffer.prototype; }; -export function compare(a: Buffer|Uint8Array, b: Buffer|Uint8Array) { +export function compare(a: Buffer | Uint8Array, b: Buffer | Uint8Array) { if (isInstance(a, Uint8Array)) { const buf = a as Uint8Array; a = fromArrayBuffer(buf.buffer, buf.byteOffset, buf.byteLength); @@ -444,16 +499,21 @@ export function compare(a: Buffer|Uint8Array, b: Buffer|Uint8Array) { Buffer.compare = compare; export function isEncoding(encoding: unknown): encoding is string { - return typeof encoding === "string" && + return ( + typeof encoding === 'string' && encoding.length !== 0 && - normalizeEncoding(encoding) !== undefined; -}; + normalizeEncoding(encoding) !== undefined + ); +} Buffer.isEncoding = isEncoding; -Buffer.concat = function concat(list: (Buffer|Uint8Array)[], length?: number) { +Buffer.concat = function concat( + list: (Buffer | Uint8Array)[], + length?: number +) { if (!Array.isArray(list)) { - throw new ERR_INVALID_ARG_TYPE("list", "(Buffer|Uint8Array)[]", list); + throw new ERR_INVALID_ARG_TYPE('list', '(Buffer|Uint8Array)[]', list); } if (list.length === 0) return alloc(0); @@ -464,11 +524,15 @@ Buffer.concat = function concat(list: (Buffer|Uint8Array)[], length?: number) { if (list[i]!.length !== undefined) { length += list[i]!.length; } else { - throw new ERR_INVALID_ARG_TYPE('list', '(Buffer|Uint8Array)[]', list[i]); + throw new ERR_INVALID_ARG_TYPE( + 'list', + '(Buffer|Uint8Array)[]', + list[i] + ); } } } - validateOffset(length, "length"); + validateOffset(length, 'length'); const ab = bufferUtil.concat(list, length as number); return fromArrayBuffer(ab, 0, length); @@ -478,21 +542,27 @@ function base64ByteLength(str: string) { let len = str.length; if (str.charCodeAt(len - 1) === 0x3d) { len--; - } if (len > 1 && str.charCodeAt(len - 1) === 0x3d) - len--; + } + if (len > 1 && str.charCodeAt(len - 1) === 0x3d) len--; // Base64 ratio: 3/4 return (len * 3) >>> 2; } -function byteLength(string: string|ArrayBufferView|ArrayBuffer|SharedArrayBuffer, - encoding?: string) { - if (typeof string !== "string") { +function byteLength( + string: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, + encoding?: string +) { + if (typeof string !== 'string') { if (isArrayBufferView(string) || isAnyArrayBuffer(string)) { return string.byteLength; } - throw new ERR_INVALID_ARG_TYPE("string", ["string", "Buffer", "ArrayBuffer"], string); + throw new ERR_INVALID_ARG_TYPE( + 'string', + ['string', 'Buffer', 'ArrayBuffer'], + string + ); } string = `${string}`; @@ -500,19 +570,19 @@ function byteLength(string: string|ArrayBufferView|ArrayBuffer|SharedArrayBuffer switch (normalizedEncoding) { case ASCII: - // Fall through + // Fall through case LATIN1: return (string as string).length; case UTF16LE: return (string as string).length * 2; case BASE64: - // Fall through + // Fall through case BASE64URL: return base64ByteLength(string as string); case HEX: return (string as string).length >>> 1; case UTF8: - // Fall-through + // Fall-through default: return bufferUtil.byteLength(string as string); } @@ -548,9 +618,10 @@ Buffer.prototype.swap64 = function swap64() { }; Buffer.prototype.toString = function toString( - encoding?: string, - start?: number, - end?: number) { + encoding?: string, + start?: number, + end?: number +) { if (arguments.length === 0) { return bufferUtil.toString(this, 0, this.length, UTF8); } @@ -560,7 +631,7 @@ Buffer.prototype.toString = function toString( if (start === undefined || start <= 0) { start = 0; } else if (start >= len) { - return ""; + return ''; } else { start |= 0; } @@ -572,7 +643,7 @@ Buffer.prototype.toString = function toString( } if ((end as number) <= start) { - return ""; + return ''; } const normalizedEncoding = normalizeEncoding(`${encoding}`); @@ -580,46 +651,56 @@ Buffer.prototype.toString = function toString( throw new ERR_UNKNOWN_ENCODING(`${encoding}`); } - return bufferUtil.toString(this, start as number, end as number, normalizedEncoding); + return bufferUtil.toString( + this, + start as number, + end as number, + normalizedEncoding + ); }; Buffer.prototype.toLocaleString = Buffer.prototype.toString; -Buffer.prototype.equals = function equals(b: Buffer|Uint8Array) { +Buffer.prototype.equals = function equals(b: Buffer | Uint8Array) { return compare(this, b) === 0; }; -Buffer.prototype.inspect = function inspect(_recurseTimes: number, ctx: InspectOptionsStylized) { - let str = ""; +Buffer.prototype.inspect = function inspect( + _recurseTimes: number, + ctx: InspectOptionsStylized +) { + let str = ''; const max = INSPECT_MAX_BYTES; - str = this.toString("hex", 0, max).replace(/(.{2})/g, "$1 ").trim(); + str = this.toString('hex', 0, max) + .replace(/(.{2})/g, '$1 ') + .trim(); const remaining = this.length - max; if (remaining > 0) { str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; } // Inspect special properties as well, if possible. - if (ctx) { - let extras = false; - const filter = ctx.showHidden ? internalUtil.ALL_PROPERTIES : internalUtil.ONLY_ENUMERABLE; - const obj: Record = { __proto__: null }; - internalUtil.getOwnNonIndexProperties(this, filter).forEach( - (key) => { - extras = true; - obj[key] = this[key]; - }); - if (extras) { - if (this.length !== 0) - str += ', '; - // '[Object: null prototype] {'.length === 26 - // This is guarded with a test. - str += utilInspect(obj, { - ...ctx, - breakLength: Infinity, - compact: true, - }).slice(27, -2); - } + if (ctx) { + let extras = false; + const filter = ctx.showHidden + ? internalUtil.ALL_PROPERTIES + : internalUtil.ONLY_ENUMERABLE; + const obj: Record = { __proto__: null }; + internalUtil.getOwnNonIndexProperties(this, filter).forEach((key) => { + extras = true; + obj[key] = this[key]; + }); + if (extras) { + if (this.length !== 0) str += ', '; + // '[Object: null prototype] {'.length === 26 + // This is guarded with a test. + str += utilInspect(obj, { + ...ctx, + breakLength: Infinity, + compact: true, + }).slice(27, -2); } - return ""; + } + return ''; }; if (customInspectSymbol) { @@ -627,41 +708,45 @@ if (customInspectSymbol) { } Buffer.prototype.compare = function compare( - target: Buffer|Uint8Array, + target: Buffer | Uint8Array, start?: number, end?: number, thisStart?: number, - thisEnd?: number, + thisEnd?: number ) { if (isInstance(target, Uint8Array)) { - target = fromArrayBuffer(target.buffer, target.byteOffset, target.byteLength); + target = fromArrayBuffer( + target.buffer, + target.byteOffset, + target.byteLength + ); } if (!Buffer.isBuffer(target)) { - throw new ERR_INVALID_ARG_TYPE("target", ["Buffer", "Uint8Array"], target); + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); } if (start === undefined) { start = 0; } else { - validateOffset(start, "targetStart", 0, kMaxLength); + validateOffset(start, 'targetStart', 0, kMaxLength); } if (end === undefined) { end = target.length; } else { - validateOffset(end, "targetEnd", 0, target.length); + validateOffset(end, 'targetEnd', 0, target.length); } if (thisStart === undefined) { thisStart = 0; } else { - validateOffset(thisStart as number, "sourceStart", 0, kMaxLength); + validateOffset(thisStart as number, 'sourceStart', 0, kMaxLength); } if (thisEnd === undefined) { thisEnd = this.length; } else { - validateOffset(thisEnd as number, "sourceEnd", 0, this.length); + validateOffset(thisEnd as number, 'sourceEnd', 0, this.length); } return bufferUtil.compare(this, target, { @@ -673,16 +758,16 @@ Buffer.prototype.compare = function compare( }; function includes( - this: Buffer, - val: string|number|Buffer|Uint8Array, - byteOffset?: number, - encoding?: string) { + this: Buffer, + val: string | number | Buffer | Uint8Array, + byteOffset?: number, + encoding?: string +) { return this.indexOf(val as any, byteOffset, encoding) !== -1; } Buffer.prototype.includes = includes; - // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, // OR the last index of `val` in `buffer` at offset <= `byteOffset`. // @@ -694,30 +779,34 @@ Buffer.prototype.includes = includes; // - dir - true for indexOf, false for lastIndexOf function bidirectionalIndexOf( buffer: Uint8Array, - val: string|number|Buffer|Uint8Array, - byteOffset: number|string|undefined, - encoding: string|undefined, - dir: boolean|undefined) { - + val: string | number | Buffer | Uint8Array, + byteOffset: number | string | undefined, + encoding: string | undefined, + dir: boolean | undefined +) { if (Buffer.isBuffer(val) && !isUint8Array(val)) { - throw new ERR_INVALID_ARG_TYPE('val', ['string', 'number', 'Buffer', 'Uint8Array'], val); + throw new ERR_INVALID_ARG_TYPE( + 'val', + ['string', 'number', 'Buffer', 'Uint8Array'], + val + ); } if (typeof byteOffset === 'string') { encoding = byteOffset; byteOffset = undefined; - } else if (byteOffset as number > 0x7fffffff) { + } else if ((byteOffset as number) > 0x7fffffff) { byteOffset = 0x7fffffff; - } else if (byteOffset as number < -0x80000000) { + } else if ((byteOffset as number) < -0x80000000) { byteOffset = -0x80000000; } // Coerce to Number. Values like null and [] become 0. byteOffset = +(byteOffset as number); // If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer. if (Number.isNaN(byteOffset)) { - byteOffset = dir ? 0 : (buffer.length || buffer.byteLength); + byteOffset = dir ? 0 : buffer.length || buffer.byteLength; } - dir = !!dir; // Cast to bool. + dir = !!dir; // Cast to bool. if (typeof val === 'number') { val = (val >>> 0) & 0xff; @@ -729,7 +818,11 @@ function bidirectionalIndexOf( } if (typeof val !== 'string' && !isUint8Array(val) && !Buffer.isBuffer(val)) { - throw new ERR_INVALID_ARG_TYPE('value', ['number', 'string', 'Buffer', 'Uint8Array'], val); + throw new ERR_INVALID_ARG_TYPE( + 'value', + ['number', 'string', 'Buffer', 'Uint8Array'], + val + ); } const normalizedEncoding = normalizeEncoding(encoding); @@ -737,140 +830,215 @@ function bidirectionalIndexOf( throw new ERR_UNKNOWN_ENCODING(`${encoding}`); } - const result = bufferUtil.indexOf(buffer, val, byteOffset, normalizedEncoding, dir); + const result = bufferUtil.indexOf( + buffer, + val, + byteOffset, + normalizedEncoding, + dir + ); return result == null ? -1 : result; } Buffer.prototype.indexOf = function indexOf( - val: string|number|Buffer|Uint8Array, - byteOffset?: number|string, - encoding?: string) { + val: string | number | Buffer | Uint8Array, + byteOffset?: number | string, + encoding?: string +) { return bidirectionalIndexOf(this, val, byteOffset, encoding, true); }; Buffer.prototype.lastIndexOf = function lastIndexOf( - val: string|number|Buffer|Uint8Array, - byteOffset?: number|string, - encoding?: string) { + val: string | number | Buffer | Uint8Array, + byteOffset?: number | string, + encoding?: string +) { return bidirectionalIndexOf(this, val, byteOffset, encoding, false); }; Buffer.prototype.asciiSlice = function asciiSlice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, ASCII); }; -Buffer.prototype.base64Slice = function base64Slice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); +Buffer.prototype.base64Slice = function base64Slice( + start: number, + end: number +) { + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, BASE64); }; -Buffer.prototype.base64urlSlice = function base64urlSlice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); +Buffer.prototype.base64urlSlice = function base64urlSlice( + start: number, + end: number +) { + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, BASE64URL); }; Buffer.prototype.hexSlice = function hexSlice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, HEX); }; -Buffer.prototype.latin1Slice = function latin1Slice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); +Buffer.prototype.latin1Slice = function latin1Slice( + start: number, + end: number +) { + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, LATIN1); }; Buffer.prototype.ucs2Slice = function ucs2Slice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, UTF16LE); }; Buffer.prototype.utf8Slice = function utf8Slice(start: number, end: number) { - validateOffset(start, "start", 0, this.length); - validateOffset(end, "end", 0, this.length); + validateOffset(start, 'start', 0, this.length); + validateOffset(end, 'end', 0, this.length); return bufferUtil.toString(this, start, end, UTF8); }; -Buffer.prototype.asciiWrite = function asciiWrite(string: StringLike, - offset?: number, - length?: number) { +Buffer.prototype.asciiWrite = function asciiWrite( + string: StringLike, + offset?: number, + length?: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, ASCII); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + ASCII + ); }; -Buffer.prototype.base64Write = function base64Write(string: StringLike, - offset?: number, - length?: number) { +Buffer.prototype.base64Write = function base64Write( + string: StringLike, + offset?: number, + length?: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, BASE64); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + BASE64 + ); }; -Buffer.prototype.base64urlWrite = function base64urlWrite(string: StringLike, - offset?: number, - length?: number) { +Buffer.prototype.base64urlWrite = function base64urlWrite( + string: StringLike, + offset?: number, + length?: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, BASE64URL); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + BASE64URL + ); }; -Buffer.prototype.hexWrite = function hexWrite(string: StringLike, - offset: number, - length: number) { +Buffer.prototype.hexWrite = function hexWrite( + string: StringLike, + offset: number, + length: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, HEX); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + HEX + ); }; -Buffer.prototype.latin1Write = function latin1Write(string: StringLike, - offset: number, - length: number) { +Buffer.prototype.latin1Write = function latin1Write( + string: StringLike, + offset: number, + length: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, LATIN1); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + LATIN1 + ); }; -Buffer.prototype.ucs2Write = function ucs2Write(string: StringLike, - offset: number, - length: number) { +Buffer.prototype.ucs2Write = function ucs2Write( + string: StringLike, + offset: number, + length: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, UTF16LE); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + UTF16LE + ); }; -Buffer.prototype.utf8Write = function utf8Write(string: StringLike, - offset: number, - length: number) { +Buffer.prototype.utf8Write = function utf8Write( + string: StringLike, + offset: number, + length: number +) { offset ??= 0; length ??= this.length; - validateOffset(offset as number, "offset", 0, this.length); - validateOffset(length as number, "length", 0, this.length - offset); - return bufferUtil.write(this, `${string}`, offset as number, length as number, UTF8); + validateOffset(offset as number, 'offset', 0, this.length); + validateOffset(length as number, 'length', 0, this.length - offset); + return bufferUtil.write( + this, + `${string}`, + offset as number, + length as number, + UTF8 + ); }; -Buffer.prototype.write = function write(string: StringLike, - offset?: number | string, - length?: number | string, - encoding?: string) { +Buffer.prototype.write = function write( + string: StringLike, + offset?: number | string, + length?: number | string, + encoding?: string +) { string = `${string}`; if (offset === undefined) { // Buffer#write(string) @@ -902,7 +1070,13 @@ Buffer.prototype.write = function write(string: StringLike, } if (!encoding) { - return bufferUtil.write(this, string as string, offset as number, length as number, UTF8); + return bufferUtil.write( + this, + string as string, + offset as number, + length as number, + UTF8 + ); } const normalizedEncoding = normalizeEncoding(encoding); @@ -910,13 +1084,18 @@ Buffer.prototype.write = function write(string: StringLike, throw new ERR_UNKNOWN_ENCODING(`${encoding}`); } - return bufferUtil.write(this, string as string, offset as number, length as number, - normalizedEncoding); + return bufferUtil.write( + this, + string as string, + offset as number, + length as number, + normalizedEncoding + ); }; Buffer.prototype.toJSON = function toJSON() { return { - type: "Buffer", + type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0), }; }; @@ -953,43 +1132,58 @@ Buffer.prototype.slice = function slice(start: number, end?: number) { Buffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE( offset: number, - byteLength: number) { + byteLength: number +) { if (offset === undefined) { - throw new ERR_INVALID_ARG_TYPE("offset", "number", offset); + throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); } switch (byteLength) { - case 1: return this.readUInt8(offset); - case 2: return this.readUInt16LE(offset); - case 3: return readUInt24LE(this, offset); - case 4: return this.readUInt32LE(offset); - case 5: return readUInt40LE(this, offset); - case 6: return readUInt48LE(this, offset); + case 1: + return this.readUInt8(offset); + case 2: + return this.readUInt16LE(offset); + case 3: + return readUInt24LE(this, offset); + case 4: + return this.readUInt32LE(offset); + case 5: + return readUInt40LE(this, offset); + case 6: + return readUInt48LE(this, offset); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; Buffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE( offset: number, - byteLength: number) { + byteLength: number +) { if (offset === undefined) { - throw new ERR_INVALID_ARG_TYPE("offset", "number", offset); + throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); } switch (byteLength) { - case 1: return this.readUInt8(offset); - case 2: return this.readUInt16BE(offset); - case 3: return readUInt24BE(this, offset); - case 4: return this.readUInt32BE(offset); - case 5: return readUInt40BE(this, offset); - case 6: return readUInt48BE(this, offset); + case 1: + return this.readUInt8(offset); + case 2: + return this.readUInt16BE(offset); + case 3: + return readUInt24BE(this, offset); + case 4: + return this.readUInt32BE(offset); + case 5: + return readUInt40BE(this, offset); + case 6: + return readUInt48BE(this, offset); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; Buffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8( - offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + offset: number = 0 +) { + validateOffset(offset, 'offset', 0, this.length); const val = this[offset]; if (val === undefined) { boundsError(offset, this.length - 1); @@ -1000,121 +1194,143 @@ Buffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8( Buffer.prototype.readUint16BE = Buffer.prototype.readUInt16BE = readUInt16BE; -Buffer.prototype.readUint16LE = - Buffer.prototype.readUInt16LE = - function readUInt16LE(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); - const first = this[offset]; - const last = this[offset + 1]; - if (first === undefined || last === undefined) { - boundsError(offset, this.length - 2); - } +Buffer.prototype.readUint16LE = Buffer.prototype.readUInt16LE = + function readUInt16LE(offset: number = 0) { + validateOffset(offset, 'offset', 0, this.length); + const first = this[offset]; + const last = this[offset + 1]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 2); + } - return first + last * 2 ** 8; - }; - -Buffer.prototype.readUint32LE = - Buffer.prototype.readUInt32LE = - function readUInt32LE(this: Buffer, offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); - const first = this[offset]; - const last = this[offset + 3]; - if (first === undefined || last === undefined) { - boundsError(offset, this.length - 4); - } + return first + last * 2 ** 8; + }; - return first + - this[++offset]! * 2 ** 8 + - this[++offset]! * 2 ** 16 + - last * 2 ** 24; - }; +Buffer.prototype.readUint32LE = Buffer.prototype.readUInt32LE = + function readUInt32LE(this: Buffer, offset: number = 0) { + validateOffset(offset, 'offset', 0, this.length); + const first = this[offset]; + const last = this[offset + 3]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 4); + } + + return ( + first + + this[++offset]! * 2 ** 8 + + this[++offset]! * 2 ** 16 + + last * 2 ** 24 + ); + }; Buffer.prototype.readUint32BE = Buffer.prototype.readUInt32BE = readUInt32BE; -Buffer.prototype.readBigUint64LE = - Buffer.prototype.readBigUInt64LE = - function readBigUInt64LE(this: Buffer, offset: number = 0) { - offset = offset >>> 0; - validateOffset(offset, "offset", 0, this.length); - const first = this[offset]; - const last = this[offset + 7]; - if (first === undefined || last === undefined) { - boundsError(offset, this.length - 8); - } - const lo = first + this[++offset]! * 2 ** 8 + - this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 24; - const hi = this[++offset]! + this[++offset]! * 2 ** 8 + - this[++offset]! * 2 ** 16 + last * 2 ** 24; - return BigInt(lo) + (BigInt(hi) << BigInt(32)); - }; - -Buffer.prototype.readBigUint64BE = - Buffer.prototype.readBigUInt64BE = - function readBigUInt64BE(this: Buffer, offset: number = 0) { - offset = offset >>> 0; - validateOffset(offset, "offset", 0, this.length); - const first = this[offset]; - const last = this[offset + 7]; - if (first === undefined || last === undefined) { - boundsError(offset, this.length - 8); - } - const hi = first * 2 ** 24 + this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 8 + this[++offset]!; - const lo = this[++offset]! * 2 ** 24 + this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 8 + last; - return (BigInt(hi) << BigInt(32)) + BigInt(lo); - }; +Buffer.prototype.readBigUint64LE = Buffer.prototype.readBigUInt64LE = + function readBigUInt64LE(this: Buffer, offset: number = 0) { + offset = offset >>> 0; + validateOffset(offset, 'offset', 0, this.length); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const lo = + first + + this[++offset]! * 2 ** 8 + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 24; + const hi = + this[++offset]! + + this[++offset]! * 2 ** 8 + + this[++offset]! * 2 ** 16 + + last * 2 ** 24; + return BigInt(lo) + (BigInt(hi) << BigInt(32)); + }; + +Buffer.prototype.readBigUint64BE = Buffer.prototype.readBigUInt64BE = + function readBigUInt64BE(this: Buffer, offset: number = 0) { + offset = offset >>> 0; + validateOffset(offset, 'offset', 0, this.length); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const hi = + first * 2 ** 24 + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 8 + + this[++offset]!; + const lo = + this[++offset]! * 2 ** 24 + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 8 + + last; + return (BigInt(hi) << BigInt(32)) + BigInt(lo); + }; Buffer.prototype.readIntLE = function readIntLE( offset: number, - byteLength: number, + byteLength: number ) { if (offset === undefined) { - throw new ERR_INVALID_ARG_TYPE("offset", "number", offset); + throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); } switch (byteLength) { - case 1: return this.readInt8(offset); - case 2: return this.readInt16LE(offset); - case 3: return readInt24LE(this, offset); - case 4: return this.readInt32LE(offset); - case 5: return readInt40LE(this, offset); - case 6: return readInt48LE(this, offset); + case 1: + return this.readInt8(offset); + case 2: + return this.readInt16LE(offset); + case 3: + return readInt24LE(this, offset); + case 4: + return this.readInt32LE(offset); + case 5: + return readInt40LE(this, offset); + case 6: + return readInt48LE(this, offset); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; Buffer.prototype.readIntBE = function readIntBE( - offset: number, - byteLength: number) { + offset: number, + byteLength: number +) { if (offset === undefined) { - throw new ERR_INVALID_ARG_TYPE("offset", "number", offset); + throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); } switch (byteLength) { - case 1: return this.readInt8(offset); - case 2: return this.readInt16BE(offset); - case 3: return readInt24BE(this, offset); - case 4: return this.readInt32BE(offset); - case 5: return readInt40BE(this, offset); - case 6: return readInt48BE(this, offset); + case 1: + return this.readInt8(offset); + case 2: + return this.readInt16BE(offset); + case 3: + return readInt24BE(this, offset); + case 4: + return this.readInt32BE(offset); + case 5: + return readInt40BE(this, offset); + case 6: + return readInt48BE(this, offset); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; Buffer.prototype.readInt8 = function readInt8(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const val = this[offset]; if (val === undefined) { boundsError(offset, this.length - 1); } - return val | (val & 2 ** 7) * 0x1fffffe; + return val | ((val & (2 ** 7)) * 0x1fffffe); }; Buffer.prototype.readInt16LE = function readInt16LE(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) { @@ -1122,11 +1338,11 @@ Buffer.prototype.readInt16LE = function readInt16LE(offset: number = 0) { } const val = first + last * 2 ** 8; - return val | (val & 2 ** 15) * 0x1fffe; + return val | ((val & (2 ** 15)) * 0x1fffe); }; Buffer.prototype.readInt16BE = function readInt16BE(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) { @@ -1134,69 +1350,90 @@ Buffer.prototype.readInt16BE = function readInt16BE(offset: number = 0) { } const val = first * 2 ** 8 + last; - return val | (val & 2 ** 15) * 0x1fffe; + return val | ((val & (2 ** 15)) * 0x1fffe); }; Buffer.prototype.readInt32LE = function readInt32LE(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) { boundsError(offset, this.length - 4); } - return first + - this[++offset] * 2 ** 8 + - this[++offset] * 2 ** 16 + - (last << 24); // Overflow + return ( + first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + (last << 24) + ); // Overflow }; Buffer.prototype.readInt32BE = function readInt32BE(offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) { boundsError(offset, this.length - 4); } - return (first << 24) + // Overflow + return ( + (first << 24) + // Overflow this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + - last; + last + ); }; -Buffer.prototype.readBigInt64LE = function readBigInt64LE(this: Buffer, offset: number = 0) { +Buffer.prototype.readBigInt64LE = function readBigInt64LE( + this: Buffer, + offset: number = 0 +) { offset = offset >>> 0; - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) { boundsError(offset, this.length - 8); } - const val = this[offset + 4]! + this[offset + 5]! * 2 ** 8 + - this[offset + 6]! * 2 ** 16 + (last << 24); - return (BigInt(val) << BigInt(32)) + + const val = + this[offset + 4]! + + this[offset + 5]! * 2 ** 8 + + this[offset + 6]! * 2 ** 16 + + (last << 24); + return ( + (BigInt(val) << BigInt(32)) + BigInt( - first + this[++offset]! * 2 ** 8 + this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 24, - ); + first + + this[++offset]! * 2 ** 8 + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 24 + ) + ); }; -Buffer.prototype.readBigInt64BE = function readBigInt64BE(this: Buffer, offset: number = 0) { +Buffer.prototype.readBigInt64BE = function readBigInt64BE( + this: Buffer, + offset: number = 0 +) { offset = offset >>> 0; - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) { boundsError(offset, this.length - 8); } - const val = (first << 24) + this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 8 + this[++offset]!; - return (BigInt(val) << BigInt(32)) + + const val = + (first << 24) + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 8 + + this[++offset]!; + return ( + (BigInt(val) << BigInt(32)) + BigInt( - this[++offset]! * 2 ** 24 + this[++offset]! * 2 ** 16 + - this[++offset]! * 2 ** 8 + last, - ); + this[++offset]! * 2 ** 24 + + this[++offset]! * 2 ** 16 + + this[++offset]! * 2 ** 8 + + last + ) + ); }; Buffer.prototype.readFloatLE = function readFloatLE(offset: number = 0) { @@ -1223,73 +1460,80 @@ Buffer.prototype.readDoubleBE = function readDoubleBE(offset: number = 0) { : readDoubleBackwards(this, offset); }; -Buffer.prototype.writeUintLE = - Buffer.prototype.writeUIntLE = - function writeUIntLE(value: number, offset: number, byteLength: number) { - switch (byteLength) { - case 1: return writeU_Int8(this, value, offset, 0, 0xff); - case 2: return writeU_Int16LE(this, value, offset, 0, 0xffff); - case 3: return writeU_Int24LE(this, value, offset, 0, 0xffffff); - case 4: return writeU_Int32LE(this, value, offset, 0, 0xffffffff); - case 5: return writeU_Int40LE(this, value, offset, 0, 0xffffffffff); - case 6: return writeU_Int48LE(this, value, offset, 0, 0xffffffffffff); - default: - boundsError(byteLength, 6, "byteLength"); - } - }; - -Buffer.prototype.writeUintBE = - Buffer.prototype.writeUIntBE = - function writeUIntBE(value: number, offset: number, byteLength: number) { - switch (byteLength) { - case 1: return writeU_Int8(this, value, offset, 0, 0xff); - case 2: return writeU_Int16BE(this, value, offset, 0, 0xffff); - case 3: return writeU_Int24BE(this, value, offset, 0, 0xffffff); - case 4: return writeU_Int32BE(this, value, offset, 0, 0xffffffff); - case 5: return writeU_Int40BE(this, value, offset, 0, 0xffffffffff); - case 6: return writeU_Int48BE(this, value, offset, 0, 0xffffffffffff); - default: - boundsError(byteLength, 6, "byteLength"); - } - }; +Buffer.prototype.writeUintLE = Buffer.prototype.writeUIntLE = + function writeUIntLE(value: number, offset: number, byteLength: number) { + switch (byteLength) { + case 1: + return writeU_Int8(this, value, offset, 0, 0xff); + case 2: + return writeU_Int16LE(this, value, offset, 0, 0xffff); + case 3: + return writeU_Int24LE(this, value, offset, 0, 0xffffff); + case 4: + return writeU_Int32LE(this, value, offset, 0, 0xffffffff); + case 5: + return writeU_Int40LE(this, value, offset, 0, 0xffffffffff); + case 6: + return writeU_Int48LE(this, value, offset, 0, 0xffffffffffff); + default: + boundsError(byteLength, 6, 'byteLength'); + } + }; + +Buffer.prototype.writeUintBE = Buffer.prototype.writeUIntBE = + function writeUIntBE(value: number, offset: number, byteLength: number) { + switch (byteLength) { + case 1: + return writeU_Int8(this, value, offset, 0, 0xff); + case 2: + return writeU_Int16BE(this, value, offset, 0, 0xffff); + case 3: + return writeU_Int24BE(this, value, offset, 0, 0xffffff); + case 4: + return writeU_Int32BE(this, value, offset, 0, 0xffffffff); + case 5: + return writeU_Int40BE(this, value, offset, 0, 0xffffffffff); + case 6: + return writeU_Int48BE(this, value, offset, 0, 0xffffffffffff); + default: + boundsError(byteLength, 6, 'byteLength'); + } + }; Buffer.prototype.writeUint8 = Buffer.prototype.writeUInt8 = function writeUInt8( value: number, - offset: number = 0, + offset: number = 0 ) { return writeU_Int8(this, value, offset, 0, 0xff); }; -Buffer.prototype.writeUint16LE = - Buffer.prototype.writeUInt16LE = - function writeUInt16LE(value: number, offset: number = 0) { - return writeU_Int16LE(this, value, offset, 0, 0xffff); - }; - -Buffer.prototype.writeUint16BE = - Buffer.prototype.writeUInt16BE = - function writeUInt16BE(value: number, offset: number = 0) { - return writeU_Int16BE(this, value, offset, 0, 0xffff); - }; - -Buffer.prototype.writeUint32LE = - Buffer.prototype.writeUInt32LE = - function writeUInt32LE(value: number, offset: number = 0) { - return _writeUInt32LE(this, value, offset, 0, 0xffffffff); - }; - -Buffer.prototype.writeUint32BE = - Buffer.prototype.writeUInt32BE = - function writeUInt32BE(value: number, offset: number = 0) { - return _writeUInt32BE(this, value, offset, 0, 0xffffffff); - }; +Buffer.prototype.writeUint16LE = Buffer.prototype.writeUInt16LE = + function writeUInt16LE(value: number, offset: number = 0) { + return writeU_Int16LE(this, value, offset, 0, 0xffff); + }; + +Buffer.prototype.writeUint16BE = Buffer.prototype.writeUInt16BE = + function writeUInt16BE(value: number, offset: number = 0) { + return writeU_Int16BE(this, value, offset, 0, 0xffff); + }; + +Buffer.prototype.writeUint32LE = Buffer.prototype.writeUInt32LE = + function writeUInt32LE(value: number, offset: number = 0) { + return _writeUInt32LE(this, value, offset, 0, 0xffffffff); + }; + +Buffer.prototype.writeUint32BE = Buffer.prototype.writeUInt32BE = + function writeUInt32BE(value: number, offset: number = 0) { + return _writeUInt32BE(this, value, offset, 0, 0xffffffff); + }; function wrtBigUInt64LE( - buf: Buffer, - value: bigint, - offset: number, - min: bigint, - max: bigint) { + buf: Buffer, + value: bigint, + offset: number, + min: bigint, + max: bigint +) { checkIntBI(value, min, max, buf, offset, 7); let lo = Number(value & BigInt(4294967295)); buf[offset++] = lo; @@ -1299,7 +1543,7 @@ function wrtBigUInt64LE( buf[offset++] = lo; lo = lo >> 8; buf[offset++] = lo; - let hi = Number(value >> BigInt(32) & BigInt(4294967295)); + let hi = Number((value >> BigInt(32)) & BigInt(4294967295)); buf[offset++] = hi; hi = hi >> 8; buf[offset++] = hi; @@ -1311,11 +1555,12 @@ function wrtBigUInt64LE( } function wrtBigUInt64BE( - buf: Buffer, - value: bigint, - offset: number, - min: bigint, - max: bigint) { + buf: Buffer, + value: bigint, + offset: number, + min: bigint, + max: bigint +) { checkIntBI(value, min, max, buf, offset, 7); let lo = Number(value & BigInt(4294967295)); buf[offset + 7] = lo; @@ -1325,7 +1570,7 @@ function wrtBigUInt64BE( buf[offset + 5] = lo; lo = lo >> 8; buf[offset + 4] = lo; - let hi = Number(value >> BigInt(32) & BigInt(4294967295)); + let hi = Number((value >> BigInt(32)) & BigInt(4294967295)); buf[offset + 3] = hi; hi = hi >> 8; buf[offset + 2] = hi; @@ -1336,86 +1581,140 @@ function wrtBigUInt64BE( return offset + 8; } -Buffer.prototype.writeBigUint64LE = - Buffer.prototype.writeBigUInt64LE = - function writeBigUInt64LE(this: Buffer, value: bigint, offset: number = 0) { - return wrtBigUInt64LE(this, value, offset, 0n, 0xffffffffffffffffn); - }; +Buffer.prototype.writeBigUint64LE = Buffer.prototype.writeBigUInt64LE = + function writeBigUInt64LE(this: Buffer, value: bigint, offset: number = 0) { + return wrtBigUInt64LE(this, value, offset, 0n, 0xffffffffffffffffn); + }; -Buffer.prototype.writeBigUint64BE = - Buffer.prototype.writeBigUInt64BE = - function writeBigUInt64BE(this: Buffer, value: bigint, offset: number = 0) { - return wrtBigUInt64BE(this, value, offset, 0n, 0xffffffffffffffffn); - }; +Buffer.prototype.writeBigUint64BE = Buffer.prototype.writeBigUInt64BE = + function writeBigUInt64BE(this: Buffer, value: bigint, offset: number = 0) { + return wrtBigUInt64BE(this, value, offset, 0n, 0xffffffffffffffffn); + }; Buffer.prototype.writeIntLE = function writeIntLE( - value: number, - offset: number, - byteLength: number) { - switch(byteLength) { - case 1: return writeU_Int8(this, value, offset, -0x80, 0x7f); - case 2: return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff); - case 3: return writeU_Int24LE(this, value, offset, -0x800000, 0x7fffff); - case 4: return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff); - case 5: return writeU_Int40LE(this, value, offset, -0x8000000000, 0x7fffffffff); - case 6: return writeU_Int48LE(this, value, offset, -0x800000000000, 0x7fffffffffff); + value: number, + offset: number, + byteLength: number +) { + switch (byteLength) { + case 1: + return writeU_Int8(this, value, offset, -0x80, 0x7f); + case 2: + return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff); + case 3: + return writeU_Int24LE(this, value, offset, -0x800000, 0x7fffff); + case 4: + return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff); + case 5: + return writeU_Int40LE(this, value, offset, -0x8000000000, 0x7fffffffff); + case 6: + return writeU_Int48LE( + this, + value, + offset, + -0x800000000000, + 0x7fffffffffff + ); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; Buffer.prototype.writeIntBE = function writeIntBE( - value: number, - offset: number, - byteLength: number) { - switch(byteLength) { - case 1: return writeU_Int8(this, value, offset, -0x80, 0x7f); - case 2: return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff); - case 3: return writeU_Int24BE(this, value, offset, -0x800000, 0x7fffff); - case 4: return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff); - case 5: return writeU_Int40BE(this, value, offset, -0x8000000000, 0x7fffffffff); - case 6: return writeU_Int48BE(this, value, offset, -0x800000000000, 0x7fffffffffff); + value: number, + offset: number, + byteLength: number +) { + switch (byteLength) { + case 1: + return writeU_Int8(this, value, offset, -0x80, 0x7f); + case 2: + return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff); + case 3: + return writeU_Int24BE(this, value, offset, -0x800000, 0x7fffff); + case 4: + return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff); + case 5: + return writeU_Int40BE(this, value, offset, -0x8000000000, 0x7fffffffff); + case 6: + return writeU_Int48BE( + this, + value, + offset, + -0x800000000000, + 0x7fffffffffff + ); default: - boundsError(byteLength, 6, "byteLength"); + boundsError(byteLength, 6, 'byteLength'); } }; -Buffer.prototype.writeInt8 = function writeInt8(value: number, offset: number = 0) { +Buffer.prototype.writeInt8 = function writeInt8( + value: number, + offset: number = 0 +) { return writeU_Int8(this, value, offset, -0x80, 0x7f); }; -Buffer.prototype.writeInt16LE = function writeInt16LE(value: number, offset: number = 0) { +Buffer.prototype.writeInt16LE = function writeInt16LE( + value: number, + offset: number = 0 +) { return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff); }; Buffer.prototype.writeInt16BE = function writeInt16BE( value: number, - offset: number = 0, + offset: number = 0 ) { return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff); }; -Buffer.prototype.writeInt32LE = function writeInt32LE(value: number, offset: number = 0) { +Buffer.prototype.writeInt32LE = function writeInt32LE( + value: number, + offset: number = 0 +) { return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff); }; -Buffer.prototype.writeInt32BE = function writeInt32BE(value: number, offset: number = 0) { +Buffer.prototype.writeInt32BE = function writeInt32BE( + value: number, + offset: number = 0 +) { return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff); }; -Buffer.prototype.writeBigInt64LE = - function writeBigInt64LE(this: Buffer, value: bigint, offset: number = 0) { - return wrtBigUInt64LE(this, value, offset, -0x8000000000000000n, 0x7fffffffffffffffn); - }; +Buffer.prototype.writeBigInt64LE = function writeBigInt64LE( + this: Buffer, + value: bigint, + offset: number = 0 +) { + return wrtBigUInt64LE( + this, + value, + offset, + -0x8000000000000000n, + 0x7fffffffffffffffn + ); +}; -Buffer.prototype.writeBigInt64BE = - function writeBigInt64BE(this: Buffer, value: bigint, offset: number = 0) { - return wrtBigUInt64BE(this, value, offset, -0x8000000000000000n, 0x7fffffffffffffffn); - }; +Buffer.prototype.writeBigInt64BE = function writeBigInt64BE( + this: Buffer, + value: bigint, + offset: number = 0 +) { + return wrtBigUInt64BE( + this, + value, + offset, + -0x8000000000000000n, + 0x7fffffffffffffffn + ); +}; Buffer.prototype.writeFloatLE = function writeFloatLE( value: number, - offset: number, + offset: number ) { return bigEndian ? writeFloatBackwards(this, value, offset) @@ -1424,7 +1723,7 @@ Buffer.prototype.writeFloatLE = function writeFloatLE( Buffer.prototype.writeFloatBE = function writeFloatBE( value: number, - offset: number, + offset: number ) { return bigEndian ? writeFloatForwards(this, value, offset) @@ -1433,7 +1732,7 @@ Buffer.prototype.writeFloatBE = function writeFloatBE( Buffer.prototype.writeDoubleLE = function writeDoubleLE( value: number, - offset: number, + offset: number ) { return bigEndian ? writeDoubleBackwards(this, value, offset) @@ -1442,7 +1741,7 @@ Buffer.prototype.writeDoubleLE = function writeDoubleLE( Buffer.prototype.writeDoubleBE = function writeDoubleBE( value: number, - offset: number, + offset: number ) { return bigEndian ? writeDoubleForwards(this, value, offset) @@ -1450,42 +1749,45 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE( }; Buffer.prototype.copy = function copy( - target: Buffer|Uint8Array, + target: Buffer | Uint8Array, targetStart?: number, sourceStart?: number, - sourceEnd?: number, + sourceEnd?: number ) { if (!isUint8Array(target)) { - throw new ERR_INVALID_ARG_TYPE("target", ["Buffer", "Uint8Array"], target); + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); } targetStart = toInteger(targetStart, 0); if ((targetStart as number) < 0) { - throw new ERR_OUT_OF_RANGE("targetStart", ">= 0", targetStart); + throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart); } sourceStart = toInteger(sourceStart, 0); if ((sourceStart as number) < 0) { - throw new ERR_OUT_OF_RANGE("sourceStart", ">= 0", sourceStart); + throw new ERR_OUT_OF_RANGE('sourceStart', '>= 0', sourceStart); } if ((sourceStart as number) >= MAX_UINT32) { - throw new ERR_OUT_OF_RANGE("sourceStart", `< ${MAX_UINT32}`, sourceStart); + throw new ERR_OUT_OF_RANGE('sourceStart', `< ${MAX_UINT32}`, sourceStart); } sourceEnd ??= this.length; sourceEnd = toInteger(sourceEnd, 0); if ((sourceEnd as number) < 0) { - throw new ERR_OUT_OF_RANGE("sourceEnd", ">= 0", sourceEnd); + throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd); } if ((sourceEnd as number) >= MAX_UINT32) { - throw new ERR_OUT_OF_RANGE("sourceEnd", `< ${MAX_UINT32}`, sourceEnd); + throw new ERR_OUT_OF_RANGE('sourceEnd', `< ${MAX_UINT32}`, sourceEnd); } if ((targetStart as number) >= target.length) { return 0; } - if ((sourceEnd as number) > 0 && (sourceEnd as number) < (sourceStart as number)) { + if ( + (sourceEnd as number) > 0 && + (sourceEnd as number) < (sourceStart as number) + ) { sourceEnd = sourceStart; } if (sourceEnd === sourceStart) { @@ -1499,13 +1801,21 @@ Buffer.prototype.copy = function copy( sourceEnd = this.length; } - if (target.length - (targetStart as number) < (sourceEnd as number) - (sourceStart as number)) { - sourceEnd = target.length - (targetStart as number) + (sourceStart as number); + if ( + target.length - (targetStart as number) < + (sourceEnd as number) - (sourceStart as number) + ) { + sourceEnd = + target.length - (targetStart as number) + (sourceStart as number); } const len = (sourceEnd as number) - (sourceStart as number); if (this === target) { - this.copyWithin(targetStart as number, sourceStart as number, sourceEnd as number); + this.copyWithin( + targetStart as number, + sourceStart as number, + sourceEnd as number + ); } else { const sub = this.subarray(sourceStart, sourceEnd); target.set(sub, targetStart); @@ -1515,17 +1825,18 @@ Buffer.prototype.copy = function copy( }; Buffer.prototype.fill = function fill( - val: string|number|Buffer|Uint8Array, - start?: number|string, - end?: number, - encoding?: string) { + val: string | number | Buffer | Uint8Array, + start?: number | string, + end?: number, + encoding?: string +) { let normalizedEncoding: Encoding | undefined; - if (typeof val === "string") { - if (typeof start === "string") { + if (typeof val === 'string') { + if (typeof start === 'string') { encoding = start; start = 0; end = this.length; - } else if (typeof end === "string") { + } else if (typeof end === 'string') { encoding = end; end = this.length; } @@ -1535,7 +1846,7 @@ Buffer.prototype.fill = function fill( } if (val.length === 1) { const code = val.charCodeAt(0); - if (encoding === "utf8" && code < 128 || encoding === "latin1") { + if ((encoding === 'utf8' && code < 128) || encoding === 'latin1') { val = code; } } @@ -1551,7 +1862,11 @@ Buffer.prototype.fill = function fill( if ((end as number) < 0 || (end as number) > this.length) { throw new ERR_OUT_OF_RANGE('end', `0 to ${this.length}`, end); } - if ((start as number) < 0 || this.length < (start as number) || this.length < (end as number)) { + if ( + (start as number) < 0 || + this.length < (start as number) || + this.length < (end as number) + ) { throw new ERR_OUT_OF_RANGE('start', '0 to end', start); } if ((end as number) <= (start as number)) { @@ -1560,12 +1875,14 @@ Buffer.prototype.fill = function fill( start = (start as number) >>> 0; end = end === void 0 ? this.length : end >>> 0; - if (typeof val === "string") { - bufferUtil.fillImpl(this, - val as string, - start as number, - end as number, - normalizedEncoding); + if (typeof val === 'string') { + bufferUtil.fillImpl( + this, + val as string, + start as number, + end as number, + normalizedEncoding + ); return this; } @@ -1573,13 +1890,18 @@ Buffer.prototype.fill = function fill( if ((val as ArrayBufferView).byteLength === 0) { throw new ERR_INVALID_ARG_VALUE('value', 'zero-length'); } - bufferUtil.fillImpl(this, val as ArrayBufferView, start as number, end as number); + bufferUtil.fillImpl( + this, + val as ArrayBufferView, + start as number, + end as number + ); return this; } - if (typeof val === "number") { + if (typeof val === 'number') { val = val & 255; - } else if (typeof val === "boolean") { + } else if (typeof val === 'boolean') { val = Number(val); } val ??= 0; @@ -1589,25 +1911,23 @@ Buffer.prototype.fill = function fill( return this; }; -function checkBounds( - buf: Buffer, - offset: number, - byteLength2: number) { - validateOffset(offset, "offset", 0, buf.length); +function checkBounds(buf: Buffer, offset: number, byteLength2: number) { + validateOffset(offset, 'offset', 0, buf.length); if (buf[offset] === undefined || buf[offset + byteLength2] === undefined) { boundsError(offset, buf.length - (byteLength2 + 1)); } } function checkIntBI( - value: bigint|number, - min: bigint|number, - max: bigint|number, - buf: Buffer, - offset: number, - byteLength2: number) { + value: bigint | number, + min: bigint | number, + max: bigint | number, + buf: Buffer, + offset: number, + byteLength2: number +) { if (value > max || value < min) { - const n = typeof min === "bigint" ? "n" : ""; + const n = typeof min === 'bigint' ? 'n' : ''; let range; if (byteLength2 > 3) { if (min === 0 || min === BigInt(0)) { @@ -1620,49 +1940,57 @@ function checkIntBI( } else { range = `>= ${min}${n} and <= ${max}${n}`; } - throw new ERR_OUT_OF_RANGE("value", range, value); + throw new ERR_OUT_OF_RANGE('value', range, value); } checkBounds(buf, offset, byteLength2); } function isInstance(obj: unknown, type: Function) { - return obj instanceof type || - obj != null && obj.constructor != null && - obj.constructor.name != null && obj.constructor.name === type.name; + return ( + obj instanceof type || + (obj != null && + obj.constructor != null && + obj.constructor.name != null && + obj.constructor.name === type.name) + ); } -function readUInt48LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt48LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 6); } - return first + + return ( + first + buf[++offset]! * 2 ** 8 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 24 + - (buf[++offset]! + last * 2 ** 8) * 2 ** 32; + (buf[++offset]! + last * 2 ** 8) * 2 ** 32 + ); } -function readUInt40LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt40LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 5); } - return first + + return ( + first + buf[++offset]! * 2 ** 8 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 24 + - last * 2 ** 32; + last * 2 ** 32 + ); } -function readUInt24LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt24LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) { @@ -1672,38 +2000,42 @@ function readUInt24LE(buf: Buffer|Uint8Array, offset: number = 0) { return first + buf[++offset]! * 2 ** 8 + last * 2 ** 16; } -function readUInt48BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt48BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 6); } - return (first * 2 ** 8 + buf[++offset]!) * 2 ** 32 + + return ( + (first * 2 ** 8 + buf[++offset]!) * 2 ** 32 + buf[++offset]! * 2 ** 24 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 8 + - last; + last + ); } -function readUInt40BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt40BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 5); } - return first * 2 ** 32 + + return ( + first * 2 ** 32 + buf[++offset]! * 2 ** 24 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 8 + - last; + last + ); } -function readUInt24BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readUInt24BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) { @@ -1714,7 +2046,7 @@ function readUInt24BE(buf: Buffer|Uint8Array, offset: number = 0) { } function readUInt16BE(this: Buffer, offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) { @@ -1725,21 +2057,23 @@ function readUInt16BE(this: Buffer, offset: number = 0) { } function readUInt32BE(this: Buffer, offset: number = 0) { - validateOffset(offset, "offset", 0, this.length); + validateOffset(offset, 'offset', 0, this.length); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) { boundsError(offset, this.length - 4); } - return first * 2 ** 24 + + return ( + first * 2 ** 24 + this[++offset]! * 2 ** 16 + this[++offset]! * 2 ** 8 + - last; + last + ); } -function readDoubleBackwards(buffer: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buffer.length); +function readDoubleBackwards(buffer: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buffer.length); const first = buffer[offset]; const last = buffer[offset + 7]; if (first === undefined || last === undefined) { @@ -1757,8 +2091,8 @@ function readDoubleBackwards(buffer: Buffer|Uint8Array, offset: number = 0) { return float64Array[0]; } -function readDoubleForwards(buffer: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buffer.length); +function readDoubleForwards(buffer: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buffer.length); const first = buffer[offset]; const last = buffer[offset + 7]; if (first === undefined || last === undefined) { @@ -1776,7 +2110,11 @@ function readDoubleForwards(buffer: Buffer|Uint8Array, offset: number = 0) { return float64Array[0]; } -function writeDoubleForwards(buffer: Buffer|Uint8Array, val: number, offset: number = 0) { +function writeDoubleForwards( + buffer: Buffer | Uint8Array, + val: number, + offset: number = 0 +) { val = +val; checkBounds(buffer as any, offset, 7); @@ -1792,7 +2130,11 @@ function writeDoubleForwards(buffer: Buffer|Uint8Array, val: number, offset: num return offset; } -function writeDoubleBackwards(buffer: Buffer|Uint8Array, val: number, offset: number = 0) { +function writeDoubleBackwards( + buffer: Buffer | Uint8Array, + val: number, + offset: number = 0 +) { val = +val; checkBounds(buffer as any, offset, 7); @@ -1808,8 +2150,8 @@ function writeDoubleBackwards(buffer: Buffer|Uint8Array, val: number, offset: nu return offset; } -function readFloatBackwards(buffer: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buffer.length); +function readFloatBackwards(buffer: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buffer.length); const first = buffer[offset]; const last = buffer[offset + 3]; if (first === undefined || last === undefined) { @@ -1823,8 +2165,8 @@ function readFloatBackwards(buffer: Buffer|Uint8Array, offset: number = 0) { return float32Array[0]; } -function readFloatForwards(buffer: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buffer.length); +function readFloatForwards(buffer: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buffer.length); const first = buffer[offset]; const last = buffer[offset + 3]; if (first === undefined || last === undefined) { @@ -1838,7 +2180,11 @@ function readFloatForwards(buffer: Buffer|Uint8Array, offset: number = 0) { return float32Array[0]; } -function writeFloatForwards(buffer: Buffer|Uint8Array, val: number, offset: number = 0) { +function writeFloatForwards( + buffer: Buffer | Uint8Array, + val: number, + offset: number = 0 +) { val = +val; checkBounds(buffer as any, offset, 3); @@ -1850,7 +2196,11 @@ function writeFloatForwards(buffer: Buffer|Uint8Array, val: number, offset: numb return offset; } -function writeFloatBackwards(buffer: Buffer|Uint8Array, val: number, offset: number = 0) { +function writeFloatBackwards( + buffer: Buffer | Uint8Array, + val: number, + offset: number = 0 +) { val = +val; checkBounds(buffer as any, offset, 3); @@ -1862,8 +2212,8 @@ function writeFloatBackwards(buffer: Buffer|Uint8Array, val: number, offset: num return offset; } -function readInt24LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt24LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) { @@ -1871,26 +2221,28 @@ function readInt24LE(buf: Buffer|Uint8Array, offset: number = 0) { } const val = first + buf[++offset]! * 2 ** 8 + last * 2 ** 16; - return val | (val & 2 ** 23) * 0x1fe; + return val | ((val & (2 ** 23)) * 0x1fe); } -function readInt40LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt40LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 5); } - return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 + + return ( + (last | ((last & (2 ** 7)) * 0x1fffffe)) * 2 ** 32 + first + buf[++offset]! * 2 ** 8 + buf[++offset]! * 2 ** 16 + - buf[++offset]! * 2 ** 24; + buf[++offset]! * 2 ** 24 + ); } -function readInt48LE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt48LE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) { @@ -1898,15 +2250,17 @@ function readInt48LE(buf: Buffer|Uint8Array, offset: number = 0) { } const val = buf[offset + 4]! + last * 2 ** 8; - return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 + + return ( + (val | ((val & (2 ** 15)) * 0x1fffe)) * 2 ** 32 + first + buf[++offset]! * 2 ** 8 + buf[++offset]! * 2 ** 16 + - buf[++offset]! * 2 ** 24; + buf[++offset]! * 2 ** 24 + ); } -function readInt24BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt24BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) { @@ -1914,11 +2268,11 @@ function readInt24BE(buf: Buffer|Uint8Array, offset: number = 0) { } const val = first * 2 ** 16 + buf[++offset]! * 2 ** 8 + last; - return val | (val & 2 ** 23) * 0x1fe; + return val | ((val & (2 ** 23)) * 0x1fe); } -function readInt48BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt48BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) { @@ -1926,31 +2280,35 @@ function readInt48BE(buf: Buffer|Uint8Array, offset: number = 0) { } const val = buf[++offset]! + first * 2 ** 8; - return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 + + return ( + (val | ((val & (2 ** 15)) * 0x1fffe)) * 2 ** 32 + buf[++offset]! * 2 ** 24 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 8 + - last; + last + ); } -function readInt40BE(buf: Buffer|Uint8Array, offset: number = 0) { - validateOffset(offset, "offset", 0, buf.length); +function readInt40BE(buf: Buffer | Uint8Array, offset: number = 0) { + validateOffset(offset, 'offset', 0, buf.length); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) { boundsError(offset, buf.length - 5); } - return (first | (first & 2 ** 7) * 0x1fffffe) * 2 ** 32 + + return ( + (first | ((first & (2 ** 7)) * 0x1fffffe)) * 2 ** 32 + buf[++offset]! * 2 ** 24 + buf[++offset]! * 2 ** 16 + buf[++offset]! * 2 ** 8 + - last; + last + ); } -function boundsError(value: number, length: number, type?: string) : never { +function boundsError(value: number, length: number, type?: string): never { if (Math.floor(value) !== value) { - throw new ERR_OUT_OF_RANGE(type || "offset", "an integer", value); + throw new ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value); } if (length < 0) { @@ -1958,44 +2316,46 @@ function boundsError(value: number, length: number, type?: string) : never { } throw new ERR_OUT_OF_RANGE( - type || "offset", + type || 'offset', `>= ${type ? 1 : 0} and <= ${length}`, - value, + value ); } function validateNumber(value: unknown, name: string) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } } function checkInt( - value: number|bigint, - min: number|bigint, - max: number|bigint, - buf: Buffer, - offset: number, - byteLength: number) { + value: number | bigint, + min: number | bigint, + max: number | bigint, + buf: Buffer, + offset: number, + byteLength: number +) { if (value > max || value < min) { - const n = typeof min === "bigint" ? "n" : ""; + const n = typeof min === 'bigint' ? 'n' : ''; let range; if (byteLength > 3) { if (min === 0 || min === 0n) { range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`; } else { - range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and ` + + range = + `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and ` + `< 2${n} ** ${(byteLength + 1) * 8 - 1}${n}`; } } else { range = `>= ${min}${n} and <= ${max}${n}`; } - throw new ERR_OUT_OF_RANGE("value", range, value); + throw new ERR_OUT_OF_RANGE('value', range, value); } checkBounds(buf, offset, byteLength); } -function toInteger(n: number|undefined, defaultVal: number) { +function toInteger(n: number | undefined, defaultVal: number) { if (n === undefined) n = 0; n = +(n as number); if ( @@ -2003,21 +2363,22 @@ function toInteger(n: number|undefined, defaultVal: number) { n >= Number.MIN_SAFE_INTEGER && n <= Number.MAX_SAFE_INTEGER ) { - return ((n % 1) === 0 ? n : Math.floor(n)); + return n % 1 === 0 ? n : Math.floor(n); } return defaultVal; } function writeU_Int8( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); if (value > max || value < min) { - throw new ERR_OUT_OF_RANGE("value", `>= ${min} and <= ${max}`, value); + throw new ERR_OUT_OF_RANGE('value', `>= ${min} and <= ${max}`, value); } if (buf[offset] === undefined) { boundsError(offset, buf.length - 1); @@ -2028,13 +2389,14 @@ function writeU_Int8( } function writeU_Int16BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 1); buf[offset++] = value >>> 8; @@ -2043,13 +2405,14 @@ function writeU_Int16BE( } function _writeUInt32LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 3); buf[offset++] = value; @@ -2063,13 +2426,14 @@ function _writeUInt32LE( } function writeU_Int16LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 1); buf[offset++] = value; @@ -2078,13 +2442,14 @@ function writeU_Int16LE( } function _writeUInt32BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 3); buf[offset + 3] = value; @@ -2098,13 +2463,14 @@ function _writeUInt32BE( } function writeU_Int48BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 5); const newVal = Math.floor(value * 2 ** -32); @@ -2121,13 +2487,14 @@ function writeU_Int48BE( } function writeU_Int40BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 4); buf[offset++] = Math.floor(value * 2 ** -32); @@ -2142,13 +2509,14 @@ function writeU_Int40BE( } function writeU_Int32BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 3); buf[offset + 3] = value; @@ -2162,13 +2530,14 @@ function writeU_Int32BE( } function writeU_Int24BE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 2); buf[offset + 2] = value; @@ -2183,13 +2552,13 @@ function validateOffset( value: number, name: string, min: number = 0, - max: number = Number.MAX_SAFE_INTEGER, + max: number = Number.MAX_SAFE_INTEGER ) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } if (!Number.isInteger(value)) { - throw new ERR_OUT_OF_RANGE(name, "an integer", value); + throw new ERR_OUT_OF_RANGE(name, 'an integer', value); } if (value < min || value > max) { throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value); @@ -2197,13 +2566,14 @@ function validateOffset( } function writeU_Int48LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 5); const newVal = Math.floor(value * 2 ** -32); @@ -2220,13 +2590,14 @@ function writeU_Int48LE( } function writeU_Int40LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 4); const newVal = value; @@ -2242,13 +2613,14 @@ function writeU_Int40LE( } function writeU_Int32LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 3); buf[offset++] = value; @@ -2262,13 +2634,14 @@ function writeU_Int32LE( } function writeU_Int24LE( - buf: Buffer, - value: number, - offset: number, - min: number, - max: number) { + buf: Buffer, + value: number, + offset: number, + min: number, + max: number +) { value = +value; - validateOffset(offset, "offset", 0, buf.length); + validateOffset(offset, 'offset', 0, buf.length); checkInt(value, min, max, buf, offset, 2); buf[offset++] = value; @@ -2281,19 +2654,27 @@ function writeU_Int24LE( export function isAscii(value: ArrayBufferView) { if ((value as any)?.detached || (value as any)?.buffer?.detached) { - throw new Error('Unable to determine if buffer is ASCII when it is detached'); + throw new Error( + 'Unable to determine if buffer is ASCII when it is detached' + ); } return bufferUtil.isAscii(value); } export function isUtf8(value: ArrayBufferView) { if ((value as any)?.detached || (value as any)?.buffer?.detached) { - throw new Error('Unable to determine if buffer is UTF8 when it is detached'); + throw new Error( + 'Unable to determine if buffer is UTF8 when it is detached' + ); } return bufferUtil.isUtf8(value); } -export function transcode(source: ArrayBufferView, fromEncoding: string, toEncoding: string) { +export function transcode( + source: ArrayBufferView, + fromEncoding: string, + toEncoding: string +) { if (!isArrayBufferView(source)) { throw new ERR_INVALID_ARG_TYPE('source', 'ArrayBufferView', typeof source); } @@ -2305,7 +2686,9 @@ export function transcode(source: ArrayBufferView, fromEncoding: string, toEncod if (normalizedToEncoding === undefined) { throw new ERR_UNKNOWN_ENCODING(toEncoding); } - return Buffer.from(bufferUtil.transcode(source, normalizedFromEncoding, normalizedToEncoding)); + return Buffer.from( + bufferUtil.transcode(source, normalizedFromEncoding, normalizedToEncoding) + ); } export default { diff --git a/src/node/internal/internal_comparisons.ts b/src/node/internal/internal_comparisons.ts index be01e9cb5c7..c4ea9b287d5 100644 --- a/src/node/internal/internal_comparisons.ts +++ b/src/node/internal/internal_comparisons.ts @@ -49,7 +49,7 @@ import { import { ONLY_ENUMERABLE, SKIP_SYMBOLS, - getOwnNonIndexProperties + getOwnNonIndexProperties, } from 'node-internal:internal_utils'; const kStrict = true; @@ -60,9 +60,9 @@ const kIsSet = 2; const kIsMap = 3; function areSimilarRegExps(a: RegExp, b: RegExp) { - return a.source === b.source && - a.flags === b.flags && - a.lastIndex === b.lastIndex; + return ( + a.source === b.source && a.flags === b.flags && a.lastIndex === b.lastIndex + ); } type FloatArray = Float32Array | Float64Array; @@ -90,55 +90,82 @@ function areSimilarTypedArrays(a: ArrayBufferView, b: ArrayBufferView) { if (a.byteLength !== b.byteLength) { return false; } - return compare(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), - new Uint8Array(b.buffer, b.byteOffset, b.byteLength)) === 0; + return ( + compare( + new Uint8Array(a.buffer, a.byteOffset, a.byteLength), + new Uint8Array(b.buffer, b.byteOffset, b.byteLength) + ) === 0 + ); } function areEqualArrayBuffers(buf1: AnyArrayBuffer, buf2: AnyArrayBuffer) { - return buf1.byteLength === buf2.byteLength && - compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0; + return ( + buf1.byteLength === buf2.byteLength && + compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0 + ); } function areEqualBoxedPrimitives(val1: unknown, val2: unknown) { if (isNumberObject(val1)) { - return isNumberObject(val2) && - Object.is(Number.prototype.valueOf.call(val1), - Number.prototype.valueOf.call(val2)); + return ( + isNumberObject(val2) && + Object.is( + Number.prototype.valueOf.call(val1), + Number.prototype.valueOf.call(val2) + ) + ); } if (isStringObject(val1)) { - return isStringObject(val2) && - String.prototype.valueOf.call(val1) === String.prototype.valueOf.call(val2); + return ( + isStringObject(val2) && + String.prototype.valueOf.call(val1) === + String.prototype.valueOf.call(val2) + ); } if (isBooleanObject(val1)) { - return isBooleanObject(val2) && - Boolean.prototype.valueOf.call(val1) === Boolean.prototype.valueOf.call(val2); + return ( + isBooleanObject(val2) && + Boolean.prototype.valueOf.call(val1) === + Boolean.prototype.valueOf.call(val2) + ); } if (isBigIntObject(val1)) { - return isBigIntObject(val2) && - BigInt.prototype.valueOf.call(val1) === BigInt.prototype.valueOf.call(val2); + return ( + isBigIntObject(val2) && + BigInt.prototype.valueOf.call(val1) === + BigInt.prototype.valueOf.call(val2) + ); } if (isSymbolObject(val1)) { - return isSymbolObject(val2) && - Symbol.prototype.valueOf.call(val1) === Symbol.prototype.valueOf.call(val2); + return ( + isSymbolObject(val2) && + Symbol.prototype.valueOf.call(val1) === + Symbol.prototype.valueOf.call(val2) + ); } // Should be unreachable, here just as a backup. throw new Error(`Unknown boxed type ${val1}`); } -function innerDeepEqual(val1: unknown, val2: unknown, strict: boolean, memos?: Memos) { +function innerDeepEqual( + val1: unknown, + val2: unknown, + strict: boolean, + memos?: Memos +) { // All identical values are equivalent, as determined by ===. if (val1 === val2) { - if (val1 !== 0) - return true; + if (val1 !== 0) return true; return strict ? Object.is(val1, val2) : true; } // Check more closely if val1 and val2 are equal. if (strict) { if (typeof val1 !== 'object') { - return typeof val1 === 'number' && Number.isNaN(val1) && - Number.isNaN(val2); + return ( + typeof val1 === 'number' && Number.isNaN(val1) && Number.isNaN(val2) + ); } if (typeof val2 !== 'object' || val1 === null || val2 === null) { return false; @@ -180,8 +207,10 @@ function innerDeepEqual(val1: unknown, val2: unknown, strict: boolean, memos?: M } else if (val1Tag === '[object Object]') { return keyCheck(val1, val2, strict, memos, kNoIterator); } else if (isDate(val1)) { - if (!isDate(val2) || - Date.prototype.getTime.call(val1) !== Date.prototype.getTime.call(val2)) { + if ( + !isDate(val2) || + Date.prototype.getTime.call(val1) !== Date.prototype.getTime.call(val2) + ) { return false; } } else if (isRegExp(val1)) { @@ -191,21 +220,27 @@ function innerDeepEqual(val1: unknown, val2: unknown, strict: boolean, memos?: M } else if (isNativeError(val1) || val1 instanceof Error) { // Do not compare the stack as it might differ even though the error itself // is otherwise identical. - if ((!isNativeError(val2) && !(val2 instanceof Error)) || - (val1 as Error).message !== (val2 as Error).message || - (val1 as Error).name !== (val2 as Error).name) { + if ( + (!isNativeError(val2) && !(val2 instanceof Error)) || + (val1 as Error).message !== (val2 as Error).message || + (val1 as Error).name !== (val2 as Error).name + ) { return false; } } else if (isArrayBufferView(val1)) { if (!isArrayBufferView(val2)) return false; - if ((val1 as any)[Symbol.toStringTag] !== (val2 as any)[Symbol.toStringTag]) { + if ( + (val1 as any)[Symbol.toStringTag] !== (val2 as any)[Symbol.toStringTag] + ) { return false; } if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) { if (!areSimilarFloatArrays(val1 as FloatArray, val2 as FloatArray)) { return false; } - } else if (!areSimilarTypedArrays(val1 as ArrayBufferView, val2 as ArrayBufferView)) { + } else if ( + !areSimilarTypedArrays(val1 as ArrayBufferView, val2 as ArrayBufferView) + ) { return false; } // Buffer.compare returns true, so val1.length === val2.length. If they both @@ -219,50 +254,62 @@ function innerDeepEqual(val1: unknown, val2: unknown, strict: boolean, memos?: M } return keyCheck(val1, val2, strict, memos, kNoIterator, keys1); } else if (isSet(val1)) { - if (!isSet(val2) || (val1 as Set).size !== (val2 as Set).size) { + if ( + !isSet(val2) || + (val1 as Set).size !== (val2 as Set).size + ) { return false; } return keyCheck(val1, val2, strict, memos, kIsSet); } else if (isMap(val1)) { - if (!isMap(val2) || (val1 as Map).size !== - (val2 as Map).size) { + if ( + !isMap(val2) || + (val1 as Map).size !== + (val2 as Map).size + ) { return false; } return keyCheck(val1, val2, strict, memos, kIsMap); } else if (isAnyArrayBuffer(val1)) { - if (!isAnyArrayBuffer(val2) || - !areEqualArrayBuffers(val1 as ArrayBuffer, val2 as ArrayBuffer)) { + if ( + !isAnyArrayBuffer(val2) || + !areEqualArrayBuffers(val1 as ArrayBuffer, val2 as ArrayBuffer) + ) { return false; } } else if (isBoxedPrimitive(val1)) { if (!areEqualBoxedPrimitives(val1, val2)) { return false; } - } else if (Array.isArray(val2) || - isArrayBufferView(val2) || - isSet(val2) || - isMap(val2) || - isDate(val2) || - isRegExp(val2) || - isAnyArrayBuffer(val2) || - isBoxedPrimitive(val2) || - isNativeError(val2) || - val2 instanceof Error) { + } else if ( + Array.isArray(val2) || + isArrayBufferView(val2) || + isSet(val2) || + isMap(val2) || + isDate(val2) || + isRegExp(val2) || + isAnyArrayBuffer(val2) || + isBoxedPrimitive(val2) || + isNativeError(val2) || + val2 instanceof Error + ) { return false; } return keyCheck(val1, val2, strict, memos, kNoIterator); } -function getEnumerables(val: Object, keys : (string | symbol)[]) { +function getEnumerables(val: Object, keys: (string | symbol)[]) { return keys.filter((k) => val.propertyIsEnumerable(k)); } -function keyCheck(val1: Object, - val2: Object, - strict: boolean, - memos?: Memos, - iterationType?: number, - aKeys? : (string | symbol)[]) { +function keyCheck( + val1: Object, + val2: Object, + strict: boolean, + memos?: Memos, + iterationType?: number, + aKeys?: (string | symbol)[] +) { // For all remaining Object pairs, including Array, objects and Maps, // equivalence is determined by having: // a) The same number of owned enumerable properties @@ -305,23 +352,29 @@ function keyCheck(val1: Object, } } const symbolKeysB = Object.getOwnPropertySymbols(val2); - if (symbolKeysA.length !== symbolKeysB.length && - getEnumerables(val2, symbolKeysB).length !== count) { + if ( + symbolKeysA.length !== symbolKeysB.length && + getEnumerables(val2, symbolKeysB).length !== count + ) { return false; } } else { const symbolKeysB = Object.getOwnPropertySymbols(val2); - if (symbolKeysB.length !== 0 && - getEnumerables(val2, symbolKeysB).length !== 0) { + if ( + symbolKeysB.length !== 0 && + getEnumerables(val2, symbolKeysB).length !== 0 + ) { return false; } } } - if (aKeys!.length === 0 && - (iterationType === kNoIterator || - (iterationType === kIsArray && (val1 as any[]).length === 0) || - (val1 as any).size === 0)) { + if ( + aKeys!.length === 0 && + (iterationType === kNoIterator || + (iterationType === kIsArray && (val1 as any[]).length === 0) || + (val1 as any).size === 0) + ) { return true; } @@ -330,7 +383,7 @@ function keyCheck(val1: Object, memos = { val1: new Map(), val2: new Map(), - position: 0 + position: 0, }; } else { // We prevent up to two map.has(x) calls by directly retrieving the value @@ -357,7 +410,12 @@ function keyCheck(val1: Object, return areEq; } -function setHasEqualElement(set : Set, val1: unknown, strict: boolean, memo: Memos) { +function setHasEqualElement( + set: Set, + val1: unknown, + strict: boolean, + memo: Memos +) { // Go looking. for (const val2 of set) { if (innerDeepEqual(val1, val2, strict, memo)) { @@ -370,7 +428,7 @@ function setHasEqualElement(set : Set, val1: unknown, strict: boolean, return false; } -function findLooseMatchingPrimitives(prim : unknown) { +function findLooseMatchingPrimitives(prim: unknown) { switch (typeof prim) { case 'undefined': return null; @@ -380,37 +438,52 @@ function findLooseMatchingPrimitives(prim : unknown) { return false; case 'string': return !Number.isNaN(+prim); - // Loose equal entries exist only if the string is possible to convert to - // a regular number and not NaN. + // Loose equal entries exist only if the string is possible to convert to + // a regular number and not NaN. case 'number': return !Number.isNaN(prim); } return true; } -function setMightHaveLoosePrim(a: Set, b: Set, prim: unknown) { +function setMightHaveLoosePrim( + a: Set, + b: Set, + prim: unknown +) { const altValue = findLooseMatchingPrimitives(prim); - if (altValue != null) - return altValue; + if (altValue != null) return altValue; return b.has(altValue) && !a.has(altValue); } -function mapMightHaveLoosePrim(a: Map, b: Map, prim: unknown, - item: unknown, memo: Memos) { +function mapMightHaveLoosePrim( + a: Map, + b: Map, + prim: unknown, + item: unknown, + memo: Memos +) { const altValue = findLooseMatchingPrimitives(prim); if (altValue != null) { return altValue; } const curB = b.get(altValue); - if ((curB === undefined && !b.has(altValue)) || - !innerDeepEqual(item, curB, false, memo)) { + if ( + (curB === undefined && !b.has(altValue)) || + !innerDeepEqual(item, curB, false, memo) + ) { return false; } return !a.has(altValue) && innerDeepEqual(item, curB, false, memo); } -function setEquiv(a: Set, b: Set, strict: boolean, memo: Memos) { +function setEquiv( + a: Set, + b: Set, + strict: boolean, + memo: Memos +) { // This is a lazily initiated Set of entries which have to be compared // pairwise. let set = null; @@ -428,8 +501,7 @@ function setEquiv(a: Set, b: Set, strict: boolean, memo: Memos // O(n log n) complexity we have to copy these values in a new set first. set.add(val); } else if (!b.has(val)) { - if (strict) - return false; + if (strict) return false; // Fast path to detect missing string, symbol, undefined and null values. if (!setMightHaveLoosePrim(a, b, val)) { @@ -448,11 +520,12 @@ function setEquiv(a: Set, b: Set, strict: boolean, memo: Memos // We have to check if a primitive value is already // matching and only if it's not, go hunting for it. if (typeof val === 'object' && val !== null) { - if (!setHasEqualElement(set, val, strict, memo)) - return false; - } else if (!strict && - !a.has(val) && - !setHasEqualElement(set, val, strict, memo)) { + if (!setHasEqualElement(set, val, strict, memo)) return false; + } else if ( + !strict && + !a.has(val) && + !setHasEqualElement(set, val, strict, memo) + ) { return false; } } @@ -462,18 +535,22 @@ function setEquiv(a: Set, b: Set, strict: boolean, memo: Memos return true; } -function mapHasEqualEntry(set: Set, - map: Map, - key1: unknown, - item1: unknown, - strict: boolean, - memo: Memos) { +function mapHasEqualEntry( + set: Set, + map: Map, + key1: unknown, + item1: unknown, + strict: boolean, + memo: Memos +) { // To be able to handle cases like: // Map([[{}, 'a'], [{}, 'b']]) vs Map([[{}, 'b'], [{}, 'a']]) // ... we need to consider *all* matching keys, not just the first we find. for (const key2 of set) { - if (innerDeepEqual(key1, key2, strict, memo) && - innerDeepEqual(item1, map.get(key2), strict, memo)) { + if ( + innerDeepEqual(key1, key2, strict, memo) && + innerDeepEqual(item1, map.get(key2), strict, memo) + ) { set.delete(key2); return true; } @@ -482,8 +559,12 @@ function mapHasEqualEntry(set: Set, return false; } -function mapEquiv(a: Map, b: Map, - strict: boolean, memo: Memos) { +function mapEquiv( + a: Map, + b: Map, + strict: boolean, + memo: Memos +) { let set = null; for (const { 0: key, 1: item1 } of a) { @@ -496,14 +577,14 @@ function mapEquiv(a: Map, b: Map, // By directly retrieving the value we prevent another b.has(key) check in // almost all possible cases. const item2 = b.get(key); - if (((item2 === undefined && !b.has(key)) || - !innerDeepEqual(item1, item2, strict, memo))) { - if (strict) - return false; + if ( + (item2 === undefined && !b.has(key)) || + !innerDeepEqual(item1, item2, strict, memo) + ) { + if (strict) return false; // Fast path to detect missing string, symbol, undefined and null // keys. - if (!mapMightHaveLoosePrim(a, b, key, item1, memo)) - return false; + if (!mapMightHaveLoosePrim(a, b, key, item1, memo)) return false; if (set === null) { set = new Set(); } @@ -515,12 +596,12 @@ function mapEquiv(a: Map, b: Map, if (set !== null) { for (const { 0: key, 1: item } of b) { if (typeof key === 'object' && key !== null) { - if (!mapHasEqualEntry(set, a, key, item, strict, memo)) - return false; - } else if (!strict && - (!a.has(key) || - !innerDeepEqual(a.get(key), item, false, memo)) && - !mapHasEqualEntry(set, a, key, item, false, memo)) { + if (!mapHasEqualEntry(set, a, key, item, strict, memo)) return false; + } else if ( + !strict && + (!a.has(key) || !innerDeepEqual(a.get(key), item, false, memo)) && + !mapHasEqualEntry(set, a, key, item, false, memo) + ) { return false; } } @@ -530,8 +611,14 @@ function mapEquiv(a: Map, b: Map, return true; } -function objEquiv(a: Object, b: Object, strict: boolean, keys: (string|symbol)[], - memos: Memos, iterationType?: number) { +function objEquiv( + a: Object, + b: Object, + strict: boolean, + keys: (string | symbol)[], + memos: Memos, + iterationType?: number +) { // Sets and maps don't have their entries accessible via normal object // properties. let i = 0; @@ -541,14 +628,23 @@ function objEquiv(a: Object, b: Object, strict: boolean, keys: (string|symbol)[] return false; } } else if (iterationType === kIsMap) { - if (!mapEquiv(a as Map, b as Map, strict, memos)) { + if ( + !mapEquiv( + a as Map, + b as Map, + strict, + memos + ) + ) { return false; } } else if (iterationType === kIsArray) { for (; i < (a as [any]).length; i++) { if (a.hasOwnProperty(i)) { - if (!b.hasOwnProperty(i) || - !innerDeepEqual((a as [any])[i], (b as [any])[i], strict, memos)) { + if ( + !b.hasOwnProperty(i) || + !innerDeepEqual((a as [any])[i], (b as [any])[i], strict, memos) + ) { return false; } } else if (b.hasOwnProperty(i)) { @@ -558,8 +654,10 @@ function objEquiv(a: Object, b: Object, strict: boolean, keys: (string|symbol)[] const keysA = Object.keys(a); for (; i < keysA.length; i++) { const key = keysA[i]; - if (!b.hasOwnProperty(key!) || - !innerDeepEqual((a as any)[key!], (b as any)[key!], strict, memos)) { + if ( + !b.hasOwnProperty(key!) || + !innerDeepEqual((a as any)[key!], (b as any)[key!], strict, memos) + ) { return false; } } diff --git a/src/node/internal/internal_diffs.ts b/src/node/internal/internal_diffs.ts index 157dd0a82d5..1df6ae8d4ff 100644 --- a/src/node/internal/internal_diffs.ts +++ b/src/node/internal/internal_diffs.ts @@ -10,9 +10,9 @@ interface FarthestPoint { } export enum DiffType { - removed = "removed", - common = "common", - added = "added", + removed = 'removed', + common = 'common', + added = 'added', } export interface DiffResult { @@ -52,7 +52,7 @@ export function diff(A: T[], B: T[]): Array> { const suffixCommon = createCommon( A.slice(prefixCommon.length), B.slice(prefixCommon.length), - true, + true ).reverse(); A = suffixCommon.length ? A.slice(prefixCommon.length, -suffixCommon.length) @@ -68,26 +68,26 @@ export function diff(A: T[], B: T[]): Array> { if (!N) { return [ ...prefixCommon.map( - (c): DiffResult => ({ type: DiffType.common, value: c }), + (c): DiffResult => ({ type: DiffType.common, value: c }) ), ...A.map( (a): DiffResult => ({ type: swapped ? DiffType.added : DiffType.removed, value: a, - }), + }) ), ...suffixCommon.map( - (c): DiffResult => ({ type: DiffType.common, value: c }), + (c): DiffResult => ({ type: DiffType.common, value: c }) ), ]; } const offset = N; const delta = M - N; const size = M + N + 1; - const fp: FarthestPoint[] = Array.from( - { length: size }, - () => ({ y: -1, id: -1 }), - ); + const fp: FarthestPoint[] = Array.from({ length: size }, () => ({ + y: -1, + id: -1, + })); /** * INFO: * This buffer is used to save memory and improve performance. @@ -105,7 +105,7 @@ export function diff(A: T[], B: T[]): Array> { A: T[], B: T[], current: FarthestPoint, - swapped: boolean, + swapped: boolean ): Array<{ type: DiffType; value: T; @@ -150,7 +150,7 @@ export function diff(A: T[], B: T[]): Array> { slide: FarthestPoint, down: FarthestPoint, k: number, - M: number, + M: number ): FarthestPoint { if (slide && slide.y === -1 && down && down.y === -1) { return { y: 0, id: 0 }; @@ -180,7 +180,7 @@ export function diff(A: T[], B: T[]): Array> { down: FarthestPoint, _offset: number, A: T[], - B: T[], + B: T[] ): FarthestPoint { const M = A.length; const N = B.length; @@ -208,7 +208,7 @@ export function diff(A: T[], B: T[]): Array> { fp[k + 1 + offset], offset, A, - B, + B ); } for (let k = delta + p; k > delta; --k) { @@ -219,7 +219,7 @@ export function diff(A: T[], B: T[]): Array> { fp[k + 1 + offset], offset, A, - B, + B ); } fp[delta + offset] = snake( @@ -229,17 +229,17 @@ export function diff(A: T[], B: T[]): Array> { fp[delta + 1 + offset], offset, A, - B, + B ); } return [ ...prefixCommon.map( - (c): DiffResult => ({ type: DiffType.common, value: c }), + (c): DiffResult => ({ type: DiffType.common, value: c }) ), // @ts-ignore ...backTrace(A, B, fp[delta + offset], swapped), ...suffixCommon.map( - (c): DiffResult => ({ type: DiffType.common, value: c }), + (c): DiffResult => ({ type: DiffType.common, value: c }) ), ]; } @@ -255,13 +255,14 @@ export function diffstr(A: string, B: string) { // unescape invisible characters. // ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#escape_sequences return string - .replaceAll("\b", "\\b") - .replaceAll("\f", "\\f") - .replaceAll("\t", "\\t") - .replaceAll("\v", "\\v") - .replaceAll( // does not remove line breaks + .replaceAll('\b', '\\b') + .replaceAll('\f', '\\f') + .replaceAll('\t', '\\t') + .replaceAll('\v', '\\v') + .replaceAll( + // does not remove line breaks /\r\n|\r|\n/g, - (str) => str === "\r" ? "\\r" : str === "\n" ? "\\n\n" : "\\r\\n\r\n", + (str) => (str === '\r' ? '\\r' : str === '\n' ? '\\n\n' : '\\r\\n\r\n') ); } @@ -277,7 +278,9 @@ export function diffstr(A: string, B: string) { for (let i = 0; i < tokens.length - 1; i++) { if ( // @ts-ignore - !tokens[i + 1] && tokens[i + 2] && words.test(tokens[i]) && + !tokens[i + 1] && + tokens[i + 2] && + words.test(tokens[i]) && // @ts-ignore words.test(tokens[i + 2]) ) { @@ -289,7 +292,8 @@ export function diffstr(A: string, B: string) { return tokens.filter((token) => token); } else { // Split string on new lines symbols - const tokens = [], lines = string.split(/(\n|\r\n)/); + const tokens = [], + lines = string.split(/(\n|\r\n)/); // Ignore final empty token when text ends with a newline if (!lines[lines.length - 1]) { @@ -314,32 +318,35 @@ export function diffstr(A: string, B: string) { // and merge "space-diff" if surrounded by word-diff for cleaner displays function createDetails( line: DiffResult, - tokens: Array>, + tokens: Array> ) { - return tokens.filter(({ type }) => - type === line.type || type === DiffType.common - ).map((result, i, t) => { - if ( - (result.type === DiffType.common) && (t[i - 1]) && - (t[i - 1]?.type === t[i + 1]?.type) && /\s+/.test(result.value) - ) { - return { - ...result, - // @ts-ignore - type: t[i - 1].type, - }; - } - return result; - }); + return tokens + .filter(({ type }) => type === line.type || type === DiffType.common) + .map((result, i, t) => { + if ( + result.type === DiffType.common && + t[i - 1] && + t[i - 1]?.type === t[i + 1]?.type && + /\s+/.test(result.value) + ) { + return { + ...result, + // @ts-ignore + type: t[i - 1].type, + }; + } + return result; + }); } // Compute multi-line diff const diffResult = diff( tokenize(`${unescape(A)}\n`), - tokenize(`${unescape(B)}\n`), + tokenize(`${unescape(B)}\n`) ); - const added = [], removed = []; + const added = [], + removed = []; for (const result of diffResult) { if (result.type === DiffType.added) { added.push(result); @@ -360,11 +367,11 @@ export function diffstr(A: string, B: string) { b = bLines.shift(); tokens = diff( tokenize(a.value, { wordDiff: true }), - tokenize(b?.value ?? "", { wordDiff: true }), + tokenize(b?.value ?? '', { wordDiff: true }) ); if ( - tokens.some(({ type, value }) => - type === DiffType.common && value.trim().length + tokens.some( + ({ type, value }) => type === DiffType.common && value.trim().length ) ) { break; @@ -387,31 +394,32 @@ export function diffstr(A: string, B: string) { function createSign(diffType: DiffType): string { switch (diffType) { case DiffType.added: - return "+ "; + return '+ '; case DiffType.removed: - return "- "; + return '- '; default: - return " "; + return ' '; } } export function buildMessage( diffResult: ReadonlyArray>, - { stringDiff = false } = {}, + { stringDiff = false } = {} ): string[] { - const messages: string[] = [], diffMessages: string[] = []; + const messages: string[] = [], + diffMessages: string[] = []; + messages.push(''); + messages.push(''); + messages.push('[Diff] Actual / Expected'); messages.push(''); messages.push(''); - messages.push('[Diff] Actual / Expected', - ); - messages.push(""); - messages.push(""); diffResult.forEach((result: DiffResult) => { - const line = result.details?.map((detail) => detail.value).join("") ?? result.value; + const line = + result.details?.map((detail) => detail.value).join('') ?? result.value; diffMessages.push(`${createSign(result.type)}${line}`); }); - messages.push(...(stringDiff ? [diffMessages.join("")] : diffMessages)); - messages.push(""); + messages.push(...(stringDiff ? [diffMessages.join('')] : diffMessages)); + messages.push(''); return messages; } diff --git a/src/node/internal/internal_errors.ts b/src/node/internal/internal_errors.ts index 2a85cf33135..aad91d506c2 100644 --- a/src/node/internal/internal_errors.ts +++ b/src/node/internal/internal_errors.ts @@ -29,20 +29,20 @@ // TODO(soon): Fill in more of the internal/errors implementation -import { inspect } from "node-internal:internal_inspect"; +import { inspect } from 'node-internal:internal_inspect'; const classRegExp = /^([A-Z][a-z0-9]*)+$/; const kTypes = [ - "string", - "function", - "number", - "object", - "Function", - "Object", - "boolean", - "bigint", - "symbol", + 'string', + 'function', + 'number', + 'object', + 'Function', + 'Object', + 'boolean', + 'bigint', + 'symbol', ]; export class NodeErrorAbstraction extends Error { @@ -54,7 +54,8 @@ export class NodeErrorAbstraction extends Error { this.name = name; //This number changes depending on the name of this class //20 characters as of now - (this as any).stack = this.stack && `${name} [${this.code}]${this.stack.slice(20)}`; + (this as any).stack = + this.stack && `${name} [${this.code}]${this.stack.slice(20)}`; } override toString() { @@ -90,19 +91,19 @@ export class NodeTypeError extends NodeErrorAbstraction implements TypeError { function createInvalidArgType( name: string, - expected: string | string[], + expected: string | string[] ): string { // https://github.com/nodejs/node/blob/f3eb224/lib/internal/errors.js#L1037-L1087 expected = Array.isArray(expected) ? expected : [expected]; - let msg = "The "; - if (name.endsWith(" argument")) { + let msg = 'The '; + if (name.endsWith(' argument')) { // For cases like 'first argument' msg += `${name} `; } else { - const type = name.includes(".") ? "property" : "argument"; + const type = name.includes('.') ? 'property' : 'argument'; msg += `"${name}" ${type} `; } - msg += "must be "; + msg += 'must be '; const types = []; const instances = []; @@ -120,31 +121,31 @@ function createInvalidArgType( // Special handle `object` in case other instances are allowed to outline // the differences between each other. if (instances.length > 0) { - const pos = types.indexOf("object"); + const pos = types.indexOf('object'); if (pos !== -1) { types.splice(pos, 1); - instances.push("Object"); + instances.push('Object'); } } if (types.length > 0) { if (types.length > 2) { const last = types.pop(); - msg += `one of type ${types.join(", ")}, or ${last}`; + msg += `one of type ${types.join(', ')}, or ${last}`; } else if (types.length === 2) { msg += `one of type ${types[0]} or ${types[1]}`; } else { msg += `of type ${types[0]}`; } if (instances.length > 0 || other.length > 0) { - msg += " or "; + msg += ' or '; } } if (instances.length > 0) { if (instances.length > 2) { const last = instances.pop(); - msg += `an instance of ${instances.join(", ")}, or ${last}`; + msg += `an instance of ${instances.join(', ')}, or ${last}`; } else { msg += `an instance of ${instances[0]}`; if (instances.length === 2) { @@ -152,20 +153,20 @@ function createInvalidArgType( } } if (other.length > 0) { - msg += " or "; + msg += ' or '; } } if (other.length > 0) { if (other.length > 2) { const last = other.pop(); - msg += `one of ${other.join(", ")}, or ${last}`; + msg += `one of ${other.join(', ')}, or ${last}`; } else if (other.length === 2) { msg += `one of ${other[0]} or ${other[1]}`; } else { - // @ts-ignore + // @ts-ignore if (other[0].toLowerCase() !== other[0]) { - msg += "an "; + msg += 'an '; } msg += `${other[0]}`; } @@ -178,10 +179,10 @@ function invalidArgTypeHelper(input: any) { if (input == null) { return ` Received ${input}`; } - if (typeof input === "function" && input.name) { + if (typeof input === 'function' && input.name) { return ` Received function ${input.name}`; } - if (typeof input === "object") { + if (typeof input === 'object') { if (input.constructor && input.constructor.name) { return ` Received an instance of ${input.constructor.name}`; } @@ -195,9 +196,9 @@ function invalidArgTypeHelper(input: any) { } function addNumericalSeparator(val: string) { - let res = ""; + let res = ''; let i = val.length; - const start = val[0] === "-" ? 1 : 0; + const start = val[0] === '-' ? 1 : 0; for (; i >= start + 4; i -= 3) { res = `_${val.slice(i - 3, i)}${res}`; } @@ -206,31 +207,37 @@ function addNumericalSeparator(val: string) { export class ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY extends NodeError { constructor() { - super("ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY", "Public key is not valid for specified curve"); + super( + 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY', + 'Public key is not valid for specified curve' + ); } } export class ERR_CRYPTO_HASH_FINALIZED extends NodeError { constructor() { - super("ERR_CRYPTO_HASH_FINALIZED", "Digest already called"); + super('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called'); } } export class ERR_CRYPTO_HASH_UPDATE_FAILED extends NodeError { constructor() { - super("ERR_CRYPTO_HASH_UPDATE_FAILED", "Hash update failed"); + super('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed'); } } export class ERR_CRYPTO_INCOMPATIBLE_KEY extends NodeError { constructor(name: string, msg: string) { - super("ERR_CRYPTO_INCOMPATIBLE_KEY", `Incompatible ${name}: ${msg}`); + super('ERR_CRYPTO_INCOMPATIBLE_KEY', `Incompatible ${name}: ${msg}`); } } export class ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE extends NodeError { constructor(actual: string, expected: string) { - super("ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE", `Invalid key object type ${actual}, expected ${expected}.`); + super( + 'ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE', + `Invalid key object type ${actual}, expected ${expected}.` + ); } } @@ -238,7 +245,7 @@ export class ERR_INVALID_ARG_TYPE_RANGE extends NodeRangeError { constructor(name: string, expected: string | string[], actual: unknown) { const msg = createInvalidArgType(name, expected); - super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`); + super('ERR_INVALID_ARG_TYPE', `${msg}.${invalidArgTypeHelper(actual)}`); } } @@ -246,32 +253,32 @@ export class ERR_INVALID_ARG_TYPE extends NodeTypeError { constructor(name: string, expected: string | string[], actual: unknown) { const msg = createInvalidArgType(name, expected); - super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`); + super('ERR_INVALID_ARG_TYPE', `${msg}.${invalidArgTypeHelper(actual)}`); } static RangeError = ERR_INVALID_ARG_TYPE_RANGE; } export class ERR_INVALID_ARG_VALUE_RANGE extends NodeRangeError { - constructor(name: string, value: unknown, reason: string = "is invalid") { - const type = name.includes(".") ? "property" : "argument"; + constructor(name: string, value: unknown, reason: string = 'is invalid') { + const type = name.includes('.') ? 'property' : 'argument'; const inspected = inspect(value); super( - "ERR_INVALID_ARG_VALUE", - `The ${type} '${name}' ${reason}. Received ${inspected}`, + 'ERR_INVALID_ARG_VALUE', + `The ${type} '${name}' ${reason}. Received ${inspected}` ); } } export class ERR_INVALID_ARG_VALUE extends NodeTypeError { - constructor(name: string, value: unknown, reason: string = "is invalid") { - const type = name.includes(".") ? "property" : "argument"; + constructor(name: string, value: unknown, reason: string = 'is invalid') { + const type = name.includes('.') ? 'property' : 'argument'; const inspected = inspect(value); super( - "ERR_INVALID_ARG_VALUE", - `The ${type} '${name}' ${reason}. Received ${inspected}`, + 'ERR_INVALID_ARG_VALUE', + `The ${type} '${name}' ${reason}. Received ${inspected}` ); } @@ -279,13 +286,14 @@ export class ERR_INVALID_ARG_VALUE extends NodeTypeError { } export class ERR_OUT_OF_RANGE extends RangeError { - code = "ERR_OUT_OF_RANGE"; + code = 'ERR_OUT_OF_RANGE'; constructor( str: string, range: string, input: unknown, - replaceDefaultBoolean = false) { + replaceDefaultBoolean = false + ) { // TODO(later): Implement internal assert? // assert(range, 'Missing "range" argument'); let msg = replaceDefaultBoolean @@ -294,12 +302,12 @@ export class ERR_OUT_OF_RANGE extends RangeError { let received; if (Number.isInteger(input) && Math.abs(input as number) > 2 ** 32) { received = addNumericalSeparator(String(input)); - } else if (typeof input === "bigint") { + } else if (typeof input === 'bigint') { received = String(input); if (input > 2n ** 32n || input < -(2n ** 32n)) { received = addNumericalSeparator(received); } - received += "n"; + received += 'n'; } else { received = inspect(input); } @@ -319,23 +327,23 @@ export class ERR_OUT_OF_RANGE extends RangeError { export class ERR_UNHANDLED_ERROR extends NodeError { constructor(x: string) { - super("ERR_UNHANDLED_ERROR", `Unhandled error. (${x})`); + super('ERR_UNHANDLED_ERROR', `Unhandled error. (${x})`); } } export class ERR_INVALID_THIS extends NodeTypeError { constructor(x: string) { - super("ERR_INVALID_THIS", `Value of "this" must be of type ${x}`); + super('ERR_INVALID_THIS', `Value of "this" must be of type ${x}`); } } export class ERR_BUFFER_OUT_OF_BOUNDS extends NodeRangeError { constructor(name?: string) { super( - "ERR_BUFFER_OUT_OF_BOUNDS", + 'ERR_BUFFER_OUT_OF_BOUNDS', name ? `"${name}" is outside of buffer bounds` - : "Attempt to access memory outside buffer bounds", + : 'Attempt to access memory outside buffer bounds' ); } } @@ -343,45 +351,45 @@ export class ERR_BUFFER_OUT_OF_BOUNDS extends NodeRangeError { export class ERR_INVALID_BUFFER_SIZE extends NodeRangeError { constructor(size: number) { super( - "ERR_INVALID_BUFFER_SIZE", - `Buffer size must be a multiple of ${size}-bits`, + 'ERR_INVALID_BUFFER_SIZE', + `Buffer size must be a multiple of ${size}-bits` ); } } export class ERR_UNKNOWN_ENCODING extends NodeTypeError { constructor(x: string) { - super("ERR_UNKNOWN_ENCODING", `Unknown encoding: ${x}`); + super('ERR_UNKNOWN_ENCODING', `Unknown encoding: ${x}`); } } export class ERR_STREAM_PREMATURE_CLOSE extends NodeTypeError { constructor() { - super("ERR_STREAM_PREMATURE_CLOSE", "Premature close"); + super('ERR_STREAM_PREMATURE_CLOSE', 'Premature close'); } } export class AbortError extends Error { code: string; - constructor(message = "The operation was aborted", options?: ErrorOptions) { - if (options !== undefined && typeof options !== "object") { - throw new ERR_INVALID_ARG_TYPE("options", "Object", options); + constructor(message = 'The operation was aborted', options?: ErrorOptions) { + if (options !== undefined && typeof options !== 'object') { + throw new ERR_INVALID_ARG_TYPE('options', 'Object', options); } super(message, options); - this.code = "ABORT_ERR"; - this.name = "AbortError"; + this.code = 'ABORT_ERR'; + this.name = 'AbortError'; } } function determineSpecificType(value: any) { if (value == null) { - return "" + value; + return '' + value; } - if (typeof value === "function" && value.name) { + if (typeof value === 'function' && value.name) { return `function ${value.name}`; } - if (typeof value === "object") { + if (typeof value === 'object') { if (value.constructor?.name) { return `an instance of ${value.constructor.name}`; } @@ -395,39 +403,37 @@ function determineSpecificType(value: any) { export class ERR_AMBIGUOUS_ARGUMENT extends NodeTypeError { constructor(x: string, y: string) { - super("ERR_AMBIGUOUS_ARGUMENT", `The "${x}" argument is ambiguous. ${y}`); + super('ERR_AMBIGUOUS_ARGUMENT', `The "${x}" argument is ambiguous. ${y}`); } } export class ERR_INVALID_RETURN_VALUE extends NodeTypeError { constructor(input: string, name: string, value: unknown) { super( - "ERR_INVALID_RETURN_VALUE", - `Expected ${input} to be returned from the "${name}" function but got ${ - determineSpecificType( - value, - ) - }.`, + 'ERR_INVALID_RETURN_VALUE', + `Expected ${input} to be returned from the "${name}" function but got ${determineSpecificType( + value + )}.` ); } } export class ERR_MULTIPLE_CALLBACK extends NodeError { constructor() { - super("ERR_MULTIPLE_CALLBACK", "Callback called multiple times"); + super('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); } } export class ERR_MISSING_ARGS extends NodeTypeError { constructor(...args: (string | string[])[]) { - let msg = "The "; + let msg = 'The '; const len = args.length; const wrap = (a: unknown) => `"${a}"`; args = args.map((a) => - Array.isArray(a) ? a.map(wrap).join(" or ") : wrap(a) + Array.isArray(a) ? a.map(wrap).join(' or ') : wrap(a) ); switch (len) { @@ -438,73 +444,85 @@ export class ERR_MISSING_ARGS extends NodeTypeError { msg += `${args[0]} and ${args[1]} arguments`; break; default: - msg += args.slice(0, len - 1).join(", "); + msg += args.slice(0, len - 1).join(', '); msg += `, and ${args[len - 1]} arguments`; break; } - super("ERR_MISSING_ARGS", `${msg} must be specified`); + super('ERR_MISSING_ARGS', `${msg} must be specified`); } } export class ERR_FALSY_VALUE_REJECTION extends NodeError { reason: string; constructor(reason: string) { - super("ERR_FALSY_VALUE_REJECTION", "Promise was rejected with falsy value"); + super('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value'); this.reason = reason; } } export class ERR_METHOD_NOT_IMPLEMENTED extends NodeError { - constructor(name: string|symbol) { + constructor(name: string | symbol) { if (typeof name === 'symbol') { name = (name as symbol).description!; } - super("ERR_METHOD_NOT_IMPLEMENTED", `The ${name} method is not implemented`); + super( + 'ERR_METHOD_NOT_IMPLEMENTED', + `The ${name} method is not implemented` + ); } } export class ERR_STREAM_CANNOT_PIPE extends NodeError { constructor() { - super("ERR_STREAM_CANNOT_PIPE", "Cannot pipe, not readable"); + super('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); } } export class ERR_STREAM_DESTROYED extends NodeError { - constructor(name: string|symbol) { + constructor(name: string | symbol) { if (typeof name === 'symbol') { name = (name as symbol).description!; } - super("ERR_STREAM_DESTROYED", `Cannot call ${name} after a stream was destroyed`); + super( + 'ERR_STREAM_DESTROYED', + `Cannot call ${name} after a stream was destroyed` + ); } } export class ERR_STREAM_ALREADY_FINISHED extends NodeError { - constructor(name: string|symbol) { + constructor(name: string | symbol) { if (typeof name === 'symbol') { name = (name as symbol).description!; } - super("ERR_STREAM_ALREADY_FINISHED", `Cannot call ${name} after a stream was finished`); + super( + 'ERR_STREAM_ALREADY_FINISHED', + `Cannot call ${name} after a stream was finished` + ); } } export class ERR_STREAM_NULL_VALUES extends NodeTypeError { constructor() { - super("ERR_STREAM_NULL_VALUES", "May not write null values to stream"); + super('ERR_STREAM_NULL_VALUES', 'May not write null values to stream'); } } export class ERR_STREAM_WRITE_AFTER_END extends NodeError { constructor() { - super("ERR_STREAM_WRITE_AFTER_END", "write after end"); + super('ERR_STREAM_WRITE_AFTER_END', 'write after end'); } } export class ERR_STREAM_PUSH_AFTER_EOF extends NodeError { constructor() { - super("ERR_STREAM_PUSH_AFTER_EOF", "stream.push() after EOF"); + super('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); } } export class ERR_STREAM_UNSHIFT_AFTER_END_EVENT extends NodeError { constructor() { - super("ERR_STREAM_UNSHIFT_AFTER_END_EVENT", "stream.unshift() after end event"); + super( + 'ERR_STREAM_UNSHIFT_AFTER_END_EVENT', + 'stream.unshift() after end event' + ); } } @@ -515,10 +533,12 @@ export function aggregateTwoErrors(innerError: any, outerError: any) { outerError.errors.push(innerError); return outerError; } - const err = new AggregateError([outerError, innerError], outerError.message); + const err = new AggregateError( + [outerError, innerError], + outerError.message + ); (err as any).code = outerError.code; return err; } - return innerError || outerError + return innerError || outerError; } - diff --git a/src/node/internal/internal_inspect.ts b/src/node/internal/internal_inspect.ts index 053a0d03646..4539f1a91cd 100644 --- a/src/node/internal/internal_inspect.ts +++ b/src/node/internal/internal_inspect.ts @@ -29,10 +29,10 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import internalWorkers from "cloudflare-internal:workers"; -import internal from "node-internal:util"; +import internalWorkers from 'cloudflare-internal:workers'; +import internal from 'node-internal:util'; -import { Buffer } from "node-internal:internal_buffer"; +import { Buffer } from 'node-internal:internal_buffer'; import { isAsyncFunction, isGeneratorFunction, @@ -57,18 +57,18 @@ import { isNumberObject, isBooleanObject, isBigIntObject, -} from "node-internal:internal_types"; +} from 'node-internal:internal_types'; // import { ALL_PROPERTIES, ONLY_ENUMERABLE, getOwnNonIndexProperties } from "node-internal:internal_utils"; -import { validateObject, validateString } from "node-internal:validators"; +import { validateObject, validateString } from 'node-internal:validators'; // // Simplified assertions to avoid `Assertions require every name in the call target to be // declared with an explicit type` TypeScript error -function assert(value: boolean, message = "Assertion failed"): asserts value { +function assert(value: boolean, message = 'Assertion failed'): asserts value { if (!value) throw new Error(message); } -assert.fail = function(message = "Assertion failed"): never { +assert.fail = function (message = 'Assertion failed'): never { throw new Error(message); -} +}; function isError(e: unknown): e is Error { // An error could be an instance of Error while not being a native error @@ -78,18 +78,27 @@ function isError(e: unknown): e is Error { } const typedArrayPrototype = Object.getPrototypeOf(Uint8Array).prototype; -const typedArrayPrototypeLength: (this: internal.TypedArray) => number = Object.getOwnPropertyDescriptor(typedArrayPrototype, "length")!.get!; -const typedArrayPrototypeToStringTag: (this: internal.TypedArray) => string = Object.getOwnPropertyDescriptor(typedArrayPrototype, Symbol.toStringTag)!.get!; - -const setPrototypeSize: (this: Set) => number = Object.getOwnPropertyDescriptor(Set.prototype, "size")!.get!; -const mapPrototypeSize: (this: Map) => number = Object.getOwnPropertyDescriptor(Map.prototype, "size")!.get!; +const typedArrayPrototypeLength: (this: internal.TypedArray) => number = + Object.getOwnPropertyDescriptor(typedArrayPrototype, 'length')!.get!; +const typedArrayPrototypeToStringTag: (this: internal.TypedArray) => string = + Object.getOwnPropertyDescriptor( + typedArrayPrototype, + Symbol.toStringTag + )!.get!; + +const setPrototypeSize: (this: Set) => number = + Object.getOwnPropertyDescriptor(Set.prototype, 'size')!.get!; +const mapPrototypeSize: (this: Map) => number = + Object.getOwnPropertyDescriptor(Map.prototype, 'size')!.get!; let maxStack_ErrorName: string; let maxStack_ErrorMessage: string; function isStackOverflowError(err: Error): boolean { if (maxStack_ErrorMessage === undefined) { try { - function overflowStack() { overflowStack(); } + function overflowStack() { + overflowStack(); + } overflowStack(); } catch (err) { assert(isError(err)); @@ -98,8 +107,11 @@ function isStackOverflowError(err: Error): boolean { } } - return err && err.name === maxStack_ErrorName && - err.message === maxStack_ErrorMessage; + return ( + err && + err.name === maxStack_ErrorName && + err.message === maxStack_ErrorMessage + ); } export const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom'); @@ -185,7 +197,7 @@ export interface InspectOptions { * the getter function. * @default false */ - getters?: "get" | "set" | boolean; + getters?: 'get' | 'set' | boolean; /** * If set to `true`, an underscore is used to separate every three digits in all bigints and numbers. * @default false @@ -193,30 +205,35 @@ export interface InspectOptions { numericSeparator?: boolean; } export type Style = - | "special" - | "number" - | "bigint" - | "boolean" - | "undefined" - | "null" - | "string" - | "symbol" - | "date" - | "regexp" - | "module" - | "name"; -export type CustomInspectFunction = (depth: number, options: InspectOptionsStylized) => any; // TODO: , inspect: inspect + | 'special' + | 'number' + | 'bigint' + | 'boolean' + | 'undefined' + | 'null' + | 'string' + | 'symbol' + | 'date' + | 'regexp' + | 'module' + | 'name'; +export type CustomInspectFunction = ( + depth: number, + options: InspectOptionsStylized +) => any; // TODO: , inspect: inspect export interface InspectOptionsStylized extends InspectOptions { stylize(text: string, styleType: Style): string; } const builtInObjects = new Set( - Object.getOwnPropertyNames(globalThis).filter( - (e) => /^[A-Z][a-zA-Z0-9]+$/.exec(e) !== null) + Object.getOwnPropertyNames(globalThis).filter( + (e) => /^[A-Z][a-zA-Z0-9]+$/.exec(e) !== null + ) ); // https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot -const isUndetectableObject = (v: unknown): boolean => typeof v === 'undefined' && v !== undefined; +const isUndetectableObject = (v: unknown): boolean => + typeof v === 'undefined' && v !== undefined; // These options must stay in sync with `getUserOptions`. So if any option will // be added or removed, `getUserOptions` must also be updated accordingly. @@ -239,10 +256,14 @@ const kObjectType = 0; const kArrayType = 1; const kArrayExtrasType = 2; -const strEscapeSequencesRegExp = /[\x00-\x1f\x27\x5c\x7f-\x9f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<~]))'; @@ -300,7 +468,10 @@ interface Context extends Required { circular?: Map; } -function getUserOptions(ctx: Context, isCrossContext: boolean): InspectOptionsStylized { +function getUserOptions( + ctx: Context, + isCrossContext: boolean +): InspectOptionsStylized { const ret: InspectOptionsStylized = { stylize: ctx.stylize, showHidden: ctx.showHidden, @@ -325,9 +496,11 @@ function getUserOptions(ctx: Context, isCrossContext: boolean): InspectOptionsSt // and remove all other non-primitives, including non-primitive user options. if (isCrossContext) { Object.setPrototypeOf(ret, null); - for (const key of (Object.keys(ret) as (keyof InspectOptionsStylized)[])) { - if ((typeof ret[key] === 'object' || typeof ret[key] === 'function') && - ret[key] !== null) { + for (const key of Object.keys(ret) as (keyof InspectOptionsStylized)[]) { + if ( + (typeof ret[key] === 'object' || typeof ret[key] === 'function') && + ret[key] !== null + ) { delete ret[key]; } } @@ -355,9 +528,17 @@ function getUserOptions(ctx: Context, isCrossContext: boolean): InspectOptionsSt * @param {object} opts Optional options object that alters the output. */ /* Legacy: value, showHidden, depth, colors */ -export function inspect(value: unknown, showHidden?: boolean, depth?: number | null, color?: boolean): string; +export function inspect( + value: unknown, + showHidden?: boolean, + depth?: number | null, + color?: boolean +): string; export function inspect(value: unknown, opts?: InspectOptions): string; -export function inspect(value: unknown, opts?: Partial | boolean): string { +export function inspect( + value: unknown, + opts?: Partial | boolean +): string { // Default options const ctx: Context = { budget: {}, @@ -400,8 +581,10 @@ export function inspect(value: unknown, opts?: Partial | // functionality. if ( Object.prototype.hasOwnProperty.call(inspectDefaultOptions, key) || - key === 'stylize') { - (ctx as Record)[key] = opts[key]; + key === 'stylize' + ) { + (ctx as Record)[key] = + opts[key]; } else if (ctx.userOptions === undefined) { // This is required to pass through the actual user input. ctx.userOptions = opts; @@ -537,7 +720,9 @@ function addQuotes(str: string, quotes: number): string { function escapeFn(str: string): string { const charCode = str.charCodeAt(0); - return meta.length > charCode ? meta[charCode]! : `\\u${charCode.toString(16)}`; + return meta.length > charCode + ? meta[charCode]! + : `\\u${charCode.toString(16)}`; } // Escape control characters, single quotes and the backslash. @@ -554,10 +739,9 @@ function strEscape(str: string): string { if (str.includes("'")) { // This invalidates the charCode and therefore can not be matched for // anymore. - if (!(str.includes('"'))) { + if (!str.includes('"')) { singleQuote = -1; - } else if (!str.includes('`') && - !str.includes('${')) { + } else if (!str.includes('`') && !str.includes('${')) { singleQuote = -2; } if (singleQuote !== 39) { @@ -578,10 +762,12 @@ function strEscape(str: string): string { let last = 0; for (let i = 0; i < str.length; i++) { const point = str.charCodeAt(i); - if (point === singleQuote || - point === 92 || - point < 32 || - (point > 126 && point < 160)) { + if ( + point === singleQuote || + point === 92 || + point < 32 || + (point > 126 && point < 160) + ) { if (last === i) { result += meta[point]; } else { @@ -610,7 +796,9 @@ function strEscape(str: string): string { function stylizeWithColor(str: string, styleType: Style): string { const style = inspect.styles[styleType]; if (style !== undefined) { - const color = (inspect.colors as unknown as Record)[style]; + const color = ( + inspect.colors as unknown as Record + )[style]; if (color !== undefined) return `\u001b[${color[0]}m${str}\u001b[${color[1]}m`; } @@ -634,20 +822,33 @@ function isInstanceof(object: unknown, proto: Function): boolean { } } -function getConstructorName(obj: object, ctx: Context, recurseTimes: number, protoProps?: string[]): string | null { +function getConstructorName( + obj: object, + ctx: Context, + recurseTimes: number, + protoProps?: string[] +): string | null { let firstProto: unknown; const tmp = obj; while (obj || isUndetectableObject(obj)) { const descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); - if (descriptor !== undefined && - typeof descriptor.value === 'function' && - descriptor.value.name !== '' && - isInstanceof(tmp, descriptor.value)) { - if (protoProps !== undefined && - (firstProto !== obj || - !builtInObjects.has(descriptor.value.name))) { + if ( + descriptor !== undefined && + typeof descriptor.value === 'function' && + descriptor.value.name !== '' && + isInstanceof(tmp, descriptor.value) + ) { + if ( + protoProps !== undefined && + (firstProto !== obj || !builtInObjects.has(descriptor.value.name)) + ) { addPrototypeProperties( - ctx, tmp, firstProto || tmp, recurseTimes, protoProps); + ctx, + tmp, + firstProto || tmp, + recurseTimes, + protoProps + ); } return String(descriptor.value.name); } @@ -669,7 +870,11 @@ function getConstructorName(obj: object, ctx: Context, recurseTimes: number, pro } const protoConstr = getConstructorName( - firstProto!, ctx, recurseTimes + 1, protoProps); + firstProto!, + ctx, + recurseTimes + 1, + protoProps + ); if (protoConstr === null) { return `${res} <${inspect(firstProto, { @@ -685,7 +890,13 @@ function getConstructorName(obj: object, ctx: Context, recurseTimes: number, pro // This function has the side effect of adding prototype properties to the // `output` argument (which is an array). This is intended to highlight user // defined prototype properties. -function addPrototypeProperties(ctx: Context, main: object, obj: Object, recurseTimes: number, output: string[]): void { +function addPrototypeProperties( + ctx: Context, + main: object, + obj: Object, + recurseTimes: number, + output: string[] +): void { let depth = 0; let keys: PropertyKey[] | undefined; let keySet: Set | undefined; @@ -698,9 +909,11 @@ function addPrototypeProperties(ctx: Context, main: object, obj: Object, recurse } // Stop as soon as a built-in object type is detected. const descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); - if (descriptor !== undefined && - typeof descriptor.value === 'function' && - builtInObjects.has(descriptor.value.name)) { + if ( + descriptor !== undefined && + typeof descriptor.value === 'function' && + builtInObjects.has(descriptor.value.name) + ) { return; } } @@ -715,9 +928,11 @@ function addPrototypeProperties(ctx: Context, main: object, obj: Object, recurse ctx.seen.push(main); for (const key of keys) { // Ignore the `constructor` property and keys that exist on layers above. - if (key === 'constructor' || - Object.prototype.hasOwnProperty.call(main, key) || - (depth !== 0 && keySet!.has(key))) { + if ( + key === 'constructor' || + Object.prototype.hasOwnProperty.call(main, key) || + (depth !== 0 && keySet!.has(key)) + ) { continue; } const desc = Object.getOwnPropertyDescriptor(obj, key); @@ -725,7 +940,14 @@ function addPrototypeProperties(ctx: Context, main: object, obj: Object, recurse continue; } const value = formatProperty( - ctx, obj, recurseTimes, key, kObjectType, desc, main); + ctx, + obj, + recurseTimes, + key, + kObjectType, + desc, + main + ); if (ctx.colors) { // Faint! output.push(`\u001b[2m${value}\u001b[22m`); @@ -734,13 +956,18 @@ function addPrototypeProperties(ctx: Context, main: object, obj: Object, recurse } } ctx.seen.pop(); - // Limit the inspection to up to three prototype layers. Using `recurseTimes` - // is not a good choice here, because it's as if the properties are declared - // on the current object from the users perspective. + // Limit the inspection to up to three prototype layers. Using `recurseTimes` + // is not a good choice here, because it's as if the properties are declared + // on the current object from the users perspective. } while (++depth !== 3); } -function getPrefix(constructor: string | null, tag: string, fallback: string, size = ''): string { +function getPrefix( + constructor: string | null, + tag: string, + fallback: string, + size = '' +): string { if (constructor === null) { if (tag !== '' && fallback !== tag) { return `[${fallback}${size}: null prototype] [${tag}] `; @@ -760,8 +987,7 @@ function getKeys(value: object, showHidden: boolean): PropertyKey[] { const symbols = Object.getOwnPropertySymbols(value); if (showHidden) { keys = Object.getOwnPropertyNames(value); - if (symbols.length !== 0) - keys.push(...symbols); + if (symbols.length !== 0) keys.push(...symbols); } else { // This might throw if `value` is a Module Namespace Object from an // unevaluated module, but we don't want to perform the actual type @@ -771,19 +997,27 @@ function getKeys(value: object, showHidden: boolean): PropertyKey[] { try { keys = Object.keys(value); } catch (err: any) { - assert(isNativeError(err) && err.name === 'ReferenceError' && - isModuleNamespaceObject(value)); + assert( + isNativeError(err) && + err.name === 'ReferenceError' && + isModuleNamespaceObject(value) + ); keys = Object.getOwnPropertyNames(value); } if (symbols.length !== 0) { - const filter = (key: PropertyKey) => Object.prototype.propertyIsEnumerable.call(value, key); + const filter = (key: PropertyKey) => + Object.prototype.propertyIsEnumerable.call(value, key); keys.push(...symbols.filter(filter)); } } return keys; } -function getCtxStyle(value: unknown, constructor: string | null, tag: string): string { +function getCtxStyle( + value: unknown, + constructor: string | null, + tag: string +): string { let fallback = ''; if (constructor === null) { fallback = internal.getConstructorName(value); @@ -794,7 +1028,11 @@ function getCtxStyle(value: unknown, constructor: string | null, tag: string): s return getPrefix(constructor, tag, fallback); } -function formatProxy(ctx: Context, proxy: internal.ProxyDetails, recurseTimes: number): string { +function formatProxy( + ctx: Context, + proxy: internal.ProxyDetails, + recurseTimes: number +): string { if (ctx.depth !== null && recurseTimes > ctx.depth) { return ctx.stylize('Proxy [Array]', 'special'); } @@ -806,17 +1044,30 @@ function formatProxy(ctx: Context, proxy: internal.ProxyDetails, recurseTimes: n ]; ctx.indentationLvl -= 2; return reduceToSingleString( - ctx, res, '', ['Proxy [', ']'], kArrayExtrasType, recurseTimes); + ctx, + res, + '', + ['Proxy [', ']'], + kArrayExtrasType, + recurseTimes + ); } // Note: using `formatValue` directly requires the indentation level to be // corrected by setting `ctx.indentationLvL += diff` and then to decrease the // value afterwards again. -function formatValue(ctx: Context, value: unknown, recurseTimes: number, typedArray?: unknown): string { +function formatValue( + ctx: Context, + value: unknown, + recurseTimes: number, + typedArray?: unknown +): string { // Primitive types cannot have properties. - if (typeof value !== 'object' && - typeof value !== 'function' && - !isUndetectableObject(value)) { + if ( + typeof value !== 'object' && + typeof value !== 'function' && + !isUndetectableObject(value) + ) { return formatPrimitive(ctx.stylize, value as Primitive, ctx); } if (value === null) { @@ -841,22 +1092,31 @@ function formatValue(ctx: Context, value: unknown, recurseTimes: number, typedAr // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it. if (ctx.customInspect) { - let maybeCustom = (value as Record)[customInspectSymbol]; + let maybeCustom = (value as Record)[ + customInspectSymbol + ]; // WORKERD SPECIFIC PATCH: if `value` is a JSG resource type, use a well-known custom inspect - const maybeResourceTypeInspect = (value as Record)[internal.kResourceTypeInspect]; - if (typeof maybeResourceTypeInspect === "object") { + const maybeResourceTypeInspect = (value as Record)[ + internal.kResourceTypeInspect + ]; + if (typeof maybeResourceTypeInspect === 'object') { maybeCustom = formatJsgResourceType.bind( context as Record, maybeResourceTypeInspect as Record ); } - if (typeof maybeCustom === 'function' && - // Filter out the util module, its inspect function is special. - maybeCustom !== inspect && - // Also filter out any prototype objects using the circular check. - !((value as object).constructor && (value as object).constructor.prototype === value)) { + if ( + typeof maybeCustom === 'function' && + // Filter out the util module, its inspect function is special. + maybeCustom !== inspect && + // Also filter out any prototype objects using the circular check. + !( + (value as object).constructor && + (value as object).constructor.prototype === value + ) + ) { // This makes sure the recurseTimes are reported as before while using // a counter internally. const depth = ctx.depth === null ? null : ctx.depth - recurseTimes; @@ -867,7 +1127,7 @@ function formatValue(ctx: Context, value: unknown, recurseTimes: number, typedAr context, depth, getUserOptions(ctx, isCrossContext), - inspect, + inspect ); // If the custom inspection method returned `this`, don't go into // infinite recursion. @@ -900,14 +1160,24 @@ function formatValue(ctx: Context, value: unknown, recurseTimes: number, typedAr return formatRaw(ctx, value, recurseTimes, typedArray); } -function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArray: unknown): string { +function formatRaw( + ctx: Context, + value: unknown, + recurseTimes: number, + typedArray: unknown +): string { let keys: PropertyKey[] | undefined; let protoProps: string[] | undefined; if (ctx.showHidden && (ctx.depth === null || recurseTimes <= ctx.depth)) { protoProps = []; } - const constructor = getConstructorName(value as object, ctx, recurseTimes, protoProps); + const constructor = getConstructorName( + value as object, + ctx, + recurseTimes, + protoProps + ); // Reset the variable to check for this later on. if (protoProps !== undefined && protoProps.length === 0) { protoProps = undefined; @@ -916,20 +1186,25 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra let tag = (value as { [Symbol.toStringTag]?: string })[Symbol.toStringTag]; // Only list the tag in case it's non-enumerable / not an own property. // Otherwise we'd print this twice. - if (typeof tag !== 'string' || - (tag !== '' && - (ctx.showHidden ? - Object.prototype.hasOwnProperty : - Object.prototype.propertyIsEnumerable) - .call(value, Symbol.toStringTag))) { + if ( + typeof tag !== 'string' || + (tag !== '' && + (ctx.showHidden + ? Object.prototype.hasOwnProperty + : Object.prototype.propertyIsEnumerable + ).call(value, Symbol.toStringTag)) + ) { tag = ''; } let base = ''; - let formatter: (ctx: Context, value: any, recurseTimes: number) => string[] = getEmptyFormatArray; + let formatter: (ctx: Context, value: any, recurseTimes: number) => string[] = + getEmptyFormatArray; let braces: [string, string] | undefined; let noIterator = true; let i = 0; - const filter = ctx.showHidden ? internal.ALL_PROPERTIES : internal.ONLY_ENUMERABLE; + const filter = ctx.showHidden + ? internal.ALL_PROPERTIES + : internal.ONLY_ENUMERABLE; let extrasType = kObjectType; @@ -938,7 +1213,11 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra // Otherwise it would not possible to identify all types properly. const isEntriesObject = hasEntries(value); - if (Symbol.iterator in (value as object) || constructor === null || isEntriesObject) { + if ( + Symbol.iterator in (value as object) || + constructor === null || + isEntriesObject + ) { noIterator = false; if (isEntriesObject) { // WORKERD SPECIFIC PATCH: if `value` is an object with entries, format them like a map @@ -948,7 +1227,7 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra // Remove `kEntries` and `size` from keys keys.splice(keys.indexOf(kEntries), 1); - const sizeIndex = keys.indexOf("size"); + const sizeIndex = keys.indexOf('size'); if (sizeIndex !== -1) keys.splice(sizeIndex, 1); formatter = formatMap.bind(null, value[kEntries][Symbol.iterator]()); @@ -957,9 +1236,10 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra braces = [`${prefix}{`, '}']; } else if (Array.isArray(value)) { // Only set the constructor for non ordinary ("Array [...]") arrays. - const prefix = (constructor !== 'Array' || tag !== '') ? - getPrefix(constructor, tag, 'Array', `(${value.length})`) : - ''; + const prefix = + constructor !== 'Array' || tag !== '' + ? getPrefix(constructor, tag, 'Array', `(${value.length})`) + : ''; keys = internal.getOwnNonIndexProperties(value, filter); braces = [`${prefix}[`, ']']; if (value.length === 0 && keys.length === 0 && protoProps === undefined) @@ -970,9 +1250,10 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra const size = setPrototypeSize.call(value); const prefix = getPrefix(constructor, tag, 'Set', `(${size})`); keys = getKeys(value, ctx.showHidden); - formatter = constructor !== null ? - formatSet.bind(null, value) : - formatSet.bind(null, Set.prototype.values.call(value)); + formatter = + constructor !== null + ? formatSet.bind(null, value) + : formatSet.bind(null, Set.prototype.values.call(value)); if (size === 0 && keys.length === 0 && protoProps === undefined) return `${prefix}{}`; braces = [`${prefix}{`, '}']; @@ -980,9 +1261,10 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra const size = mapPrototypeSize.call(value); const prefix = getPrefix(constructor, tag, 'Map', `(${size})`); keys = getKeys(value, ctx.showHidden); - formatter = constructor !== null ? - formatMap.bind(null, value) : - formatMap.bind(null, Map.prototype.entries.call(value)); + formatter = + constructor !== null + ? formatMap.bind(null, value) + : formatMap.bind(null, Map.prototype.entries.call(value)); if (size === 0 && keys.length === 0 && protoProps === undefined) return `${prefix}{}`; braces = [`${prefix}{`, '}']; @@ -993,7 +1275,12 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra if (constructor === null) { fallback = typedArrayPrototypeToStringTag.call(value); // Reconstruct the array information. - bound = new (globalThis as unknown as Record)[fallback]!(value); + bound = new ( + globalThis as unknown as Record< + string, + { new (value: NodeJS.TypedArray): NodeJS.TypedArray } + > + )[fallback]!(value); } const size = typedArrayPrototypeLength.call(value); const prefix = getPrefix(constructor, tag, fallback, `(${size})`); @@ -1040,39 +1327,41 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra constructor !== null ? value : new RegExp(value) ); const prefix = getPrefix(constructor, tag, 'RegExp'); - if (prefix !== 'RegExp ') - base = `${prefix}${base}`; - if ((keys.length === 0 && protoProps === undefined) || - (ctx.depth !== null && recurseTimes > ctx.depth)) { + if (prefix !== 'RegExp ') base = `${prefix}${base}`; + if ( + (keys.length === 0 && protoProps === undefined) || + (ctx.depth !== null && recurseTimes > ctx.depth) + ) { return ctx.stylize(base, 'regexp'); } } else if (isDate(value)) { // Make dates with properties first say the date - base = Number.isNaN(Date.prototype.getTime.call(value)) ? - Date.prototype.toString.call(value) : - Date.prototype.toISOString.call(value); + base = Number.isNaN(Date.prototype.getTime.call(value)) + ? Date.prototype.toString.call(value) + : Date.prototype.toISOString.call(value); const prefix = getPrefix(constructor, tag, 'Date'); - if (prefix !== 'Date ') - base = `${prefix}${base}`; + if (prefix !== 'Date ') base = `${prefix}${base}`; if (keys.length === 0 && protoProps === undefined) { return ctx.stylize(base, 'date'); } } else if (isError(value)) { base = formatError(value, constructor, tag, ctx, keys); - if (keys.length === 0 && protoProps === undefined) - return base; + if (keys.length === 0 && protoProps === undefined) return base; } else if (isAnyArrayBuffer(value)) { // Fast path for ArrayBuffer and SharedArrayBuffer. // Can't do the same for DataView because it has a non-primitive // .buffer property that we need to recurse for. - const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' : - 'SharedArrayBuffer'; + const arrayType = isArrayBuffer(value) + ? 'ArrayBuffer' + : 'SharedArrayBuffer'; const prefix = getPrefix(constructor, tag, arrayType); if (typedArray === undefined) { formatter = formatArrayBuffer; } else if (keys.length === 0 && protoProps === undefined) { - return prefix + - `{ byteLength: ${formatNumber(ctx.stylize, value.byteLength, false)} }`; + return ( + prefix + + `{ byteLength: ${formatNumber(ctx.stylize, value.byteLength, false)} }` + ); } braces[0] = `${prefix}{`; keys.unshift('byteLength'); @@ -1108,8 +1397,7 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra if (ctx.depth !== null && recurseTimes > ctx.depth) { let constructorName = getCtxStyle(value, constructor, tag).slice(0, -1); - if (constructor !== null) - constructorName = `[${constructorName}]`; + if (constructor !== null) constructorName = `[${constructorName}]`; return ctx.stylize(constructorName, 'special'); } recurseTimes += 1; @@ -1122,7 +1410,13 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra output = formatter(ctx, value, recurseTimes); for (i = 0; i < keys!.length; i++) { output.push( - formatProperty(ctx, value as object, recurseTimes, keys![i]!, extrasType), + formatProperty( + ctx, + value as object, + recurseTimes, + keys![i]!, + extrasType + ) ); } if (protoProps !== undefined) { @@ -1130,7 +1424,12 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra } } catch (err) { const constructorName = getCtxStyle(value, constructor, tag).slice(0, -1); - return handleMaxCallStackSize(ctx, err as Error, constructorName, indentationLvl); + return handleMaxCallStackSize( + ctx, + err as Error, + constructorName, + indentationLvl + ); } if (ctx.circular !== undefined) { const index = ctx.circular.get(value); @@ -1151,13 +1450,22 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra if (extrasType === kObjectType) { output.sort(comparator); } else if (keys!.length > 1) { - const sorted = output.slice(output.length - keys!.length).sort(comparator); + const sorted = output + .slice(output.length - keys!.length) + .sort(comparator); output.splice(output.length - keys!.length, keys!.length, ...sorted); } } const res = reduceToSingleString( - ctx, output, base, braces!, extrasType, recurseTimes, value); + ctx, + output, + base, + braces!, + extrasType, + recurseTimes, + value + ); const budget = ctx.budget[ctx.indentationLvl] || 0; const newLength = budget + res.length; ctx.budget[ctx.indentationLvl] = newLength; @@ -1176,16 +1484,21 @@ function formatRaw(ctx: Context, value: unknown, recurseTimes: number, typedArra function getIteratorBraces(type: string, tag: string): [string, string] { if (tag !== `${type} Iterator`) { - if (tag !== '') - tag += '] ['; + if (tag !== '') tag += '] ['; tag += `${type} Iterator`; } return [`[${tag}] {`, '}']; } -function getBoxedBase(value: unknown, ctx: Context, keys: PropertyKey[], constructor: string | null, tag: string): string { +function getBoxedBase( + value: unknown, + ctx: Context, + keys: PropertyKey[], + constructor: string | null, + tag: string +): string { let fn: (this: unknown) => Primitive; - let type: Capitalize> | "BigInt"; + let type: Capitalize> | 'BigInt'; if (isNumberObject(value)) { fn = Number.prototype.valueOf; type = 'Number'; @@ -1218,12 +1531,15 @@ function getBoxedBase(value: unknown, ctx: Context, keys: PropertyKey[], constru if (tag !== '' && tag !== constructor) { base += ` [${tag}]`; } - if (keys.length !== 0 || ctx.stylize === stylizeNoColor) - return base; + if (keys.length !== 0 || ctx.stylize === stylizeNoColor) return base; return ctx.stylize(base, type.toLowerCase() as Style); } -function getClassBase(value: any, constructor: string | null, tag: string): string { +function getClassBase( + value: any, + constructor: string | null, + tag: string +): string { const hasName = Object.prototype.hasOwnProperty.call(value, 'name'); const name = (hasName && value.name) || '(anonymous)'; let base = `class ${name}`; @@ -1244,15 +1560,20 @@ function getClassBase(value: any, constructor: string | null, tag: string): stri return `[${base}]`; } -function getFunctionBase(value: Function, constructor: string | null, tag: string): string { +function getFunctionBase( + value: Function, + constructor: string | null, + tag: string +): string { const stringified = Function.prototype.toString.call(value); if (stringified.startsWith('class') && stringified.endsWith('}')) { const slice = stringified.slice(5, -1); const bracketIndex = slice.indexOf('{'); - if (bracketIndex !== -1 && - (!slice.slice(0, bracketIndex).includes('(') || + if ( + bracketIndex !== -1 && + (!slice.slice(0, bracketIndex).includes('(') || // Slow path to guarantee that it's indeed a class. - classRegExp.exec(slice.replace(stripCommentsRegExp, "")) !== null) + classRegExp.exec(slice.replace(stripCommentsRegExp, '')) !== null) ) { return getClassBase(value, constructor, tag); } @@ -1283,7 +1604,10 @@ function getFunctionBase(value: Function, constructor: string | null, tag: strin return base; } -export function identicalSequenceRange(a: unknown[], b: unknown[]): { len: number, offset: number } { +export function identicalSequenceRange( + a: unknown[], + b: unknown[] +): { len: number; offset: number } { for (let i = 0; i < a.length - 3; i++) { // Find the first entry of b that matches the current entry of a. const pos = b.indexOf(a[i]); @@ -1307,7 +1631,9 @@ export function identicalSequenceRange(a: unknown[], b: unknown[]): { len: numbe } function getStackString(error: Error): string { - return error.stack ? String(error.stack) : Error.prototype.toString.call(error); + return error.stack + ? String(error.stack) + : Error.prototype.toString.call(error); } function getStackFrames(ctx: Context, err: Error, stack: string): string[] { @@ -1337,19 +1663,27 @@ function getStackFrames(ctx: Context, err: Error, stack: string): string[] { return frames; } -function improveStack(stack: string, constructor: string | null, name: string, tag: string): string { +function improveStack( + stack: string, + constructor: string | null, + name: string, + tag: string +): string { // A stack trace may contain arbitrary data. Only manipulate the output // for "regular errors" (errors that "look normal") for now. let len = name.length; - if (constructor === null || - (name.endsWith('Error') && + if ( + constructor === null || + (name.endsWith('Error') && stack.startsWith(name) && - (stack.length === len || stack[len] === ':' || stack[len] === '\n'))) { + (stack.length === len || stack[len] === ':' || stack[len] === '\n')) + ) { let fallback = 'Error'; if (constructor === null) { - const start = /^([A-Z][a-z_ A-Z0-9[\]()-]+)(?::|\n {4}at)/.exec(stack) || - /^([a-z_A-Z0-9-]*Error)$/.exec(stack); + const start = + /^([A-Z][a-z_ A-Z0-9[\]()-]+)(?::|\n {4}at)/.exec(stack) || + /^([a-z_A-Z0-9-]*Error)$/.exec(stack); fallback = (start && start[1]) || ''; len = fallback.length; fallback = fallback || 'Error'; @@ -1370,7 +1704,12 @@ function improveStack(stack: string, constructor: string | null, name: string, t return stack; } -function removeDuplicateErrorKeys(ctx: Context, keys: PropertyKey[], err: Error, stack: string): void { +function removeDuplicateErrorKeys( + ctx: Context, + keys: PropertyKey[], + err: Error, + stack: string +): void { if (!ctx.showHidden && keys.length !== 0) { for (const name of ['name', 'message', 'stack'] as const) { const index = keys.indexOf(name); @@ -1398,20 +1737,27 @@ function markNodeModules(ctx: Context, line: string): string { return line; } -function formatError(err: Error, constructor: string | null, tag: string, ctx: Context, keys: PropertyKey[]): string { +function formatError( + err: Error, + constructor: string | null, + tag: string, + ctx: Context, + keys: PropertyKey[] +): string { const name = err.name != null ? String(err.name) : 'Error'; let stack = getStackString(err); removeDuplicateErrorKeys(ctx, keys, err, stack); - if ('cause' in err && - (keys.length === 0 || !keys.includes('cause'))) { + if ('cause' in err && (keys.length === 0 || !keys.includes('cause'))) { keys.push('cause'); } // Print errors aggregated into AggregateError - if (Array.isArray((err as { errors?: unknown }).errors) && - (keys.length === 0 || !keys.includes('errors'))) { + if ( + Array.isArray((err as { errors?: unknown }).errors) && + (keys.length === 0 || !keys.includes('errors')) + ) { keys.push('errors'); } @@ -1419,8 +1765,7 @@ function formatError(err: Error, constructor: string | null, tag: string, ctx: C // Ignore the error message if it's contained in the stack. let pos = (err.message && stack.indexOf(err.message)) || -1; - if (pos !== -1) - pos += err.message.length; + if (pos !== -1) pos += err.message.length; // Wrap the error in brackets in case it has no stack trace. const stackStart = stack.indexOf('\n at', pos); if (stackStart === -1) { @@ -1451,7 +1796,11 @@ function formatError(err: Error, constructor: string | null, tag: string, ctx: C return stack; } -function groupArrayElements(ctx: Context, output: string[], value: unknown[] | undefined): string[] { +function groupArrayElements( + ctx: Context, + output: string[], + value: unknown[] | undefined +): string[] { let totalLength = 0; let maxLength = 0; let i = 0; @@ -1469,8 +1818,7 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u const len = getStringWidth(output[i]!, ctx.colors); dataLen[i] = len; totalLength += len + separatorSpace; - if (maxLength < len) - maxLength = len; + if (maxLength < len) maxLength = len; } // Add two to `maxLength` as we add a single whitespace character plus a comma // in-between two entries. @@ -1479,9 +1827,10 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u // of arrays that contains entries of very different length (i.e., if a single // entry is longer than 1/5 of all other entries combined). Otherwise the // space in-between small entries would be enormous. - if (actualMax * 3 + ctx.indentationLvl < ctx.breakLength && - (totalLength / actualMax > 5 || maxLength <= 6)) { - + if ( + actualMax * 3 + ctx.indentationLvl < ctx.breakLength && + (totalLength / actualMax > 5 || maxLength <= 6) + ) { const approxCharHeights = 2.5; const averageBias = Math.sqrt(actualMax - totalLength / output.length); const biasedMax = Math.max(actualMax - 3 - averageBias, 1); @@ -1493,17 +1842,19 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u // Divide that by `actualMax` to receive the correct number of columns. // The added bias increases the columns for short entries. Math.round( - Math.sqrt( - approxCharHeights * biasedMax * outputLength, - ) / biasedMax, + Math.sqrt(approxCharHeights * biasedMax * outputLength) / biasedMax ), // Do not exceed the breakLength. Math.floor((ctx.breakLength - ctx.indentationLvl) / actualMax), // Limit array grouping for small `compact` modes as the user requested // minimal grouping. - (ctx.compact === false ? 0 : ctx.compact === true ? inspectDefaultOptions.compact : ctx.compact) * 4, + (ctx.compact === false + ? 0 + : ctx.compact === true + ? inspectDefaultOptions.compact + : ctx.compact) * 4, // Limit the columns to a maximum of fifteen. - 15, + 15 ); // Return with the original output if no grouping should happen. if (columns <= 1) { @@ -1514,8 +1865,7 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u for (let i = 0; i < columns; i++) { let lineMaxLength = 0; for (let j = i; j < output.length; j += columns) { - if (dataLen[j] > lineMaxLength) - lineMaxLength = dataLen[j]; + if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j]; } lineMaxLength += separatorSpace; maxLineLength[i] = lineMaxLength; @@ -1543,10 +1893,11 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u str += order.call(`${output[j]}, `, padding, ' '); } if (order === String.prototype.padStart) { - const padding = maxLineLength[j - i]! + - output[j]!.length - - dataLen[j] - - separatorSpace; + const padding = + maxLineLength[j - i]! + + output[j]!.length - + dataLen[j] - + separatorSpace; str += output[j]!.padStart(padding, ' '); } else { str += output[j]; @@ -1561,14 +1912,19 @@ function groupArrayElements(ctx: Context, output: string[], value: unknown[] | u return output; } -function handleMaxCallStackSize(ctx: Context, err: Error, constructorName: string, indentationLvl: number): string { +function handleMaxCallStackSize( + ctx: Context, + err: Error, + constructorName: string, + indentationLvl: number +): string { if (isStackOverflowError(err)) { ctx.seen.pop(); ctx.indentationLvl = indentationLvl; return ctx.stylize( `[${constructorName}: Inspection interrupted ` + 'prematurely. Maximum call stack size exceeded.]', - 'special', + 'special' ); } /* c8 ignore next */ @@ -1582,9 +1938,9 @@ function addNumericSeparator(integerString: string): string { for (; i >= start + 4; i -= 3) { result = `_${integerString.slice(i - 3, i)}${result}`; } - return i === integerString.length ? - integerString : - `${integerString.slice(0, i)}${result}`; + return i === integerString.length + ? integerString + : `${integerString.slice(0, i)}${result}`; } function addNumericSeparatorEnd(integerString: string): string { @@ -1593,14 +1949,17 @@ function addNumericSeparatorEnd(integerString: string): string { for (; i < integerString.length - 3; i += 3) { result += `${integerString.slice(i, i + 3)}_`; } - return i === 0 ? - integerString : - `${result}${integerString.slice(i)}`; + return i === 0 ? integerString : `${result}${integerString.slice(i)}`; } -const remainingText = (remaining: number) => `... ${remaining} more item${remaining > 1 ? 's' : ''}`; +const remainingText = (remaining: number) => + `... ${remaining} more item${remaining > 1 ? 's' : ''}`; -function formatNumber(fn: InspectOptionsStylized["stylize"], number: number, numericSeparator?: boolean): string { +function formatNumber( + fn: InspectOptionsStylized['stylize'], + number: number, + numericSeparator?: boolean +): string { if (!numericSeparator) { // Format -0 as '-0'. Checking `number === -0` won't distinguish 0 from -0. if (Object.is(number, -0)) { @@ -1619,16 +1978,19 @@ function formatNumber(fn: InspectOptionsStylized["stylize"], number: number, num if (Number.isNaN(number)) { return fn(string, 'number'); } - return fn(`${ - addNumericSeparator(string) - }.${ - addNumericSeparatorEnd( - String(number).slice(string.length + 1), - ) - }`, 'number'); + return fn( + `${addNumericSeparator(string)}.${addNumericSeparatorEnd( + String(number).slice(string.length + 1) + )}`, + 'number' + ); } -function formatBigInt(fn: InspectOptionsStylized["stylize"], bigint: bigint, numericSeparator?: boolean): string { +function formatBigInt( + fn: InspectOptionsStylized['stylize'], + bigint: bigint, + numericSeparator?: boolean +): string { const string = String(bigint); if (!numericSeparator) { return fn(`${string}n`, 'bigint'); @@ -1637,7 +1999,11 @@ function formatBigInt(fn: InspectOptionsStylized["stylize"], bigint: bigint, num } type Primitive = string | number | bigint | boolean | undefined | symbol; -function formatPrimitive(fn: InspectOptionsStylized["stylize"], value: Primitive, ctx: Context): string { +function formatPrimitive( + fn: InspectOptionsStylized['stylize'], + value: Primitive, + ctx: Context +): string { if (typeof value === 'string') { let trailer = ''; if (ctx.maxStringLength !== null && value.length > ctx.maxStringLength) { @@ -1645,17 +2011,20 @@ function formatPrimitive(fn: InspectOptionsStylized["stylize"], value: Primitive value = value.slice(0, ctx.maxStringLength); trailer = `... ${remaining} more character${remaining > 1 ? 's' : ''}`; } - if (ctx.compact !== true && - // We do not support handling unicode characters width with - // the readline getStringWidth function as there are - // performance implications. - value.length > kMinLineLength && - value.length > ctx.breakLength - ctx.indentationLvl - 4) { - return value - .split(/(?<=\n)/) - .map((line) => fn(strEscape(line), 'string')) - .join(` +\n${' '.repeat(ctx.indentationLvl + 2)}`) - + trailer; + if ( + ctx.compact !== true && + // We do not support handling unicode characters width with + // the readline getStringWidth function as there are + // performance implications. + value.length > kMinLineLength && + value.length > ctx.breakLength - ctx.indentationLvl - 4 + ) { + return ( + value + .split(/(?<=\n)/) + .map((line) => fn(strEscape(line), 'string')) + .join(` +\n${' '.repeat(ctx.indentationLvl + 2)}`) + trailer + ); } return fn(strEscape(value), 'string') + trailer; } @@ -1663,20 +2032,28 @@ function formatPrimitive(fn: InspectOptionsStylized["stylize"], value: Primitive return formatNumber(fn, value, ctx.numericSeparator); if (typeof value === 'bigint') return formatBigInt(fn, value, ctx.numericSeparator); - if (typeof value === 'boolean') - return fn(`${value}`, 'boolean'); - if (typeof value === 'undefined') - return fn('undefined', 'undefined'); + if (typeof value === 'boolean') return fn(`${value}`, 'boolean'); + if (typeof value === 'undefined') return fn('undefined', 'undefined'); // es6 symbol primitive return fn(Symbol.prototype.toString.call(value), 'symbol'); } -function formatNamespaceObject(keys: PropertyKey[], ctx: Context, value: object, recurseTimes: number): string[] { +function formatNamespaceObject( + keys: PropertyKey[], + ctx: Context, + value: object, + recurseTimes: number +): string[] { const output = new Array(keys.length); for (let i = 0; i < keys.length; i++) { try { - output[i] = formatProperty(ctx, value, recurseTimes, keys[i]!, - kObjectType); + output[i] = formatProperty( + ctx, + value, + recurseTimes, + keys[i]!, + kObjectType + ); } catch (err) { assert(isNativeError(err) && err.name === 'ReferenceError'); // Use the existing functionality. This makes sure the indentation and @@ -1687,8 +2064,9 @@ function formatNamespaceObject(keys: PropertyKey[], ctx: Context, value: object, const pos = output[i]!.lastIndexOf(' '); // We have to find the last whitespace and have to replace that value as // it will be visualized as a regular string. - output[i] = output[i]!.slice(0, pos + 1) + - ctx.stylize('', 'special'); + output[i] = + output[i]!.slice(0, pos + 1) + + ctx.stylize('', 'special'); } } // Reset the keys to an empty array. This prevents duplicated inspection. @@ -1697,7 +2075,14 @@ function formatNamespaceObject(keys: PropertyKey[], ctx: Context, value: object, } // The array is sparse and/or has extra keys -function formatSpecialArray(ctx: Context, value: unknown[], recurseTimes: number, maxLength: number, output: string[], i: number): string[] { +function formatSpecialArray( + ctx: Context, + value: unknown[], + recurseTimes: number, + maxLength: number, + output: string[], + i: number +): string[] { const keys = Object.keys(value); let index = i; for (; i < keys.length && output.length < maxLength; i++) { @@ -1744,7 +2129,8 @@ function formatArrayBuffer(ctx: Context, value: ArrayBuffer): string[] { return [ctx.stylize('(detached)', 'special')]; } const maxArrayLength = ctx.maxArrayLength; - let str = Buffer.prototype.hexSlice.call(buffer, 0, Math.min(maxArrayLength, buffer.length)) + let str = Buffer.prototype.hexSlice + .call(buffer, 0, Math.min(maxArrayLength, buffer.length)) .replace(/(.{2})/g, '$1 ') .trim(); const remaining = buffer.length - maxArrayLength; @@ -1753,7 +2139,11 @@ function formatArrayBuffer(ctx: Context, value: ArrayBuffer): string[] { return [`${ctx.stylize('[Uint8Contents]', 'special')}: <${str}>`]; } -function formatArray(ctx: Context, value: unknown[], recurseTimes: number): string[] { +function formatArray( + ctx: Context, + value: unknown[], + recurseTimes: number +): string[] { const valLen = value.length; const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen); @@ -1772,13 +2162,20 @@ function formatArray(ctx: Context, value: unknown[], recurseTimes: number): stri return output; } -function formatTypedArray(value: internal.TypedArray, length: number, ctx: Context, _ignored: unknown, recurseTimes: number): string[] { +function formatTypedArray( + value: internal.TypedArray, + length: number, + ctx: Context, + _ignored: unknown, + recurseTimes: number +): string[] { const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), length); const remaining = value.length - maxLength; const output = new Array(maxLength); - const elementFormatter = value.length > 0 && typeof value[0] === 'number' ? - formatNumber : - formatBigInt; + const elementFormatter = + value.length > 0 && typeof value[0] === 'number' + ? formatNumber + : formatBigInt; for (let i = 0; i < maxLength; ++i) { // @ts-expect-error `value[i]` assumed to be of correct numeric type output[i] = elementFormatter(ctx.stylize, value[i], ctx.numericSeparator); @@ -1805,7 +2202,12 @@ function formatTypedArray(value: internal.TypedArray, length: number, ctx: Conte return output; } -function formatSet(value: Set | IterableIterator, ctx: Context, _ignored: unknown, recurseTimes: number): string[] { +function formatSet( + value: Set | IterableIterator, + ctx: Context, + _ignored: unknown, + recurseTimes: number +): string[] { const length = isSet(value) ? value.size : NaN; const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), length); const remaining = length - maxLength; @@ -1824,7 +2226,12 @@ function formatSet(value: Set | IterableIterator, ctx: Context return output; } -function formatMap(value: Map | IterableIterator<[unknown, unknown]>, ctx: Context, _ignored: unknown, recurseTimes: number): string[] { +function formatMap( + value: Map | IterableIterator<[unknown, unknown]>, + ctx: Context, + _ignored: unknown, + recurseTimes: number +): string[] { const length = isMap(value) ? value.size : NaN; const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), length); const remaining = length - maxLength; @@ -1845,7 +2252,12 @@ function formatMap(value: Map | IterableIterator<[unknown, unk return output; } -function formatSetIterInner(ctx: Context, recurseTimes: number, entries: unknown[], state: number): string[] { +function formatSetIterInner( + ctx: Context, + recurseTimes: number, + entries: unknown[], + state: number +): string[] { const maxArrayLength = Math.max(ctx.maxArrayLength, 0); const maxLength = Math.min(maxArrayLength, entries.length); const output = new Array(maxLength); @@ -1867,7 +2279,12 @@ function formatSetIterInner(ctx: Context, recurseTimes: number, entries: unknown return output; } -function formatMapIterInner(ctx: Context, recurseTimes: number, entries: unknown[], state: number): string[] { +function formatMapIterInner( + ctx: Context, + recurseTimes: number, + entries: unknown[], + state: number +): string[] { const maxArrayLength = Math.max(ctx.maxArrayLength, 0); // Entries exist as [key1, val1, key2, val2, ...] const len = entries.length / 2; @@ -1885,8 +2302,7 @@ function formatMapIterInner(ctx: Context, recurseTimes: number, entries: unknown // Sort all entries to have a halfway reliable output (if more entries than // retrieved ones exist, we can not reliably return the same output) if the // output is not sorted anyway. - if (!ctx.sorted) - output.sort(); + if (!ctx.sorted) output.sort(); } else { for (; i < maxLength; i++) { const pos = i * 2; @@ -1895,7 +2311,13 @@ function formatMapIterInner(ctx: Context, recurseTimes: number, entries: unknown formatValue(ctx, entries[pos + 1], recurseTimes), ]; output[i] = reduceToSingleString( - ctx, res, '', ['[', ']'], kArrayExtrasType, recurseTimes); + ctx, + res, + '', + ['[', ']'], + kArrayExtrasType, + recurseTimes + ); } } ctx.indentationLvl -= 2; @@ -1909,17 +2331,30 @@ function formatWeakCollection(ctx: Context): string[] { return [ctx.stylize('', 'special')]; } -function formatWeakSet(ctx: Context, value: WeakSet, recurseTimes: number): string[] { +function formatWeakSet( + ctx: Context, + value: WeakSet, + recurseTimes: number +): string[] { const { entries } = internal.previewEntries(value)!; return formatSetIterInner(ctx, recurseTimes, entries, kWeak); } -function formatWeakMap(ctx: Context, value: WeakMap, recurseTimes: number): string[] { +function formatWeakMap( + ctx: Context, + value: WeakMap, + recurseTimes: number +): string[] { const { entries } = internal.previewEntries(value)!; return formatMapIterInner(ctx, recurseTimes, entries, kWeak); } -function formatIterator(braces: [string, string], ctx: Context, value: Iterator, recurseTimes: number): string[] { +function formatIterator( + braces: [string, string], + ctx: Context, + value: Iterator, + recurseTimes: number +): string[] { const { entries, isKeyValue } = internal.previewEntries(value)!; if (isKeyValue) { // Mark entry iterators as such. @@ -1930,7 +2365,11 @@ function formatIterator(braces: [string, string], ctx: Context, value: Iterator< return formatSetIterInner(ctx, recurseTimes, entries, kIterator); } -function formatPromise(ctx: Context, value: Promise, recurseTimes: number): string[] { +function formatPromise( + ctx: Context, + value: Promise, + recurseTimes: number +): string[] { let output: string[]; const { state, result } = internal.getPromiseDetails(value)!; if (state === internal.kPending) { @@ -1940,22 +2379,32 @@ function formatPromise(ctx: Context, value: Promise, recurseTimes: numb const str = formatValue(ctx, result, recurseTimes); ctx.indentationLvl -= 2; output = [ - state === internal.kRejected ? - `${ctx.stylize('', 'special')} ${str}` : - str, + state === internal.kRejected + ? `${ctx.stylize('', 'special')} ${str}` + : str, ]; } return output; } -function formatProperty(ctx: Context, value: object, recurseTimes: number, key: PropertyKey, type: number, desc?: PropertyDescriptor, - original = value): string { +function formatProperty( + ctx: Context, + value: object, + recurseTimes: number, + key: PropertyKey, + type: number, + desc?: PropertyDescriptor, + original = value +): string { let name: string, str: string; let extra = ' '; - desc = desc || Object.getOwnPropertyDescriptor(value, key) || - { value: (value as Record)[key], enumerable: true }; + desc = desc || + Object.getOwnPropertyDescriptor(value, key) || { + value: (value as Record)[key], + enumerable: true, + }; if (desc.value !== undefined) { - const diff = (ctx.compact !== true || type !== kObjectType) ? 2 : 3; + const diff = ctx.compact !== true || type !== kObjectType ? 2 : 3; ctx.indentationLvl += diff; str = formatValue(ctx, desc.value, recurseTimes); if (diff === 3 && ctx.breakLength < getStringWidth(str, ctx.colors)) { @@ -1966,9 +2415,12 @@ function formatProperty(ctx: Context, value: object, recurseTimes: number, key: const label = desc.set !== undefined ? 'Getter/Setter' : 'Getter'; const s = ctx.stylize; const sp = 'special'; - if (ctx.getters && (ctx.getters === true || - (ctx.getters === 'get' && desc.set === undefined) || - (ctx.getters === 'set' && desc.set !== undefined))) { + if ( + ctx.getters && + (ctx.getters === true || + (ctx.getters === 'get' && desc.set === undefined) || + (ctx.getters === 'set' && desc.set !== undefined)) + ) { try { const tmp = desc.get.call(original); ctx.indentationLvl += 2; @@ -1997,7 +2449,9 @@ function formatProperty(ctx: Context, value: object, recurseTimes: number, key: return str; } if (typeof key === 'symbol') { - const tmp = Symbol.prototype.toString.call(key).replace(strEscapeSequencesReplacer, escapeFn); + const tmp = Symbol.prototype.toString + .call(key) + .replace(strEscapeSequencesReplacer, escapeFn); name = `[${ctx.stylize(tmp, 'symbol')}]`; } else if (key === '__proto__') { name = "['__proto__']"; @@ -2012,7 +2466,12 @@ function formatProperty(ctx: Context, value: object, recurseTimes: number, key: return `${name}:${extra}${str}`; } -function isBelowBreakLength(ctx: Context, output: string[], start: number, base: string): boolean { +function isBelowBreakLength( + ctx: Context, + output: string[], + start: number, + base: string +): boolean { // Each entry is separated by at least a comma. Thus, we start with a total // length of at least `output.length`. In addition, some cases have a // whitespace in-between each other that is added to the total as well. @@ -2020,8 +2479,7 @@ function isBelowBreakLength(ctx: Context, output: string[], start: number, base: // function. Check the performance overhead and make it an opt-in in case it's // significant. let totalLength = output.length + start; - if (totalLength + output.length > ctx.breakLength) - return false; + if (totalLength + output.length > ctx.breakLength) return false; for (let i = 0; i < output.length; i++) { if (ctx.colors) { totalLength += removeColors(output[i]!).length; @@ -2037,7 +2495,14 @@ function isBelowBreakLength(ctx: Context, output: string[], start: number, base: } function reduceToSingleString( - ctx: Context, output: string[], base: string, braces: [string, string], extrasType: number, recurseTimes: number, value?: unknown): string { + ctx: Context, + output: string[], + base: string, + braces: [string, string], + extrasType: number, + recurseTimes: number, + value?: unknown +): string { if (ctx.compact !== true) { if (typeof ctx.compact === 'number' && ctx.compact >= 1) { // Memorize the original output length. In case the output is grouped, @@ -2062,39 +2527,52 @@ function reduceToSingleString( // Consolidate all entries of the local most inner depth up to // `ctx.compact`, as long as the properties are smaller than // `ctx.breakLength`. - if (ctx.currentDepth - recurseTimes < ctx.compact && - entries === output.length) { + if ( + ctx.currentDepth - recurseTimes < ctx.compact && + entries === output.length + ) { // Line up all entries on a single line in case the entries do not // exceed `breakLength`. Add 10 as constant to start next to all other // factors that may reduce `breakLength`. - const start = output.length + ctx.indentationLvl + - braces[0].length + base.length + 10; + const start = + output.length + + ctx.indentationLvl + + braces[0].length + + base.length + + 10; if (isBelowBreakLength(ctx, output, start, base)) { const joinedOutput = output.join(', '); if (!joinedOutput.includes('\n')) { - return `${base ? `${base} ` : ''}${braces[0]} ${joinedOutput}` + - ` ${braces[1]}`; + return ( + `${base ? `${base} ` : ''}${braces[0]} ${joinedOutput}` + + ` ${braces[1]}` + ); } } } } // Line up each entry on an individual line. const indentation = `\n${' '.repeat(ctx.indentationLvl)}`; - return `${base ? `${base} ` : ''}${braces[0]}${indentation} ` + - `${output.join(`,${indentation} `)}${indentation}${braces[1]}`; + return ( + `${base ? `${base} ` : ''}${braces[0]}${indentation} ` + + `${output.join(`,${indentation} `)}${indentation}${braces[1]}` + ); } // Line up all entries on a single line in case the entries do not exceed // `breakLength`. if (isBelowBreakLength(ctx, output, 0, base)) { - return `${braces[0]}${base ? ` ${base}` : ''} ${output.join(', ')} ` + - braces[1]; + return ( + `${braces[0]}${base ? ` ${base}` : ''} ${output.join(', ')} ` + braces[1] + ); } const indentation = ' '.repeat(ctx.indentationLvl); // If the opening "brace" is too large, like in the case of "Set {", // we need to force the first item to be on the next line or the // items will not line up correctly. - const ln = base === '' && braces[0].length === 1 ? - ' ' : `${base ? ` ${base}` : ''}\n${indentation} `; + const ln = + base === '' && braces[0].length === 1 + ? ' ' + : `${base ? ` ${base}` : ''}\n${indentation} `; // Line up each entry on an individual line. return `${braces[0]}${ln}${output.join(`,\n${indentation} `)} ${braces[1]}`; } @@ -2128,12 +2606,15 @@ function hasBuiltInToString(value: object): boolean { // Check closer if the object is a built-in. const descriptor = Object.getOwnPropertyDescriptor(pointer, 'constructor'); - return descriptor !== undefined && + return ( + descriptor !== undefined && typeof descriptor.value === 'function' && - builtInObjects.has(descriptor.value.name); + builtInObjects.has(descriptor.value.name) + ); } -const firstErrorLine = (error: unknown) => (isError(error) ? error.message : String(error)).split('\n', 1)[0]; +const firstErrorLine = (error: unknown) => + (isError(error) ? error.message : String(error)).split('\n', 1)[0]; let CIRCULAR_ERROR_MESSAGE: string | undefined; function tryStringify(arg: unknown): string { try { @@ -2149,8 +2630,13 @@ function tryStringify(arg: unknown): string { CIRCULAR_ERROR_MESSAGE = firstErrorLine(circularError); } } - if (typeof err === "object" && err !== null && "name" in err && err.name === 'TypeError' && - firstErrorLine(err) === CIRCULAR_ERROR_MESSAGE) { + if ( + typeof err === 'object' && + err !== null && + 'name' in err && + err.name === 'TypeError' && + firstErrorLine(err) === CIRCULAR_ERROR_MESSAGE + ) { return '[Circular]'; } throw err; @@ -2161,7 +2647,10 @@ export function format(...args: unknown[]): string { return formatWithOptionsInternal(undefined, args); } -export function formatWithOptions(inspectOptions: InspectOptions, ...args: unknown[]): string { +export function formatWithOptions( + inspectOptions: InspectOptions, + ...args: unknown[] +): string { validateObject(inspectOptions, 'inspectOptions', { allowArray: true }); return formatWithOptionsInternal(inspectOptions, args); } @@ -2170,7 +2659,7 @@ function formatNumberNoColor(number: number, options?: InspectOptions): string { return formatNumber( stylizeNoColor, number, - options?.numericSeparator ?? inspectDefaultOptions.numericSeparator, + options?.numericSeparator ?? inspectDefaultOptions.numericSeparator ); } @@ -2178,11 +2667,14 @@ function formatBigIntNoColor(bigint: bigint, options?: InspectOptions): string { return formatBigInt( stylizeNoColor, bigint, - options?.numericSeparator ?? inspectDefaultOptions.numericSeparator, + options?.numericSeparator ?? inspectDefaultOptions.numericSeparator ); } -function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, args: unknown[]): string { +function formatWithOptionsInternal( + inspectOptions: InspectOptions | undefined, + args: unknown[] +): string { const first = args[0]; let a = 0; let str = ''; @@ -2196,19 +2688,23 @@ function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, a let lastPos = 0; for (let i = 0; i < first.length - 1; i++) { - if (first.charCodeAt(i) === 37) { // '%' + if (first.charCodeAt(i) === 37) { + // '%' const nextChar = first.charCodeAt(++i); if (a + 1 !== args.length) { switch (nextChar) { - case 115: { // 's' + case 115: { + // 's' const tempArg = args[++a]; if (typeof tempArg === 'number') { tempStr = formatNumberNoColor(tempArg, inspectOptions); } else if (typeof tempArg === 'bigint') { tempStr = formatBigIntNoColor(tempArg, inspectOptions); - } else if (typeof tempArg !== 'object' || - tempArg === null || - !hasBuiltInToString(tempArg)) { + } else if ( + typeof tempArg !== 'object' || + tempArg === null || + !hasBuiltInToString(tempArg) + ) { tempStr = String(tempArg); } else { tempStr = inspect(tempArg, { @@ -2223,7 +2719,8 @@ function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, a case 106: // 'j' tempStr = tryStringify(args[++a]); break; - case 100: { // 'd' + case 100: { + // 'd' const tempNum = args[++a]; if (typeof tempNum === 'bigint') { tempStr = formatBigIntNoColor(tempNum, inspectOptions); @@ -2245,7 +2742,8 @@ function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, a depth: 4, }); break; - case 105: { // 'i' + case 105: { + // 'i' const tempInteger = args[++a]; if (typeof tempInteger === 'bigint') { tempStr = formatBigIntNoColor(tempInteger, inspectOptions); @@ -2253,17 +2751,22 @@ function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, a tempStr = 'NaN'; } else { tempStr = formatNumberNoColor( - Number.parseInt(tempInteger as unknown as string), inspectOptions); + Number.parseInt(tempInteger as unknown as string), + inspectOptions + ); } break; } - case 102: { // 'f' + case 102: { + // 'f' const tempFloat = args[++a]; if (typeof tempFloat === 'symbol') { tempStr = 'NaN'; } else { tempStr = formatNumberNoColor( - Number.parseFloat(tempFloat as unknown as string), inspectOptions); + Number.parseFloat(tempFloat as unknown as string), + inspectOptions + ); } break; } @@ -2309,15 +2812,17 @@ function formatWithOptionsInternal(inspectOptions: InspectOptions | undefined, a } export function isZeroWidthCodePoint(code: number): boolean { - return code <= 0x1F || // C0 control codes - (code >= 0x7F && code <= 0x9F) || // C1 control codes - (code >= 0x300 && code <= 0x36F) || // Combining Diacritical Marks - (code >= 0x200B && code <= 0x200F) || // Modifying Invisible Characters + return ( + code <= 0x1f || // C0 control codes + (code >= 0x7f && code <= 0x9f) || // C1 control codes + (code >= 0x300 && code <= 0x36f) || // Combining Diacritical Marks + (code >= 0x200b && code <= 0x200f) || // Modifying Invisible Characters // Combining Diacritical Marks for Symbols - (code >= 0x20D0 && code <= 0x20FF) || - (code >= 0xFE00 && code <= 0xFE0F) || // Variation Selectors - (code >= 0xFE20 && code <= 0xFE2F) || // Combining Half Marks - (code >= 0xE0100 && code <= 0xE01EF); // Variation Selectors + (code >= 0x20d0 && code <= 0x20ff) || + (code >= 0xfe00 && code <= 0xfe0f) || // Variation Selectors + (code >= 0xfe20 && code <= 0xfe2f) || // Combining Half Marks + (code >= 0xe0100 && code <= 0xe01ef) + ); // Variation Selectors } /** @@ -2326,8 +2831,7 @@ export function isZeroWidthCodePoint(code: number): boolean { export function getStringWidth(str: string, removeControlChars = true): number { let width = 0; - if (removeControlChars) - str = stripVTControlCharacters(str); + if (removeControlChars) str = stripVTControlCharacters(str); str = str.normalize('NFC'); for (const char of str) { const code = char.codePointAt(0)!; @@ -2339,7 +2843,7 @@ export function getStringWidth(str: string, removeControlChars = true): number { } return width; -}; +} /** * Returns true if the character represented by a given @@ -2348,38 +2852,39 @@ export function getStringWidth(str: string, removeControlChars = true): number { const isFullWidthCodePoint = (code: number) => { // Code points are partially derived from: // https://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt - return code >= 0x1100 && ( - code <= 0x115f || // Hangul Jamo - code === 0x2329 || // LEFT-POINTING ANGLE BRACKET - code === 0x232a || // RIGHT-POINTING ANGLE BRACKET - // CJK Radicals Supplement .. Enclosed CJK Letters and Months - (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) || - // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A - (code >= 0x3250 && code <= 0x4dbf) || - // CJK Unified Ideographs .. Yi Radicals - (code >= 0x4e00 && code <= 0xa4c6) || - // Hangul Jamo Extended-A - (code >= 0xa960 && code <= 0xa97c) || - // Hangul Syllables - (code >= 0xac00 && code <= 0xd7a3) || - // CJK Compatibility Ideographs - (code >= 0xf900 && code <= 0xfaff) || - // Vertical Forms - (code >= 0xfe10 && code <= 0xfe19) || - // CJK Compatibility Forms .. Small Form Variants - (code >= 0xfe30 && code <= 0xfe6b) || - // Halfwidth and Fullwidth Forms - (code >= 0xff01 && code <= 0xff60) || - (code >= 0xffe0 && code <= 0xffe6) || - // Kana Supplement - (code >= 0x1b000 && code <= 0x1b001) || - // Enclosed Ideographic Supplement - (code >= 0x1f200 && code <= 0x1f251) || - // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff - // Emoticons 0x1f600 - 0x1f64f - (code >= 0x1f300 && code <= 0x1f64f) || - // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane - (code >= 0x20000 && code <= 0x3fffd) + return ( + code >= 0x1100 && + (code <= 0x115f || // Hangul Jamo + code === 0x2329 || // LEFT-POINTING ANGLE BRACKET + code === 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK Radicals Supplement .. Enclosed CJK Letters and Months + (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) || + // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A + (code >= 0x3250 && code <= 0x4dbf) || + // CJK Unified Ideographs .. Yi Radicals + (code >= 0x4e00 && code <= 0xa4c6) || + // Hangul Jamo Extended-A + (code >= 0xa960 && code <= 0xa97c) || + // Hangul Syllables + (code >= 0xac00 && code <= 0xd7a3) || + // CJK Compatibility Ideographs + (code >= 0xf900 && code <= 0xfaff) || + // Vertical Forms + (code >= 0xfe10 && code <= 0xfe19) || + // CJK Compatibility Forms .. Small Form Variants + (code >= 0xfe30 && code <= 0xfe6b) || + // Halfwidth and Fullwidth Forms + (code >= 0xff01 && code <= 0xff60) || + (code >= 0xffe0 && code <= 0xffe6) || + // Kana Supplement + (code >= 0x1b000 && code <= 0x1b001) || + // Enclosed Ideographic Supplement + (code >= 0x1f200 && code <= 0x1f251) || + // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff + // Emoticons 0x1f600 - 0x1f64f + (code >= 0x1f300 && code <= 0x1f64f) || + // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane + (code >= 0x20000 && code <= 0x3fffd)) ); }; @@ -2396,7 +2901,9 @@ export function stripVTControlCharacters(str: string): string { // WORKERD SPECIFIC CODE // Called from C++ on `console.log()`s to format values -export function formatLog(...args: [...values: unknown[], colors: boolean]): string { +export function formatLog( + ...args: [...values: unknown[], colors: boolean] +): string { const inspectOptions: InspectOptions = { colors: args.pop() as boolean }; try { return formatWithOptions(inspectOptions, ...args); @@ -2410,7 +2917,7 @@ function isBuiltinPrototype(proto: unknown) { const descriptor = Object.getOwnPropertyDescriptor(proto, 'constructor'); return ( descriptor !== undefined && - typeof descriptor.value === "function" && + typeof descriptor.value === 'function' && builtInObjects.has(descriptor.value.name) ); } @@ -2426,31 +2933,38 @@ function isRpcWildcardType(value: unknown) { function isEntry(value: unknown): value is [unknown, unknown] { return Array.isArray(value) && value.length === 2; } -function maybeGetEntries(value: Record): [unknown, unknown][] | undefined { +function maybeGetEntries( + value: Record +): [unknown, unknown][] | undefined { // If this value is an RPC type with a wildcard property handler (e.g. `RpcStub`), don't try to // call `entries()` on it. This won't be an `entries()` function, and calling it with `.call()` // would dispose the stub. if (isRpcWildcardType(value)) return; - const entriesFunction = value["entries"] as any; - if (typeof entriesFunction !== "function") return; + const entriesFunction = value['entries'] as any; + if (typeof entriesFunction !== 'function') return; const entriesIterator: unknown = entriesFunction.call(value); - if (typeof entriesIterator !== "object" || entriesIterator === null) return; + if (typeof entriesIterator !== 'object' || entriesIterator === null) return; if (!(Symbol.iterator in entriesIterator)) return; const entries = Array.from(entriesIterator as Iterable); if (!entries.every(isEntry)) return; return entries; } -const kEntries = Symbol("kEntries"); -function hasEntries(value: unknown): value is { [kEntries]: [unknown, unknown][] } { - return typeof value === "object" && value !== null && kEntries in value; +const kEntries = Symbol('kEntries'); +function hasEntries( + value: unknown +): value is { [kEntries]: [unknown, unknown][] } { + return typeof value === 'object' && value !== null && kEntries in value; } // Default custom inspect implementation for JSG resource types function formatJsgResourceType( this: Record, - additionalProperties: Record, + additionalProperties: Record< + string, + symbol /* value-func */ | false /* unimplemented-marker */ + >, depth: number, options: InspectOptionsStylized ): unknown { @@ -2473,16 +2987,23 @@ function formatJsgResourceType( if (additionalProperties[key] === false) continue; const value = this[key]; // Ignore function-valued and static properties - if (typeof value === "function" || this.constructor.propertyIsEnumerable(key)) continue; + if ( + typeof value === 'function' || + this.constructor.propertyIsEnumerable(key) + ) + continue; record[key] = value; } - } while (!isBuiltinPrototype(current = Object.getPrototypeOf(current))); + } while (!isBuiltinPrototype((current = Object.getPrototypeOf(current)))); // Add additional inspect-only properties as non-enumerable so they appear in square brackets for (const [key, symbol] of Object.entries(additionalProperties)) { // This is an additional property if it's not an unimplemented marker if (symbol !== false) { - Object.defineProperty(record, key, { value: this[symbol], enumerable: false }); + Object.defineProperty(record, key, { + value: this[symbol], + enumerable: false, + }); } } @@ -2498,6 +3019,6 @@ function formatJsgResourceType( } else { // Inspecting a entries object gives something like `Object(1) { 'a' => '1' }`, whereas we want // something like `Headers(1) { 'a' => '1' }`. - return `${name}${inspected.replace("Object", "")}`; + return `${name}${inspected.replace('Object', '')}`; } } diff --git a/src/node/internal/internal_path.ts b/src/node/internal/internal_path.ts index 8f954759fc7..661fb6a8a89 100644 --- a/src/node/internal/internal_path.ts +++ b/src/node/internal/internal_path.ts @@ -22,42 +22,41 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - CHAR_DOT, - CHAR_FORWARD_SLASH, -} from 'node-internal:constants'; +import { CHAR_DOT, CHAR_FORWARD_SLASH } from 'node-internal:constants'; -import { - validateObject, - validateString, -} from 'node-internal:validators'; +import { validateObject, validateString } from 'node-internal:validators'; -function isPosixPathSeparator(code : number) { +function isPosixPathSeparator(code: number) { return code === CHAR_FORWARD_SLASH; } // Resolves . and .. elements in a path with directory names -function normalizeString(path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code:number) => boolean) { +function normalizeString( + path: string, + allowAboveRoot: boolean, + separator: string, + isPathSeparator: (code: number) => boolean +) { let res = ''; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let code = 0; for (let i = 0; i <= path.length; ++i) { - if (i < path.length) - code = path.charCodeAt(i); - else if (isPathSeparator(code)) - break; - else - code = CHAR_FORWARD_SLASH; + if (i < path.length) code = path.charCodeAt(i); + else if (isPathSeparator(code)) break; + else code = CHAR_FORWARD_SLASH; if (isPathSeparator(code)) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (dots === 2) { - if (res.length < 2 || lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== CHAR_DOT || - res.charCodeAt(res.length - 2) !== CHAR_DOT) { + if ( + res.length < 2 || + lastSegmentLength !== 2 || + res.charCodeAt(res.length - 1) !== CHAR_DOT || + res.charCodeAt(res.length - 2) !== CHAR_DOT + ) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf(separator); if (lastSlashIndex === -1) { @@ -65,8 +64,7 @@ function normalizeString(path: string, allowAboveRoot: boolean, separator: strin lastSegmentLength = 0; } else { res = res.slice(0, lastSlashIndex); - lastSegmentLength = - res.length - 1 - res.lastIndexOf(separator); + lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); } lastSlash = i; dots = 0; @@ -86,8 +84,7 @@ function normalizeString(path: string, allowAboveRoot: boolean, separator: strin } else { if (res.length > 0) res += `${separator}${path.slice(lastSlash + 1, i)}`; - else - res = path.slice(lastSlash + 1, i); + else res = path.slice(lastSlash + 1, i); lastSegmentLength = i - lastSlash - 1; } lastSlash = i; @@ -101,7 +98,7 @@ function normalizeString(path: string, allowAboveRoot: boolean, separator: strin return res; } -function formatExt(ext : string) { +function formatExt(ext: string) { return ext ? `${ext[0] === '.' ? '' : '.'}${ext}` : ''; } @@ -125,11 +122,11 @@ type PathObject = { ext?: string; }; -function _format(sep : string, pathObject : PathObject) { +function _format(sep: string, pathObject: PathObject) { validateObject(pathObject, 'pathObject', {}); const dir = pathObject.dir || pathObject.root; - const base = pathObject.base || - `${pathObject.name || ''}${formatExt(pathObject.ext!)}`; + const base = + pathObject.base || `${pathObject.name || ''}${formatExt(pathObject.ext!)}`; if (!dir) { return base; } @@ -142,39 +139,39 @@ const win32 = { throw new Error('path.win32.resolve() is not implemented.'); }, - normalize(_ : string) { + normalize(_: string) { throw new Error('path.win32.normalize() is not implemented.'); }, - isAbsolute(_ : string) { + isAbsolute(_: string) { throw new Error('path.win32.isAbsolute() is not implemented.'); }, - join(..._ : string[]) { + join(..._: string[]) { throw new Error('path.win32.join() is not implemented.'); }, - relative(_0 : string, _1 : string) { + relative(_0: string, _1: string) { throw new Error('path.win32.relative() is not implemented.'); }, - toNamespacedPath(_ : string) { + toNamespacedPath(_: string) { throw new Error('path.win32.toNamedspacedPath() is not implemented.'); }, - dirname(_ : string) { + dirname(_: string) { throw new Error('path.win32.dirname() is not implemented.'); }, - basename(_0 : string, _1? : string) { + basename(_0: string, _1?: string) { throw new Error('path.win32.basename() is not implemented.'); }, - extname(_ : string) { + extname(_: string) { throw new Error('path.win32.extname() is not implemented.'); }, - format(_ : PathObject) { + format(_: PathObject) { throw new Error('path.win32.format() is not implemented.'); }, @@ -188,8 +185,8 @@ const win32 = { sep: '\\', delimiter: ';', - win32: null as Object|null, - posix: null as Object|null, + win32: null as Object | null, + posix: null as Object | null, }; const posix = { @@ -220,8 +217,12 @@ const posix = { // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path - resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', - isPosixPathSeparator); + resolvedPath = normalizeString( + resolvedPath, + !resolvedAbsolute, + '/', + isPosixPathSeparator + ); if (resolvedAbsolute) { return `/${resolvedPath}`; @@ -233,25 +234,23 @@ const posix = { * @param {string} path * @returns {string} */ - normalize(path : string) { + normalize(path: string) { validateString(path, 'path'); - if (path.length === 0) - return '.'; + if (path.length === 0) return '.'; const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; - const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; + const trailingSeparator = + path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; // Normalize the path path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); if (path.length === 0) { - if (isAbsolute) - return '/'; + if (isAbsolute) return '/'; return trailingSeparator ? './' : '.'; } - if (trailingSeparator) - path += '/'; + if (trailingSeparator) path += '/'; return isAbsolute ? `/${path}` : path; }, @@ -260,7 +259,7 @@ const posix = { * @param {string} path * @returns {boolean} */ - isAbsolute(path : string) { + isAbsolute(path: string) { validateString(path, 'path'); return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, @@ -269,22 +268,18 @@ const posix = { * @param {...string} args * @returns {string} */ - join(...args : string[]) { - if (args.length === 0) - return '.'; + join(...args: string[]) { + if (args.length === 0) return '.'; let joined; for (let i = 0; i < args.length; ++i) { const arg = args[i]; validateString(arg, 'path'); if (arg!.length > 0) { - if (joined === undefined) - joined = arg; - else - joined += `/${arg}`; + if (joined === undefined) joined = arg; + else joined += `/${arg}`; } } - if (joined === undefined) - return '.'; + if (joined === undefined) return '.'; return posix.normalize(joined); }, @@ -293,19 +288,17 @@ const posix = { * @param {string} to * @returns {string} */ - relative(from: string, to : string) { + relative(from: string, to: string) { validateString(from, 'from'); validateString(to, 'to'); - if (from === to) - return ''; + if (from === to) return ''; // Trim leading forward slashes. from = posix.resolve(from); to = posix.resolve(to); - if (from === to) - return ''; + if (from === to) return ''; const fromStart = 1; const fromEnd = from.length; @@ -314,15 +307,13 @@ const posix = { const toLen = to.length - toStart; // Compare paths to find the longest common path from root - const length = (fromLen < toLen ? fromLen : toLen); + const length = fromLen < toLen ? fromLen : toLen; let lastCommonSep = -1; let i = 0; for (; i < length; i++) { const fromCode = from.charCodeAt(fromStart + i); - if (fromCode !== to.charCodeAt(toStart + i)) - break; - else if (fromCode === CHAR_FORWARD_SLASH) - lastCommonSep = i; + if (fromCode !== to.charCodeAt(toStart + i)) break; + else if (fromCode === CHAR_FORWARD_SLASH) lastCommonSep = i; } if (i === length) { if (toLen > length) { @@ -367,7 +358,7 @@ const posix = { * @param {string} path * @returns {string} */ - toNamespacedPath(path : string) { + toNamespacedPath(path: string) { // Non-op on posix systems return path; }, @@ -376,10 +367,9 @@ const posix = { * @param {string} path * @returns {string} */ - dirname(path : string) { + dirname(path: string) { validateString(path, 'path'); - if (path.length === 0) - return '.'; + if (path.length === 0) return '.'; const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; let end = -1; let matchedSlash = true; @@ -395,10 +385,8 @@ const posix = { } } - if (end === -1) - return hasRoot ? '/' : '.'; - if (hasRoot && end === 1) - return '//'; + if (end === -1) return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) return '//'; return path.slice(0, end); }, @@ -407,18 +395,20 @@ const posix = { * @param {string} [suffix] * @returns {string} */ - basename(path : string, suffix? : string) { - if (suffix !== undefined) - validateString(suffix, 'ext'); + basename(path: string, suffix?: string) { + if (suffix !== undefined) validateString(suffix, 'ext'); validateString(path, 'path'); let start = 0; let end = -1; let matchedSlash = true; - if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) { - if (suffix === path) - return ''; + if ( + suffix !== undefined && + suffix.length > 0 && + suffix.length <= path.length + ) { + if (suffix === path) return ''; let extIdx = suffix.length - 1; let firstNonSlashEnd = -1; for (let i = path.length - 1; i >= 0; --i) { @@ -455,10 +445,8 @@ const posix = { } } - if (start === end) - end = firstNonSlashEnd; - else if (end === -1) - end = path.length; + if (start === end) end = firstNonSlashEnd; + else if (end === -1) end = path.length; return path.slice(start, end); } for (let i = path.length - 1; i >= 0; --i) { @@ -477,8 +465,7 @@ const posix = { } } - if (end === -1) - return ''; + if (end === -1) return ''; return path.slice(start, end); }, @@ -486,7 +473,7 @@ const posix = { * @param {string} path * @returns {string} */ - extname(path : string) { + extname(path: string) { validateString(path, 'path'); let startDot = -1; let startPart = 0; @@ -514,10 +501,8 @@ const posix = { } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension - if (startDot === -1) - startDot = i; - else if (preDotState !== 1) - preDotState = 1; + if (startDot === -1) startDot = i; + else if (preDotState !== 1) preDotState = 1; } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension @@ -525,14 +510,14 @@ const posix = { } } - if (startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && - startDot === end - 1 && - startDot === startPart + 1)) { + if ( + startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) + ) { return ''; } return path.slice(startDot, end); @@ -550,14 +535,12 @@ const posix = { * ext: string; * }} */ - parse(path: string) : PathObject { + parse(path: string): PathObject { validateString(path, 'path'); const ret = { root: '', dir: '', base: '', ext: '', name: '' }; - if (path.length === 0) - return ret; - const isAbsolute = - path.charCodeAt(0) === CHAR_FORWARD_SLASH; + if (path.length === 0) return ret; + const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; let start; if (isAbsolute) { ret.root = '/'; @@ -595,10 +578,8 @@ const posix = { } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension - if (startDot === -1) - startDot = i; - else if (preDotState !== 1) - preDotState = 1; + if (startDot === -1) startDot = i; + else if (preDotState !== 1) preDotState = 1; } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension @@ -608,13 +589,15 @@ const posix = { if (end !== -1) { const start = startPart === 0 && isAbsolute ? 1 : startPart; - if (startDot === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && + if ( + startDot === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && startDot === end - 1 && - startDot === startPart + 1)) { + startDot === startPart + 1) + ) { ret.base = ret.name = path.slice(start, end); } else { ret.name = path.slice(start, startDot); @@ -623,10 +606,8 @@ const posix = { } } - if (startPart > 0) - ret.dir = path.slice(0, startPart - 1); - else if (isAbsolute) - ret.dir = '/'; + if (startPart > 0) ret.dir = path.slice(0, startPart - 1); + else if (isAbsolute) ret.dir = '/'; return ret; }, @@ -637,8 +618,8 @@ const posix = { sep: '/', delimiter: ':', - win32: null as Object|null, - posix: null as Object|null, + win32: null as Object | null, + posix: null as Object | null, }; posix.win32 = win32.win32 = win32; diff --git a/src/node/internal/internal_stringdecoder.ts b/src/node/internal/internal_stringdecoder.ts index 7ded97463a5..52f9300d35f 100644 --- a/src/node/internal/internal_stringdecoder.ts +++ b/src/node/internal/internal_stringdecoder.ts @@ -63,10 +63,10 @@ export interface StringDecoder { readonly lastChar: Uint8Array; readonly lastNeed: number; readonly lastTotal: number; - new (encoding? : string): StringDecoder; - write(buf: ArrayBufferView|DataView|string): string; - end(buf?: ArrayBufferView|DataView|string): string; - text(buf: ArrayBufferView|DataView|string, offset?: number): string; + new (encoding?: string): StringDecoder; + write(buf: ArrayBufferView | DataView | string): string; + end(buf?: ArrayBufferView | DataView | string): string; + text(buf: ArrayBufferView | DataView | string, offset?: number): string; new (encoding?: string): StringDecoder; } @@ -84,7 +84,10 @@ export function StringDecoder(this: StringDecoder, encoding: string = 'utf8') { this.encoding = encodings[normalizedEncoding]!; } -function write(this: StringDecoder, buf: ArrayBufferView|DataView|string): string { +function write( + this: StringDecoder, + buf: ArrayBufferView | DataView | string +): string { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } @@ -92,15 +95,20 @@ function write(this: StringDecoder, buf: ArrayBufferView|DataView|string): strin return buf; } if (!ArrayBuffer.isView(buf)) { - throw new ERR_INVALID_ARG_TYPE('buf', [ - 'Buffer', 'TypedArray', 'DataView', 'string' - ], buf); + throw new ERR_INVALID_ARG_TYPE( + 'buf', + ['Buffer', 'TypedArray', 'DataView', 'string'], + buf + ); } const buffer = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); return bufferUtil.decode(buffer, (this as InternalDecoder)[kNativeDecoder]); } -function end(this: StringDecoder, buf?: ArrayBufferView|DataView|string): string { +function end( + this: StringDecoder, + buf?: ArrayBufferView | DataView | string +): string { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } @@ -114,7 +122,11 @@ function end(this: StringDecoder, buf?: ArrayBufferView|DataView|string): string return ret; } -function text(this: StringDecoder, buf: ArrayBufferView|DataView|string, offset?: number) : string { +function text( + this: StringDecoder, + buf: ArrayBufferView | DataView | string, + offset?: number +): string { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } @@ -130,17 +142,19 @@ StringDecoder.prototype.text = text; Object.defineProperties(StringDecoder.prototype, { lastChar: { enumerable: true, - get(this: StringDecoder) : Buffer { + get(this: StringDecoder): Buffer { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } return (this as InternalDecoder)[kNativeDecoder].subarray( - kIncompleteCharactersStart, kIncompleteCharactersEnd) as Buffer; + kIncompleteCharactersStart, + kIncompleteCharactersEnd + ) as Buffer; }, }, lastNeed: { enumerable: true, - get(this: StringDecoder) : number { + get(this: StringDecoder): number { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } @@ -149,16 +163,18 @@ Object.defineProperties(StringDecoder.prototype, { }, lastTotal: { enumerable: true, - get(this: StringDecoder) : number { + get(this: StringDecoder): number { if ((this as InternalDecoder)[kNativeDecoder] === undefined) { throw new ERR_INVALID_THIS('StringDecoder'); } - return (this as InternalDecoder)[kNativeDecoder][kBufferedBytes]! + - (this as InternalDecoder)[kNativeDecoder][kMissingBytes]!; + return ( + (this as InternalDecoder)[kNativeDecoder][kBufferedBytes]! + + (this as InternalDecoder)[kNativeDecoder][kMissingBytes]! + ); }, }, }); export default { - StringDecoder + StringDecoder, }; diff --git a/src/node/internal/internal_types.ts b/src/node/internal/internal_types.ts index e77907a67be..304c02b147b 100644 --- a/src/node/internal/internal_types.ts +++ b/src/node/internal/internal_types.ts @@ -23,7 +23,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -import internal from "node-internal:util"; +import internal from 'node-internal:util'; export function isCryptoKey(value: unknown): boolean { return value instanceof CryptoKey; @@ -45,7 +45,8 @@ export const isDataView = internal.isDataView.bind(internal); export const isExternal = internal.isExternal.bind(internal); export const isMap = internal.isMap.bind(internal); export const isMapIterator = internal.isMapIterator.bind(internal); -export const isModuleNamespaceObject = internal.isModuleNamespaceObject.bind(internal); +export const isModuleNamespaceObject = + internal.isModuleNamespaceObject.bind(internal); export const isNativeError = internal.isNativeError.bind(internal); export const isPromise = internal.isPromise.bind(internal); export const isProxy = internal.isProxy.bind(internal); diff --git a/src/node/internal/internal_utils.ts b/src/node/internal/internal_utils.ts index 54019ed969c..16605410934 100644 --- a/src/node/internal/internal_utils.ts +++ b/src/node/internal/internal_utils.ts @@ -32,83 +32,86 @@ import type { Encoding } from 'node-internal:buffer'; const { UTF8, UTF16LE, HEX, ASCII, BASE64, BASE64URL, LATIN1 } = bufferUtil; -export function normalizeEncoding(enc?: string) : Encoding | undefined { - if (enc == null || - enc === "utf8" || - enc === "utf-8" || - enc === "UTF8" || - enc === "UTF-8") return UTF8; +export function normalizeEncoding(enc?: string): Encoding | undefined { + if ( + enc == null || + enc === 'utf8' || + enc === 'utf-8' || + enc === 'UTF8' || + enc === 'UTF-8' + ) + return UTF8; return slowCases(enc); } -export function slowCases(enc: string) : Encoding | undefined { +export function slowCases(enc: string): Encoding | undefined { switch (enc.length) { case 4: - if (enc === "UTF8") return UTF8; - if (enc === "ucs2" || enc === "UCS2") return UTF16LE; + if (enc === 'UTF8') return UTF8; + if (enc === 'ucs2' || enc === 'UCS2') return UTF16LE; enc = `${enc}`.toLowerCase(); - if (enc === "utf8") return UTF8; - if (enc === "ucs2") return UTF16LE; + if (enc === 'utf8') return UTF8; + if (enc === 'ucs2') return UTF16LE; break; case 3: - if ( - enc === "hex" || enc === "HEX" || - `${enc}`.toLowerCase() === "hex" - ) { + if (enc === 'hex' || enc === 'HEX' || `${enc}`.toLowerCase() === 'hex') { return HEX; } break; case 5: - if (enc === "ascii") return ASCII; - if (enc === "ucs-2") return UTF16LE; - if (enc === "UTF-8") return UTF8; - if (enc === "ASCII") return ASCII; - if (enc === "UCS-2") return UTF16LE; + if (enc === 'ascii') return ASCII; + if (enc === 'ucs-2') return UTF16LE; + if (enc === 'UTF-8') return UTF8; + if (enc === 'ASCII') return ASCII; + if (enc === 'UCS-2') return UTF16LE; enc = `${enc}`.toLowerCase(); - if (enc === "utf-8") return UTF8; - if (enc === "ascii") return ASCII; - if (enc === "ucs-2") return UTF16LE; + if (enc === 'utf-8') return UTF8; + if (enc === 'ascii') return ASCII; + if (enc === 'ucs-2') return UTF16LE; break; case 6: - if (enc === "base64") return BASE64; - if (enc === "latin1" || enc === "binary") return LATIN1; - if (enc === "BASE64") return BASE64; - if (enc === "LATIN1" || enc === "BINARY") return LATIN1; + if (enc === 'base64') return BASE64; + if (enc === 'latin1' || enc === 'binary') return LATIN1; + if (enc === 'BASE64') return BASE64; + if (enc === 'LATIN1' || enc === 'BINARY') return LATIN1; enc = `${enc}`.toLowerCase(); - if (enc === "base64") return BASE64; - if (enc === "latin1" || enc === "binary") return LATIN1; + if (enc === 'base64') return BASE64; + if (enc === 'latin1' || enc === 'binary') return LATIN1; break; case 7: if ( - enc === "utf16le" || enc === "UTF16LE" || - `${enc}`.toLowerCase() === "utf16le" + enc === 'utf16le' || + enc === 'UTF16LE' || + `${enc}`.toLowerCase() === 'utf16le' ) { return UTF16LE; } break; case 8: if ( - enc === "utf-16le" || enc === "UTF-16LE" || - `${enc}`.toLowerCase() === "utf-16le" + enc === 'utf-16le' || + enc === 'UTF-16LE' || + `${enc}`.toLowerCase() === 'utf-16le' ) { return UTF16LE; } break; case 9: if ( - enc === "base64url" || enc === "BASE64URL" || - `${enc}`.toLowerCase() === "base64url" + enc === 'base64url' || + enc === 'BASE64URL' || + `${enc}`.toLowerCase() === 'base64url' ) { return BASE64URL; } break; default: - if (enc === "") return UTF8; + if (enc === '') return UTF8; } return undefined; } -export function spliceOne(list: (string|undefined)[], index: number) { +export function spliceOne(list: (string | undefined)[], index: number) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } @@ -124,29 +127,30 @@ export const SKIP_SYMBOLS = 16; const isNumericLookup: Record = {}; export function isArrayIndex(value: unknown): value is number | string { switch (typeof value) { - case "number": + case 'number': return value >= 0 && (value | 0) === value; - case "string": { + case 'string': { const result = isNumericLookup[value]; if (result !== void 0) { return result; } const length = value.length; if (length === 0) { - return isNumericLookup[value] = false; + return (isNumericLookup[value] = false); } let ch = 0; let i = 0; for (; i < length; ++i) { ch = value.charCodeAt(i); if ( - i === 0 && ch === 0x30 && length > 1 /* must not start with 0 */ || - ch < 0x30 /* 0 */ || ch > 0x39 /* 9 */ + (i === 0 && ch === 0x30 && length > 1) /* must not start with 0 */ || + ch < 0x30 /* 0 */ || + ch > 0x39 /* 9 */ ) { - return isNumericLookup[value] = false; + return (isNumericLookup[value] = false); } } - return isNumericLookup[value] = true; + return (isNumericLookup[value] = true); } default: return false; @@ -156,7 +160,7 @@ export function isArrayIndex(value: unknown): value is number | string { export function getOwnNonIndexProperties( // deno-lint-ignore ban-types obj: object, - filter: number, + filter: number ): (string | symbol)[] { let allProperties = [ ...Object.getOwnPropertyNames(obj), @@ -186,10 +190,10 @@ export function getOwnNonIndexProperties( if (filter & ONLY_CONFIGURABLE && !desc.configurable) { continue; } - if (filter & SKIP_STRINGS && typeof key === "string") { + if (filter & SKIP_STRINGS && typeof key === 'string') { continue; } - if (filter & SKIP_SYMBOLS && typeof key === "symbol") { + if (filter & SKIP_SYMBOLS && typeof key === 'symbol') { continue; } result.push(key); @@ -205,7 +209,7 @@ export function createDeferredPromise() { const promise = new Promise((res, rej) => { resolve = res; reject = rej; - }) + }); return { promise, resolve, diff --git a/src/node/internal/internal_zlib.ts b/src/node/internal/internal_zlib.ts index 275c13a631c..8654da1e501 100644 --- a/src/node/internal/internal_zlib.ts +++ b/src/node/internal/internal_zlib.ts @@ -14,22 +14,25 @@ function crc32(data: ArrayBufferView | string, value: number = 0): number { return zlibUtil.crc32(data, value); } - -const constPrefix = 'CONST_'; +const constPrefix = 'CONST_'; const constants = {}; // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -Object.defineProperties(constants, Object.fromEntries(Object.entries(Object.getPrototypeOf(zlibUtil)) - .filter(([k,]) => k.startsWith(constPrefix)) - .map(([k, v]) => [k.slice(constPrefix.length), { - value: v, - writable: false, - configurable: false, - enumerable: true - }]) -)); - -export { - crc32, +Object.defineProperties( constants, -} + Object.fromEntries( + Object.entries(Object.getPrototypeOf(zlibUtil)) + .filter(([k]) => k.startsWith(constPrefix)) + .map(([k, v]) => [ + k.slice(constPrefix.length), + { + value: v, + writable: false, + configurable: false, + enumerable: true, + }, + ]) + ) +); + +export { crc32, constants }; diff --git a/src/node/internal/mock.js b/src/node/internal/mock.js index 7733fd7a938..b25546d3cf8 100644 --- a/src/node/internal/mock.js +++ b/src/node/internal/mock.js @@ -176,13 +176,13 @@ export class MockTracker { * @returns {ProxyConstructor} The mock function tracker. */ fn( - original = function() {}, + original = function () {}, implementation = original, - options = kEmptyObject, + options = kEmptyObject ) { if (original !== null && typeof original === 'object') { options = original; - original = function() {}; + original = function () {}; implementation = original; } else if (implementation !== null && typeof implementation === 'object') { options = implementation; @@ -194,7 +194,11 @@ export class MockTracker { validateObject(options, 'options'); const { times = Infinity } = options; validateTimes(times, 'options.times'); - const ctx = new MockFunctionContext(implementation, { __proto__: null, original }, times); + const ctx = new MockFunctionContext( + implementation, + { __proto__: null, original }, + times + ); return this.#setupMock(ctx, original); } @@ -213,7 +217,7 @@ export class MockTracker { objectOrFunction, methodName, implementation = kDefaultFunction, - options = kEmptyObject, + options = kEmptyObject ) { validateStringOrSymbol(methodName, 'methodName'); if (typeof objectOrFunction !== 'function') { @@ -228,11 +232,7 @@ export class MockTracker { validateFunction(implementation, 'implementation'); validateObject(options, 'options'); - const { - getter = false, - setter = false, - times = Infinity, - } = options; + const { getter = false, setter = false, times = Infinity } = options; validateBoolean(getter, 'options.getter'); validateBoolean(setter, 'options.setter'); @@ -240,7 +240,9 @@ export class MockTracker { if (setter && getter) { throw new ERR_INVALID_ARG_VALUE( - 'options.setter', setter, "cannot be used with 'options.getter'", + 'options.setter', + setter, + "cannot be used with 'options.getter'" ); } const descriptor = findMethodOnPrototypeChain(objectOrFunction, methodName); @@ -257,13 +259,20 @@ export class MockTracker { if (typeof original !== 'function') { throw new ERR_INVALID_ARG_VALUE( - 'methodName', original, 'must be a method', + 'methodName', + original, + 'must be a method' ); } - const restore = { __proto__: null, descriptor, object: objectOrFunction, methodName }; - const impl = implementation === kDefaultFunction ? - original : implementation; + const restore = { + __proto__: null, + descriptor, + object: objectOrFunction, + methodName, + }; + const impl = + implementation === kDefaultFunction ? original : implementation; const ctx = new MockFunctionContext(impl, restore, times); const mock = this.#setupMock(ctx, original); const mockDescriptor = { @@ -304,7 +313,7 @@ export class MockTracker { object, methodName, implementation = kDefaultFunction, - options = kEmptyObject, + options = kEmptyObject ) { if (implementation !== null && typeof implementation === 'object') { options = implementation; @@ -317,7 +326,9 @@ export class MockTracker { if (getter === false) { throw new ERR_INVALID_ARG_VALUE( - 'options.getter', getter, 'cannot be false', + 'options.getter', + getter, + 'cannot be false' ); } @@ -344,7 +355,7 @@ export class MockTracker { object, methodName, implementation = kDefaultFunction, - options = kEmptyObject, + options = kEmptyObject ) { if (implementation !== null && typeof implementation === 'object') { options = implementation; @@ -357,7 +368,9 @@ export class MockTracker { if (setter === false) { throw new ERR_INVALID_ARG_VALUE( - 'options.setter', setter, 'cannot be false', + 'options.setter', + setter, + 'cannot be false' ); } diff --git a/src/node/internal/process.ts b/src/node/internal/process.ts index 2c830e56508..5aa13bc36b6 100644 --- a/src/node/internal/process.ts +++ b/src/node/internal/process.ts @@ -8,19 +8,17 @@ // queue. /* eslint-disable */ -import { - validateObject, -} from 'node-internal:validators'; +import { validateObject } from 'node-internal:validators'; -import { - ERR_INVALID_ARG_VALUE, -} from 'node-internal:internal_errors' +import { ERR_INVALID_ARG_VALUE } from 'node-internal:internal_errors'; import { default as utilImpl } from 'node-internal:util'; export function nextTick(cb: Function, ...args: unknown[]) { - queueMicrotask(() => { cb(...args); }); -}; + queueMicrotask(() => { + cb(...args); + }); +} // Note that there is no process-level environment in workers so the process.env // object is initially empty. This is different from Node.js where process.env @@ -28,43 +26,65 @@ export function nextTick(cb: Function, ...args: unknown[]) { // for the worker are accessible from the env argument passed into the fetch // handler and have no impact here. -export const env = new Proxy({}, { - // Per Node.js rules. process.env values must be coerced to strings. - // When defined using defineProperty, the property descriptor must be writable, - // configurable, and enumerable using just a falsy check. Getters and setters - // are not permitted. - set(obj: object, prop: PropertyKey, value: any) { - return Reflect.set(obj, prop, `${value}`); - }, - defineProperty(obj: object, prop: PropertyKey, descriptor: PropertyDescriptor) { - validateObject(descriptor, 'descriptor', {}); - if (Reflect.has(descriptor, 'get') || Reflect.has(descriptor, 'set')) { - throw new ERR_INVALID_ARG_VALUE('descriptor', descriptor, - 'process.env value must not have getter/setter'); - } - if (!descriptor.configurable) { - throw new ERR_INVALID_ARG_VALUE('descriptor.configurable', descriptor, - 'process.env value must be configurable') - } - if (!descriptor.enumerable) { - throw new ERR_INVALID_ARG_VALUE('descriptor.enumerable', descriptor, - 'process.env value must be enumerable') - } - if (!descriptor.writable) { - throw new ERR_INVALID_ARG_VALUE('descriptor.writable', descriptor, - 'process.env value must be writable') - } - if (Reflect.has(descriptor, 'value')) { - Reflect.set(descriptor, 'value', `${descriptor.value}`); - } else { - throw new ERR_INVALID_ARG_VALUE('descriptor.value', descriptor, - 'process.env value must be specified explicitly'); - } - return Reflect.defineProperty(obj, prop, descriptor); +export const env = new Proxy( + {}, + { + // Per Node.js rules. process.env values must be coerced to strings. + // When defined using defineProperty, the property descriptor must be writable, + // configurable, and enumerable using just a falsy check. Getters and setters + // are not permitted. + set(obj: object, prop: PropertyKey, value: any) { + return Reflect.set(obj, prop, `${value}`); + }, + defineProperty( + obj: object, + prop: PropertyKey, + descriptor: PropertyDescriptor + ) { + validateObject(descriptor, 'descriptor', {}); + if (Reflect.has(descriptor, 'get') || Reflect.has(descriptor, 'set')) { + throw new ERR_INVALID_ARG_VALUE( + 'descriptor', + descriptor, + 'process.env value must not have getter/setter' + ); + } + if (!descriptor.configurable) { + throw new ERR_INVALID_ARG_VALUE( + 'descriptor.configurable', + descriptor, + 'process.env value must be configurable' + ); + } + if (!descriptor.enumerable) { + throw new ERR_INVALID_ARG_VALUE( + 'descriptor.enumerable', + descriptor, + 'process.env value must be enumerable' + ); + } + if (!descriptor.writable) { + throw new ERR_INVALID_ARG_VALUE( + 'descriptor.writable', + descriptor, + 'process.env value must be writable' + ); + } + if (Reflect.has(descriptor, 'value')) { + Reflect.set(descriptor, 'value', `${descriptor.value}`); + } else { + throw new ERR_INVALID_ARG_VALUE( + 'descriptor.value', + descriptor, + 'process.env value must be specified explicitly' + ); + } + return Reflect.defineProperty(obj, prop, descriptor); + }, } -}); +); -export function getBuiltinModule(id: string) : any { +export function getBuiltinModule(id: string): any { return utilImpl.getBuiltinModule(id); } diff --git a/src/node/internal/streams_adapters.js b/src/node/internal/streams_adapters.js index b29feb892ae..52f4cb8b8ae 100644 --- a/src/node/internal/streams_adapters.js +++ b/src/node/internal/streams_adapters.js @@ -25,17 +25,11 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - Readable, -} from 'node-internal:streams_readable'; +import { Readable } from 'node-internal:streams_readable'; -import { - Writable, -} from 'node-internal:streams_writable'; +import { Writable } from 'node-internal:streams_writable'; -import { - Duplex, -} from 'node-internal:streams_duplex'; +import { Duplex } from 'node-internal:streams_duplex'; import { destroy, @@ -46,9 +40,7 @@ import { isWritableEnded, } from 'node-internal:streams_util'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { ERR_INVALID_ARG_TYPE, @@ -62,10 +54,7 @@ import { normalizeEncoding, } from 'node-internal:internal_utils'; -import { - validateBoolean, - validateObject, -} from 'node-internal:validators'; +import { validateBoolean, validateObject } from 'node-internal:validators'; import * as process from 'node-internal:process'; @@ -89,7 +78,7 @@ export function newWritableStreamFromStreamWritable(streamWritable) { throw new ERR_INVALID_ARG_TYPE( 'streamWritable', 'stream.Writable', - streamWritable, + streamWritable ); } @@ -100,18 +89,16 @@ export function newWritableStreamFromStreamWritable(streamWritable) { } const highWaterMark = streamWritable.writableHighWaterMark; - const strategy = - streamWritable.writableObjectMode ? - new CountQueuingStrategy({ highWaterMark }) : - { highWaterMark }; + const strategy = streamWritable.writableObjectMode + ? new CountQueuingStrategy({ highWaterMark }) + : { highWaterMark }; let controller; let backpressurePromise; let closed; function onDrain() { - if (backpressurePromise !== undefined) - backpressurePromise.resolve(); + if (backpressurePromise !== undefined) backpressurePromise.resolve(); } const cleanup = finished(streamWritable, (error) => { @@ -125,8 +112,7 @@ export function newWritableStreamFromStreamWritable(streamWritable) { // that happen to emit an error event again after finished is called. streamWritable.on('error', () => {}); if (error != null) { - if (backpressurePromise !== undefined) - backpressurePromise.reject(error); + if (backpressurePromise !== undefined) backpressurePromise.reject(error); // If closed is not undefined, the error is happening // after the WritableStream close has already started. // We need to reject it here. @@ -150,33 +136,38 @@ export function newWritableStreamFromStreamWritable(streamWritable) { streamWritable.on('drain', onDrain); - return new WritableStream({ - start(c) { controller = c; }, + return new WritableStream( + { + start(c) { + controller = c; + }, - async write(chunk) { - if (streamWritable.writableNeedDrain || !streamWritable.write(chunk)) { - backpressurePromise = createDeferredPromise(); - return backpressurePromise.promise.finally(() => { - backpressurePromise = undefined; - }); - } - }, + async write(chunk) { + if (streamWritable.writableNeedDrain || !streamWritable.write(chunk)) { + backpressurePromise = createDeferredPromise(); + return backpressurePromise.promise.finally(() => { + backpressurePromise = undefined; + }); + } + }, - abort(reason) { - destroy(streamWritable, reason); - }, + abort(reason) { + destroy(streamWritable, reason); + }, - close() { - if (closed === undefined && !isWritableEnded(streamWritable)) { - closed = createDeferredPromise(); - streamWritable.end(); - return closed.promise; - } + close() { + if (closed === undefined && !isWritableEnded(streamWritable)) { + closed = createDeferredPromise(); + streamWritable.end(); + return closed.promise; + } - controller = undefined; - return Promise.resolve(); + controller = undefined; + return Promise.resolve(); + }, }, - }, strategy); + strategy + ); } /** @@ -189,12 +180,16 @@ export function newWritableStreamFromStreamWritable(streamWritable) { * }} [options] * @returns {Writable} */ -export function newStreamWritableFromWritableStream(writableStream, options = {}) { +export function newStreamWritableFromWritableStream( + writableStream, + options = {} +) { if (!(writableStream instanceof WritableStream)) { throw new ERR_INVALID_ARG_TYPE( 'writableStream', 'WritableStream', - writableStream); + writableStream + ); } validateObject(options, 'options'); @@ -233,10 +228,11 @@ export function newStreamWritableFromWritableStream(writableStream, options = {} } writer.ready.then(() => { - return Promise.all(chunks.map((data) => writer.write(data))) - .then(done, done); - }, - done); + return Promise.all(chunks.map((data) => writer.write(data))).then( + done, + done + ); + }, done); }, write(chunk, encoding, callback) { @@ -265,8 +261,7 @@ export function newStreamWritableFromWritableStream(writableStream, options = {} writer.ready.then(() => { return writer.write(chunk).then(done, done); - }, - done); + }, done); }, destroy(error, callback) { @@ -279,7 +274,9 @@ export function newStreamWritableFromWritableStream(writableStream, options = {} // thrown we don't want those to cause an unhandled // rejection. Let's just escape the promise and // handle it separately. - process.nextTick(() => { throw error; }); + process.nextTick(() => { + throw error; + }); } } @@ -315,19 +312,21 @@ export function newStreamWritableFromWritableStream(writableStream, options = {} }, }); - writer.closed.then(() => { - // If the WritableStream closes before the stream.Writable has been - // ended, we signal an error on the stream.Writable. - closed = true; - if (!isWritableEnded(writable)) - destroy(writable, new ERR_STREAM_PREMATURE_CLOSE()); - }, - (error) => { - // If the WritableStream errors before the stream.Writable has been - // destroyed, signal an error on the stream.Writable. - closed = true; - destroy(writable, error); - }); + writer.closed.then( + () => { + // If the WritableStream closes before the stream.Writable has been + // ended, we signal an error on the stream.Writable. + closed = true; + if (!isWritableEnded(writable)) + destroy(writable, new ERR_STREAM_PREMATURE_CLOSE()); + }, + (error) => { + // If the WritableStream errors before the stream.Writable has been + // destroyed, signal an error on the stream.Writable. + closed = true; + destroy(writable, error); + } + ); return writable; } @@ -340,7 +339,10 @@ export function newStreamWritableFromWritableStream(writableStream, options = {} * }} [options] * @returns {ReadableStream} */ -export function newReadableStreamFromStreamReadable(streamReadable, options = {}) { +export function newReadableStreamFromStreamReadable( + streamReadable, + options = {} +) { // Not using the internal/streams/utils isReadableNodeStream utility // here because it will return false if streamReadable is a Duplex // whose readable option is false. For a Duplex that is not readable, @@ -349,7 +351,8 @@ export function newReadableStreamFromStreamReadable(streamReadable, options = {} throw new ERR_INVALID_ARG_TYPE( 'streamReadable', 'stream.Readable', - streamReadable); + streamReadable + ); } if (isDestroyed(streamReadable) || !isReadable(streamReadable)) { @@ -363,8 +366,7 @@ export function newReadableStreamFromStreamReadable(streamReadable, options = {} const evaluateStrategyOrFallback = (strategy) => { // If there is a strategy available, use it - if (strategy) - return strategy; + if (strategy) return strategy; if (objectMode) { // When running in objectMode explicitly but no strategy, we just fall @@ -385,11 +387,9 @@ export function newReadableStreamFromStreamReadable(streamReadable, options = {} function onData(chunk) { // Copy the Buffer to detach it from the pool. - if (Buffer.isBuffer(chunk) && !objectMode) - chunk = new Uint8Array(chunk); + if (Buffer.isBuffer(chunk) && !objectMode) chunk = new Uint8Array(chunk); controller.enqueue(chunk); - if (controller.desiredSize <= 0) - streamReadable.pause(); + if (controller.desiredSize <= 0) streamReadable.pause(); } streamReadable.pause(); @@ -404,22 +404,28 @@ export function newReadableStreamFromStreamReadable(streamReadable, options = {} // This is a protection against non-standard, legacy streams // that happen to emit an error event again after finished is called. streamReadable.on('error', () => {}); - if (error) - return controller.error(error); + if (error) return controller.error(error); controller.close(); }); streamReadable.on('data', onData); - return new ReadableStream({ - start(c) { controller = c; }, + return new ReadableStream( + { + start(c) { + controller = c; + }, - pull() { streamReadable.resume(); }, + pull() { + streamReadable.resume(); + }, - cancel(reason) { - destroy(streamReadable, reason); + cancel(reason) { + destroy(streamReadable, reason); + }, }, - }, strategy); + strategy + ); } /** @@ -432,21 +438,20 @@ export function newReadableStreamFromStreamReadable(streamReadable, options = {} * }} [options] * @returns {Readable} */ -export function newStreamReadableFromReadableStream(readableStream, options = {}) { +export function newStreamReadableFromReadableStream( + readableStream, + options = {} +) { if (!(readableStream instanceof ReadableStream)) { throw new ERR_INVALID_ARG_TYPE( 'readableStream', 'ReadableStream', - readableStream); + readableStream + ); } validateObject(options, 'options'); - const { - highWaterMark, - encoding, - objectMode = false, - signal, - } = options; + const { highWaterMark, encoding, objectMode = false, signal } = options; if (encoding !== undefined && !Buffer.isEncoding(encoding)) throw new ERR_INVALID_ARG_VALUE(encoding, 'options.encoding'); @@ -462,15 +467,17 @@ export function newStreamReadableFromReadableStream(readableStream, options = {} signal, read() { - reader.read().then((chunk) => { - if (chunk.done) { - // Value should always be undefined here. - readable.push(null); - } else { - readable.push(chunk.value); - } - }, - (error) => destroy(readable, error)); + reader.read().then( + (chunk) => { + if (chunk.done) { + // Value should always be undefined here. + readable.push(null); + } else { + readable.push(chunk.value); + } + }, + (error) => destroy(readable, error) + ); }, destroy(error, callback) { @@ -483,7 +490,9 @@ export function newStreamReadableFromReadableStream(readableStream, options = {} // thrown we don't want those to cause an unhandled // rejection. Let's just escape the promise and // handle it separately. - process.nextTick(() => { throw error; }); + process.nextTick(() => { + throw error; + }); } } @@ -495,13 +504,15 @@ export function newStreamReadableFromReadableStream(readableStream, options = {} }, }); - reader.closed.then(() => { - closed = true; - }, - (error) => { - closed = true; - destroy(readable, error); - }); + reader.closed.then( + () => { + closed = true; + }, + (error) => { + closed = true; + destroy(readable, error); + } + ); return readable; } @@ -523,8 +534,10 @@ export function newReadableWritablePairFromDuplex(duplex) { // false. Instead, we'll check the readable and writable state after // and return closed WritableStream or closed ReadableStream as // necessary. - if (typeof duplex?._writableState !== 'object' || - typeof duplex?._readableState !== 'object') { + if ( + typeof duplex?._writableState !== 'object' || + typeof duplex?._readableState !== 'object' + ) { throw new ERR_INVALID_ARG_TYPE('duplex', 'stream.Duplex', duplex); } @@ -536,21 +549,17 @@ export function newReadableWritablePairFromDuplex(duplex) { return { readable, writable }; } - const writable = - isWritable(duplex) ? - newWritableStreamFromStreamWritable(duplex) : - new WritableStream(); + const writable = isWritable(duplex) + ? newWritableStreamFromStreamWritable(duplex) + : new WritableStream(); - if (!isWritable(duplex)) - writable.close(); + if (!isWritable(duplex)) writable.close(); - const readable = - isReadable(duplex) ? - newReadableStreamFromStreamReadable(duplex) : - new ReadableStream(); + const readable = isReadable(duplex) + ? newReadableStreamFromStreamReadable(duplex) + : new ReadableStream(); - if (!isReadable(duplex)) - readable.cancel(); + if (!isReadable(duplex)) readable.cancel(); return { writable, readable }; } @@ -567,24 +576,26 @@ export function newReadableWritablePairFromDuplex(duplex) { * }} [options] * @returns {Duplex} */ -export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) { +export function newStreamDuplexFromReadableWritablePair( + pair = {}, + options = {} +) { validateObject(pair, 'pair'); - const { - readable: readableStream, - writable: writableStream, - } = pair; + const { readable: readableStream, writable: writableStream } = pair; if (!(readableStream instanceof ReadableStream)) { throw new ERR_INVALID_ARG_TYPE( 'pair.readable', 'ReadableStream', - readableStream); + readableStream + ); } if (!(writableStream instanceof WritableStream)) { throw new ERR_INVALID_ARG_TYPE( 'pair.writable', 'WritableStream', - writableStream); + writableStream + ); } validateObject(options, 'options'); @@ -630,11 +641,12 @@ export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) } writer.ready.then(() => { - return Promise.all(chunks.map((data) => { - return writer.write(data); - })).then(done, done); - }, - done); + return Promise.all( + chunks.map((data) => { + return writer.write(data); + }) + ).then(done, done); + }, done); }, write(chunk, encoding, callback) { @@ -663,8 +675,7 @@ export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) writer.ready.then(() => { return writer.write(chunk).then(done, done); - }, - done); + }, done); }, final(callback) { @@ -687,14 +698,16 @@ export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) }, read() { - reader.read().then((chunk) => { - if (chunk.done) { - duplex.push(null); - } else { - duplex.push(chunk.value); - } - }, - (error) => destroy(duplex, error)); + reader.read().then( + (chunk) => { + if (chunk.done) { + duplex.push(null); + } else { + duplex.push(chunk.value); + } + }, + (error) => destroy(duplex, error) + ); }, destroy(error, callback) { @@ -707,22 +720,22 @@ export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) // thrown we don't want those to cause an unhandled // rejection. Let's just escape the promise and // handle it separately. - process.nextTick(() => { throw error; }); + process.nextTick(() => { + throw error; + }); } } async function closeWriter() { - if (!writableClosed) - await writer.abort(error); + if (!writableClosed) await writer.abort(error); } async function closeReader() { - if (!readableClosed) - await reader.cancel(error); + if (!readableClosed) await reader.cancel(error); } if (!writableClosed || !readableClosed) { - Promise.all([ closeWriter(), closeReader() ]).then(done, done); + Promise.all([closeWriter(), closeReader()]).then(done, done); return; } @@ -730,25 +743,29 @@ export function newStreamDuplexFromReadableWritablePair(pair = {}, options = {}) }, }); - writer.closed.then(() => { - writableClosed = true; - if (!isWritableEnded(duplex)) - destroy(duplex, new ERR_STREAM_PREMATURE_CLOSE()); - }, - (error) => { - writableClosed = true; - readableClosed = true; - destroy(duplex, error); - }); + writer.closed.then( + () => { + writableClosed = true; + if (!isWritableEnded(duplex)) + destroy(duplex, new ERR_STREAM_PREMATURE_CLOSE()); + }, + (error) => { + writableClosed = true; + readableClosed = true; + destroy(duplex, error); + } + ); - reader.closed.then(() => { - readableClosed = true; - }, - (error) => { - writableClosed = true; - readableClosed = true; - destroy(duplex, error); - }); + reader.closed.then( + () => { + readableClosed = true; + }, + (error) => { + writableClosed = true; + readableClosed = true; + destroy(duplex, error); + } + ); return duplex; } diff --git a/src/node/internal/streams_compose.js b/src/node/internal/streams_compose.js index dbad148570f..7fcb983b139 100644 --- a/src/node/internal/streams_compose.js +++ b/src/node/internal/streams_compose.js @@ -26,15 +26,11 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - pipeline, -} from 'node-internal:streams_pipeline'; -import { - Duplex, -} from 'node-internal:streams_duplex'; +import { pipeline } from 'node-internal:streams_pipeline'; +import { Duplex } from 'node-internal:streams_duplex'; import { Readable as ReadableConstructor, - from + from, } from 'node-internal:streams_readable'; import { isNodeStream, @@ -69,10 +65,18 @@ export function compose(...streams) { continue; } if (n < streams.length - 1 && !isReadable(streams[n])) { - throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], 'must be readable'); + throw new ERR_INVALID_ARG_VALUE( + `streams[${n}]`, + orgStreams[n], + 'must be readable' + ); } if (n > 0 && !isWritable(streams[n])) { - throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], 'must be writable'); + throw new ERR_INVALID_ARG_VALUE( + `streams[${n}]`, + orgStreams[n], + 'must be writable' + ); } } let ondrain; @@ -101,10 +105,18 @@ export function compose(...streams) { // See, https://github.com/nodejs/node/pull/33515. d = new Duplex({ // TODO (ronag): highWaterMark? - writableObjectMode: !!(head !== null && head !== undefined && head.writableObjectMode), - readableObjectMode: !!(tail !== null && tail !== undefined && tail.writableObjectMode), + writableObjectMode: !!( + head !== null && + head !== undefined && + head.writableObjectMode + ), + readableObjectMode: !!( + tail !== null && + tail !== undefined && + tail.writableObjectMode + ), writable, - readable + readable, }); if (writable) { const w = head; @@ -175,6 +187,6 @@ export function compose(...streams) { return d; } -ReadableConstructor.prototype.compose = function(...streams) { +ReadableConstructor.prototype.compose = function (...streams) { return compose(this, ...streams); }; diff --git a/src/node/internal/streams_duplex.js b/src/node/internal/streams_duplex.js index 6a74131b174..0f4c5e676c5 100644 --- a/src/node/internal/streams_duplex.js +++ b/src/node/internal/streams_duplex.js @@ -26,22 +26,16 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - Readable, -} from 'node-internal:streams_readable'; +import { Readable } from 'node-internal:streams_readable'; -import { - Writable, -} from 'node-internal:streams_writable'; +import { Writable } from 'node-internal:streams_writable'; import { newStreamDuplexFromReadableWritablePair, newReadableWritablePairFromDuplex, } from 'node-internal:streams_adapters'; -import { - createDeferredPromise, -} from 'node-internal:internal_utils'; +import { createDeferredPromise } from 'node-internal:internal_utils'; import * as process from 'node-internal:process'; @@ -70,7 +64,8 @@ Object.setPrototypeOf(Duplex, Readable); // Allow the keys array to be GC'ed. for (let i = 0; i < keys.length; i++) { const method = keys[i]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + if (!Duplex.prototype[method]) + Duplex.prototype[method] = Writable.prototype[method]; } } @@ -101,56 +96,65 @@ export function Duplex(options) { } Object.defineProperties(Duplex.prototype, { writable: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writable') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writable'), }, writableHighWaterMark: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableHighWaterMark') + ...Object.getOwnPropertyDescriptor( + Writable.prototype, + 'writableHighWaterMark' + ), }, writableObjectMode: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableObjectMode') + ...Object.getOwnPropertyDescriptor( + Writable.prototype, + 'writableObjectMode' + ), }, writableBuffer: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableBuffer') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableBuffer'), }, writableLength: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableLength') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableLength'), }, writableFinished: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableFinished') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableFinished'), }, writableCorked: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableCorked') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableCorked'), }, writableEnded: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableEnded') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableEnded'), }, writableNeedDrain: { - ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableNeedDrain') + ...Object.getOwnPropertyDescriptor(Writable.prototype, 'writableNeedDrain'), }, destroyed: { get() { - if (this._readableState === undefined || this._writableState === undefined) { - return false + if ( + this._readableState === undefined || + this._writableState === undefined + ) { + return false; } - return this._readableState.destroyed && this._writableState.destroyed + return this._readableState.destroyed && this._writableState.destroyed; }, set(value) { // Backward compatibility, the user is explicitly // managing destroyed. if (this._readableState && this._writableState) { - this._readableState.destroyed = value - this._writableState.destroyed = value + this._readableState.destroyed = value; + this._writableState.destroyed = value; } - } - } + }, + }, }); export function fromWeb(pair, options) { - return newStreamDuplexFromReadableWritablePair(pair, options) + return newStreamDuplexFromReadableWritablePair(pair, options); } export function toWeb(duplex) { - return newReadableWritablePairFromDuplex(duplex) + return newReadableWritablePairFromDuplex(duplex); } export function from(body) { @@ -168,17 +172,25 @@ function isBlob(b) { } // This is needed for pre node 17. -class Duplexify extends (Duplex) { +class Duplexify extends Duplex { constructor(options) { super(options); // https://github.com/nodejs/node/pull/34385 - if ((options === null || options === undefined ? undefined : options.readable) === false) { + if ( + (options === null || options === undefined + ? undefined + : options.readable) === false + ) { this['_readableState'].readable = false; this['_readableState'].ended = true; this['_readableState'].endEmitted = true; } - if ((options === null || options === undefined ? undefined : options.writable) === false) { + if ( + (options === null || options === undefined + ? undefined + : options.writable) === false + ) { this['_readableState'].writable = false; this['_readableState'].ending = true; this['_readableState'].ended = true; @@ -193,18 +205,18 @@ function duplexify(body, name) { } if (isReadableNodeStream(body)) { return _duplexify({ - readable: body + readable: body, }); } if (isWritableNodeStream(body)) { return _duplexify({ - writable: body + writable: body, }); } if (isNodeStream(body)) { return _duplexify({ writable: false, - readable: false + readable: false, }); } @@ -217,14 +229,14 @@ function duplexify(body, name) { } if (typeof body === 'function') { - const { value, write, final, destroy } = fromAsyncGen(body) + const { value, write, final, destroy } = fromAsyncGen(body); if (isIterable(value)) { return Readable.from(Duplexify, value, { // TODO (ronag): highWaterMark? objectMode: true, write, final, - destroy + destroy, }); } const then = value.then; @@ -233,12 +245,12 @@ function duplexify(body, name) { const promise = Reflect.apply(then, value, [ (val) => { if (val != null) { - throw new ERR_INVALID_RETURN_VALUE('nully', 'body', val) + throw new ERR_INVALID_RETURN_VALUE('nully', 'body', val); } }, (err) => { - destroyer(d, err) - } + destroyer(d, err); + }, ]); return (d = new Duplexify({ @@ -249,17 +261,21 @@ function duplexify(body, name) { final(cb) { final(async () => { try { - await promise + await promise; process.nextTick(cb, null); } catch (err) { process.nextTick(cb, err); } - }) + }); }, - destroy + destroy, })); } - throw new ERR_INVALID_RETURN_VALUE('Iterable, AsyncIterable or AsyncFunction', name, value) + throw new ERR_INVALID_RETURN_VALUE( + 'Iterable, AsyncIterable or AsyncFunction', + name, + value + ); } if (isBlob(body)) { return duplexify(body.arrayBuffer(), name); @@ -268,8 +284,8 @@ function duplexify(body, name) { return Readable.from(Duplexify, body, { // TODO (ronag): highWaterMark? objectMode: true, - writable: false - }) + writable: false, + }); } if ( @@ -280,12 +296,16 @@ function duplexify(body, name) { } if ( - typeof (body === null || body === undefined ? undefined : body.writable) === 'object' || - typeof (body === null || body === undefined ? undefined : body.readable) === 'object' + typeof (body === null || body === undefined ? undefined : body.writable) === + 'object' || + typeof (body === null || body === undefined ? undefined : body.readable) === + 'object' ) { const readable = body !== null && body !== undefined && body.readable - ? isReadableNodeStream(body === null || body === undefined ? undefined : body.readable) + ? isReadableNodeStream( + body === null || body === undefined ? undefined : body.readable + ) ? body === null || body === undefined ? undefined : body.readable @@ -293,7 +313,9 @@ function duplexify(body, name) { : undefined; const writable = body !== null && body !== undefined && body.writable - ? isWritableNodeStream(body === null || body === undefined ? undefined : body.writable) + ? isWritableNodeStream( + body === null || body === undefined ? undefined : body.writable + ) ? body === null || body === undefined ? undefined : body.writable @@ -301,10 +323,10 @@ function duplexify(body, name) { : undefined; return _duplexify({ readable, - writable + writable, }); } - const then = body?.then + const then = body?.then; if (typeof then === 'function') { let d; Reflect.apply(then, body, [ @@ -316,13 +338,13 @@ function duplexify(body, name) { }, (err) => { destroyer(d, err); - } + }, ]); return (d = new Duplexify({ objectMode: true, writable: false, - read() {} + read() {}, })); } throw new ERR_INVALID_ARG_TYPE( @@ -336,16 +358,16 @@ function duplexify(body, name) { 'AsyncIterable', 'Function', '{ readable, writable } pair', - 'Promise' + 'Promise', ], body - ) + ); } function fromAsyncGen(fn) { - let { promise, resolve } = createDeferredPromise() - const ac = new AbortController() - const signal = ac.signal + let { promise, resolve } = createDeferredPromise(); + const ac = new AbortController(); + const signal = ac.signal; const value = fn( (async function* () { while (true) { @@ -356,14 +378,14 @@ function fromAsyncGen(fn) { if (done) return; if (signal.aborted) throw new AbortError(undefined, { - cause: signal.reason + cause: signal.reason, }); ({ promise, resolve } = createDeferredPromise()); yield chunk; } })(), { - signal + signal, } ); return { @@ -374,26 +396,29 @@ function fromAsyncGen(fn) { _resolve({ chunk, done: false, - cb - }) + cb, + }); }, final(cb) { const _resolve = resolve; resolve = null; - (_resolve)({ + _resolve({ done: true, - cb + cb, }); }, destroy(err, cb) { ac.abort(); cb(err); - } - } + }, + }; } function _duplexify(pair) { - const r = pair.readable && typeof pair.readable.read !== 'function' ? Readable.wrap(pair.readable) : pair.readable; + const r = + pair.readable && typeof pair.readable.read !== 'function' + ? Readable.wrap(pair.readable) + : pair.readable; const w = pair.writable; let readable = !!isReadable(r); let writable = !!isWritable(w); @@ -403,14 +428,14 @@ function _duplexify(pair) { let onclose; let d; function onfinished(err) { - const cb = onclose - onclose = null + const cb = onclose; + onclose = null; if (cb) { - cb(err) + cb(err); } else if (err) { - d.destroy(err) + d.destroy(err); } else if (!readable && !writable) { - d.destroy() + d.destroy(); } } @@ -419,10 +444,18 @@ function _duplexify(pair) { // See, https://github.com/nodejs/node/pull/33515. d = new Duplexify({ // TODO (ronag): highWaterMark? - readableObjectMode: !!(r !== null && r !== undefined && r.readableObjectMode), - writableObjectMode: !!(w !== null && w !== undefined && w.writableObjectMode), + readableObjectMode: !!( + r !== null && + r !== undefined && + r.readableObjectMode + ), + writableObjectMode: !!( + w !== null && + w !== undefined && + w.writableObjectMode + ), readable, - writable + writable, }); if (writable) { eos(w, (err) => { @@ -503,6 +536,6 @@ function _duplexify(pair) { destroyer(w, err); destroyer(r, err); } - } + }; return d; } diff --git a/src/node/internal/streams_legacy.js b/src/node/internal/streams_legacy.js index 53000fa26ee..f2d749fd95a 100644 --- a/src/node/internal/streams_legacy.js +++ b/src/node/internal/streams_legacy.js @@ -26,16 +26,12 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - EventEmitter, -} from 'node-internal:events'; +import { EventEmitter } from 'node-internal:events'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; export function Stream(opts) { - EventEmitter.call(this, opts||{}); + EventEmitter.call(this, opts || {}); } Object.setPrototypeOf(Stream.prototype, EventEmitter.prototype); @@ -103,16 +99,16 @@ Stream.prototype.pipe = function (dest, options) { // Allow for unix-like usage: A.pipe(B).pipe(C) return dest; -} +}; // Backwards-compat with node 0.4.x -Stream.Stream = Stream +Stream.Stream = Stream; Stream._isUint8Array = function isUint8Array(value) { return value instanceof Uint8Array; -} +}; Stream._isArrayBufferView = function isArrayBufferView(value) { return ArrayBuffer.isView(value); -} +}; Stream._uint8ArrayToBuffer = function _uint8ArrayToBuffer(chunk) { return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength); -} +}; diff --git a/src/node/internal/streams_pipeline.js b/src/node/internal/streams_pipeline.js index 15d791126f2..eb465b2573f 100644 --- a/src/node/internal/streams_pipeline.js +++ b/src/node/internal/streams_pipeline.js @@ -48,7 +48,7 @@ import { ERR_MISSING_ARGS, ERR_STREAM_DESTROYED, ERR_STREAM_PREMATURE_CLOSE, - AbortError + AbortError, } from 'node-internal:internal_errors'; import { validateFunction, @@ -64,10 +64,10 @@ function destroyer(stream, reading, writing) { stream, { readable: reading, - writable: writing + writable: writing, }, (err) => { - finished = !err + finished = !err; } ); return { @@ -76,7 +76,7 @@ function destroyer(stream, reading, writing) { finished = true; destroyerImpl(stream, err || new ERR_STREAM_DESTROYED('pipe')); }, - cleanup + cleanup, }; } @@ -95,7 +95,11 @@ function makeAsyncIterable(val) { // Legacy streams are not Iterable. return fromReadable(val); } - throw new ERR_INVALID_ARG_TYPE('val', ['Readable', 'Iterable', 'AsyncIterable'], val); + throw new ERR_INVALID_ARG_TYPE( + 'val', + ['Readable', 'Iterable', 'AsyncIterable'], + val + ); } async function* fromReadable(val) { @@ -114,7 +118,7 @@ async function pump(iterable, writable, finish, { end }) { onresolve = null; callback(); } - } + }; const wait = () => { return new Promise((resolve, reject) => { if (error) { @@ -134,7 +138,7 @@ async function pump(iterable, writable, finish, { end }) { const cleanup = eos( writable, { - readable: false + readable: false, }, resume ); @@ -182,7 +186,9 @@ export function pipelineImpl(streams, callback, opts) { function abort() { finishImpl(new AbortError()); } - outerSignal === null || outerSignal === undefined ? undefined : outerSignal.addEventListener('abort', abort); + outerSignal === null || outerSignal === undefined + ? undefined + : outerSignal.addEventListener('abort', abort); let error; let value; const destroys = []; @@ -200,7 +206,9 @@ export function pipelineImpl(streams, callback, opts) { while (destroys.length) { destroys.shift()(error); } - outerSignal === null || outerSignal === undefined ? undefined : outerSignal.removeEventListener('abort', abort); + outerSignal === null || outerSignal === undefined + ? undefined + : outerSignal.removeEventListener('abort', abort); ac.abort(); if (final) { if (!error) { @@ -214,7 +222,9 @@ export function pipelineImpl(streams, callback, opts) { const stream = streams[i]; const reading = i < streams.length - 1; const writing = i > 0; - const end = reading || (opts === null || opts === undefined ? undefined : opts.end) !== false; + const end = + reading || + (opts === null || opts === undefined ? undefined : opts.end) !== false; const isLastStream = i === streams.length - 1; if (isNodeStream(stream)) { if (end) { @@ -227,7 +237,11 @@ export function pipelineImpl(streams, callback, opts) { // Catch stream errors that occur after pipe/pump has completed. function onError(err) { - if (err && err.name !== 'AbortError' && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') { + if ( + err && + err.name !== 'AbortError' && + err.code !== 'ERR_STREAM_PREMATURE_CLOSE' + ) { finish(err); } } @@ -235,16 +249,20 @@ export function pipelineImpl(streams, callback, opts) { if (isReadable(stream) && isLastStream) { lastStreamCleanup.push(() => { stream.removeListener('error', onError); - }) + }); } } if (i === 0) { if (typeof stream === 'function') { ret = stream({ - signal + signal, }); if (!isIterable(ret)) { - throw new ERR_INVALID_RETURN_VALUE('Iterable, AsyncIterable or Stream', 'source', ret); + throw new ERR_INVALID_RETURN_VALUE( + 'Iterable, AsyncIterable or Stream', + 'source', + ret + ); } } else if (isIterable(stream) || isReadableNodeStream(stream)) { ret = stream; @@ -254,11 +272,15 @@ export function pipelineImpl(streams, callback, opts) { } else if (typeof stream === 'function') { ret = makeAsyncIterable(ret); ret = stream(ret, { - signal + signal, }); if (reading) { if (!isIterable(ret, true)) { - throw new ERR_INVALID_RETURN_VALUE('AsyncIterable', `transform[${i - 1}]`, ret); + throw new ERR_INVALID_RETURN_VALUE( + 'AsyncIterable', + `transform[${i - 1}]`, + ret + ); } } else { let _ret; @@ -268,12 +290,13 @@ export function pipelineImpl(streams, callback, opts) { // composed through `.pipe(stream)`. const pt = new PassThrough({ - objectMode: true + objectMode: true, }); // Handle Promises/A+ spec, `then` could be a getter that throws on // second use. - const then = (_ret = ret) === null || _ret === undefined ? undefined : _ret.then + const then = + (_ret = ret) === null || _ret === undefined ? undefined : _ret.then; if (typeof then === 'function') { finishCount++; then.call( @@ -296,10 +319,14 @@ export function pipelineImpl(streams, callback, opts) { } else if (isIterable(ret, true)) { finishCount++; pump(ret, pt, finish, { - end + end, }); } else { - throw new ERR_INVALID_RETURN_VALUE('AsyncIterable or Promise', 'destination', ret); + throw new ERR_INVALID_RETURN_VALUE( + 'AsyncIterable or Promise', + 'destination', + ret + ); } ret = pt; const { destroy, cleanup } = destroyer(ret, false, true); @@ -312,7 +339,7 @@ export function pipelineImpl(streams, callback, opts) { if (isReadableNodeStream(ret)) { finishCount += 2; const cleanup = pipe(ret, stream, finish, { - end + end, }); if (isReadable(stream) && isLastStream) { lastStreamCleanup.push(cleanup); @@ -320,10 +347,14 @@ export function pipelineImpl(streams, callback, opts) { } else if (isIterable(ret)) { finishCount++; pump(ret, stream, finish, { - end + end, }); } else { - throw new ERR_INVALID_ARG_TYPE('val', ['Readable', 'Iterable', 'AsyncIterable'], ret); + throw new ERR_INVALID_ARG_TYPE( + 'val', + ['Readable', 'Iterable', 'AsyncIterable'], + ret + ); } ret = stream; } else { @@ -346,17 +377,17 @@ export function pipe(src, dst, finish, { end }) { // Finish if the destination closes before the source has completed. finish(new ERR_STREAM_PREMATURE_CLOSE()); } - }) + }); src.pipe(dst, { - end + end, }); if (end) { // Compat. Before node v10.12.0 stdio used to throw an error so // pipe() did/does not end() stdio destinations. // Now they allow it but "secretly" don't close the underlying fd. src.once('end', () => { - ended = true - dst.end() + ended = true; + dst.end(); }); } else { finish(); @@ -365,7 +396,7 @@ export function pipe(src, dst, finish, { end }) { src, { readable: true, - writable: false + writable: false, }, (err) => { const rState = src._readableState; @@ -395,7 +426,7 @@ export function pipe(src, dst, finish, { end }) { dst, { readable: false, - writable: true + writable: true, }, finish ); diff --git a/src/node/internal/streams_promises.js b/src/node/internal/streams_promises.js index 0eb7a0e16ec..a79a15abe22 100644 --- a/src/node/internal/streams_promises.js +++ b/src/node/internal/streams_promises.js @@ -26,15 +26,9 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - isIterable, - isNodeStream, - finished, -} from 'node-internal:streams_util'; +import { isIterable, isNodeStream, finished } from 'node-internal:streams_util'; -import { - pipelineImpl as pl -} from 'node-internal:streams_pipeline'; +import { pipelineImpl as pl } from 'node-internal:streams_pipeline'; export { finished }; @@ -43,7 +37,12 @@ export function pipeline(...streams) { let signal; let end; const lastArg = streams[streams.length - 1]; - if (lastArg && typeof lastArg === 'object' && !isNodeStream(lastArg) && !isIterable(lastArg)) { + if ( + lastArg && + typeof lastArg === 'object' && + !isNodeStream(lastArg) && + !isIterable(lastArg) + ) { const options = streams.pop(); signal = options.signal; end = options.end; @@ -59,7 +58,7 @@ export function pipeline(...streams) { }, { signal, - end + end, } ); }); diff --git a/src/node/internal/streams_readable.js b/src/node/internal/streams_readable.js index 2525a49bd12..da73b6f98ef 100644 --- a/src/node/internal/streams_readable.js +++ b/src/node/internal/streams_readable.js @@ -44,22 +44,16 @@ import { import * as process from 'node-internal:process'; -import { - EventEmitter, -} from 'node-internal:events'; +import { EventEmitter } from 'node-internal:events'; -import { - Stream, -} from 'node-internal:streams_legacy'; +import { Stream } from 'node-internal:streams_legacy'; import { newStreamReadableFromReadableStream, newReadableStreamFromStreamReadable, } from 'node-internal:streams_adapters'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import { AbortError, @@ -96,8 +90,9 @@ export function ReadableState(options, stream, isDuplex) { // Object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away. - this.objectMode = !!(options?.objectMode); - if (isDuplex) this.objectMode = this.objectMode || !!(options?.readableObjectMode); + this.objectMode = !!options?.objectMode; + if (isDuplex) + this.objectMode = this.objectMode || !!options?.readableObjectMode; // The point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" @@ -200,7 +195,8 @@ export function Readable(options) { if (options) { if (typeof options.read === 'function') this._read = options.read; if (typeof options.destroy === 'function') this._destroy = options.destroy; - if (typeof options.construct === 'function') this._construct = options.construct; + if (typeof options.construct === 'function') + this._construct = options.construct; if (options.signal && !isDuplex) addAbortSignal(options.signal, this); } Stream.call(this, options); @@ -210,15 +206,15 @@ export function Readable(options) { } }); } -Readable.prototype.destroy = destroy -Readable.prototype._undestroy = undestroy +Readable.prototype.destroy = destroy; +Readable.prototype._undestroy = undestroy; Readable.prototype._destroy = function (err, cb) { if (cb) cb(err); -} +}; Readable.prototype[EventEmitter.captureRejectionSymbol] = function (err) { this.destroy(err); -} +}; // Manually shove something into the read() buffer. // This returns true if the highWaterMark has not been hit yet, @@ -226,12 +222,12 @@ Readable.prototype[EventEmitter.captureRejectionSymbol] = function (err) { // write() some more. Readable.prototype.push = function (chunk, encoding) { return readableAddChunk(this, chunk, encoding, false); -} +}; // Unshift should *always* be something directly out of read(). Readable.prototype.unshift = function (chunk, encoding) { return readableAddChunk(this, chunk, encoding, true); -} +}; function readableAddChunk(stream, chunk, encoding, addToFront) { const state = stream._readableState; @@ -250,12 +246,16 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { } } } else if (chunk instanceof Buffer) { - encoding = '' + encoding = ''; } else if (Stream._isUint8Array(chunk)) { chunk = Stream._uint8ArrayToBuffer(chunk); encoding = ''; } else if (chunk != null) { - err = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + err = new ERR_INVALID_ARG_TYPE( + 'chunk', + ['string', 'Buffer', 'Uint8Array'], + chunk + ); } } if (err) { @@ -265,7 +265,8 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { onEofChunk(stream, state); } else if (state.objectMode || (chunk && chunk.length > 0)) { if (addToFront) { - if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); + if (state.endEmitted) + errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); else if (state.destroyed || state.errored) return false; else addChunk(stream, state, chunk, true); } else if (state.ended) { @@ -276,7 +277,8 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { state.reading = false; if (state.decoder && !encoding) { chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false); + if (state.objectMode || chunk.length !== 0) + addChunk(stream, state, chunk, false); else maybeReadMore(stream, state); } else { addChunk(stream, state, chunk, false); @@ -290,11 +292,18 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { // We can push more data if we are below the highWaterMark. // Also, if we have no data yet, we can stand some more bytes. // This is to work around cases where hwm=0, such as the repl. - return !state.ended && (state.length < state.highWaterMark || state.length === 0); + return ( + !state.ended && (state.length < state.highWaterMark || state.length === 0) + ); } function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync && stream.listenerCount('data') > 0) { + if ( + state.flowing && + state.length === 0 && + !state.sync && + stream.listenerCount('data') > 0 + ) { // Use the guard to avoid creating `Set()` repeatedly // when we have multiple pipes. if (state.multiAwaitDrain) { @@ -318,7 +327,7 @@ function addChunk(stream, state, chunk, addToFront) { Readable.prototype.isPaused = function () { const state = this._readableState; return state[kPaused] === true || state.flowing === false; -} +}; // Backwards compatibility. Readable.prototype.setEncoding = function (enc) { @@ -336,7 +345,7 @@ Readable.prototype.setEncoding = function (enc) { if (content !== '') buffer.push(content); this._readableState.length = content.length; return this; -} +}; // Don't raise the hwm > 1GB. const MAX_HWM = 0x40000000; @@ -393,7 +402,11 @@ Readable.prototype.read = function (n) { if ( n === 0 && state.needReadable && - ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) { + ((state.highWaterMark !== 0 + ? state.length >= state.highWaterMark + : state.length > 0) || + state.ended) + ) { if (state.length === 0 && state.ended) endReadable(this); else emitReadable(this); return null; @@ -439,7 +452,13 @@ Readable.prototype.read = function (n) { // However, if we've ended, then there's no point, if we're already // reading, then it's unnecessary, if we're constructing we have to wait, // and if we're destroyed or errored, then it's not allowed, - if (state.ended || state.reading || state.destroyed || state.errored || !state.constructed) { + if ( + state.ended || + state.reading || + state.destroyed || + state.errored || + !state.constructed + ) { doRead = false; } else if (doRead) { state.reading = true; @@ -476,17 +495,17 @@ Readable.prototype.read = function (n) { if (state.length === 0) { // If we have nothing in the buffer, then we want to know // as soon as we *do* get something into the buffer. - if (!state.ended) state.needReadable = true + if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) endReadable(this) + if (nOrig !== n && state.ended) endReadable(this); } if (ret !== null && !state.errorEmitted && !state.closeEmitted) { - state.dataEmitted = true - this.emit('data', ret) + state.dataEmitted = true; + this.emit('data', ret); } - return ret -} + return ret; +}; function onEofChunk(stream, state) { if (state.ended) return; @@ -538,7 +557,8 @@ function emitReadable_(stream) { // 2. It is not ended. // 3. It is below the highWaterMark, so we can schedule // another readable later. - state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark; + state.needReadable = + !state.flowing && !state.ended && state.length <= state.highWaterMark; flow(stream); } @@ -582,7 +602,8 @@ function maybeReadMore_(stream, state) { while ( !state.reading && !state.ended && - (state.length < state.highWaterMark || (state.flowing && state.length === 0)) + (state.length < state.highWaterMark || + (state.flowing && state.length === 0)) ) { const len = state.length; stream.read(0); @@ -599,7 +620,7 @@ function maybeReadMore_(stream, state) { // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function (_size) { throw new ERR_METHOD_NOT_IMPLEMENTED('_read()'); -} +}; Readable.prototype.pipe = function (dest, pipeOpts) { const src = this; @@ -608,11 +629,12 @@ Readable.prototype.pipe = function (dest, pipeOpts) { if (!state.multiAwaitDrain) { state.multiAwaitDrain = true; state.awaitDrainWriters = new Set( - state.awaitDrainWriters ? [state.awaitDrainWriters] : []); + state.awaitDrainWriters ? [state.awaitDrainWriters] : [] + ); } } state.pipes.push(dest); - const doEnd = (!pipeOpts || pipeOpts.end !== false); + const doEnd = !pipeOpts || pipeOpts.end !== false; const endFn = doEnd ? onend : unpipe; if (state.endEmitted) process.nextTick(endFn); else src.once('end', endFn); @@ -649,7 +671,12 @@ Readable.prototype.pipe = function (dest, pipeOpts) { // flowing again. // So, if this is awaiting a drain, then we just call it now. // If we don't know, then assume that we are waiting for one. - if (ondrain && state.awaitDrainWriters && (!dest._writableState || dest._writableState.needDrain)) ondrain(); + if ( + ondrain && + state.awaitDrainWriters && + (!dest._writableState || dest._writableState.needDrain) + ) + ondrain(); } function pause() { // If the user unpiped during `dest.write()`, it is possible @@ -729,7 +756,7 @@ Readable.prototype.pipe = function (dest, pipeOpts) { src.resume(); } return dest; -} +}; function pipeOnDrain(src, dest) { return function pipeOnDrainFunctionResult() { @@ -743,17 +770,19 @@ function pipeOnDrain(src, dest) { } else if (state.multiAwaitDrain) { state.awaitDrainWriters.delete(dest); } - if ((!state.awaitDrainWriters || state.awaitDrainWriters.size === 0) && - src.listenerCount('data')) { + if ( + (!state.awaitDrainWriters || state.awaitDrainWriters.size === 0) && + src.listenerCount('data') + ) { src.resume(); } - } + }; } Readable.prototype.unpipe = function (dest) { const state = this._readableState; const unpipeInfo = { - hasUnpiped: false + hasUnpiped: false, }; // If we're not piping anywhere, then do nothing. @@ -765,8 +794,8 @@ Readable.prototype.unpipe = function (dest) { this.pause(); for (let i = 0; i < dests.length; i++) dests[i].emit('unpipe', this, { - hasUnpiped: false - }) + hasUnpiped: false, + }); return this; } @@ -777,7 +806,7 @@ Readable.prototype.unpipe = function (dest) { if (state.pipes.length === 0) this.pause(); dest.emit('unpipe', this, unpipeInfo); return this; -} +}; // Set up data events if they are asked for // Ensure readable listeners eventually get something. @@ -804,8 +833,8 @@ Readable.prototype.on = function (ev, fn) { } } return res; -} -Readable.prototype.addListener = Readable.prototype.on +}; +Readable.prototype.addListener = Readable.prototype.on; Readable.prototype.removeListener = function (ev, fn) { const res = Stream.prototype.removeListener.call(this, ev, fn); if (ev === 'readable') { @@ -818,8 +847,8 @@ Readable.prototype.removeListener = function (ev, fn) { process.nextTick(updateReadableListening, this); } return res; -} -Readable.prototype.off = Readable.prototype.removeListener +}; +Readable.prototype.off = Readable.prototype.removeListener; Readable.prototype.removeAllListeners = function (ev) { const res = Stream.prototype.removeAllListeners.apply(this, arguments); if (ev === 'readable' || ev === undefined) { @@ -832,7 +861,7 @@ Readable.prototype.removeAllListeners = function (ev) { process.nextTick(updateReadableListening, this); } return res; -} +}; function updateReadableListening(self) { const state = self._readableState; @@ -867,7 +896,7 @@ Readable.prototype.resume = function () { } state[kPaused] = false; return this; -} +}; function resume(stream, state) { if (!state.resumeScheduled) { @@ -893,7 +922,7 @@ Readable.prototype.pause = function () { } this._readableState[kPaused] = true; return this; -} +}; function flow(stream) { const state = stream._readableState; @@ -944,23 +973,23 @@ Readable.prototype.wrap = function (stream) { } } return this; -} +}; Readable.prototype[Symbol.asyncIterator] = function () { return streamToAsyncIterator(this); -} +}; Readable.prototype.iterator = function (options) { if (options !== undefined) { validateObject(options, 'options', options); } return streamToAsyncIterator(this, options); -} +}; function streamToAsyncIterator(stream, options) { if (typeof stream.read !== 'function') { stream = Readable.wrap(stream, { - objectMode: true + objectMode: true, }); } const iter = createAsyncIterator(stream, options); @@ -983,12 +1012,12 @@ async function* createAsyncIterator(stream, options) { const cleanup = eos( stream, { - writable: false + writable: false, }, (err) => { - error = err ? aggregateTwoErrors(error, err) : null - callback() - callback = nop + error = err ? aggregateTwoErrors(error, err) : null; + callback(); + callback = nop; } ); try { @@ -1009,7 +1038,10 @@ async function* createAsyncIterator(stream, options) { throw error; } finally { if ( - (error || (options === null || options === undefined ? undefined : options.destroyOnReturn) !== false) && + (error || + (options === null || options === undefined + ? undefined + : options.destroyOnReturn) !== false) && (error === undefined || stream._readableState.autoDestroy) ) { destroyer(stream, null); @@ -1031,20 +1063,26 @@ Object.defineProperties(Readable.prototype, { // where the readable side was disabled upon construction. // Compat. The user might manually disable readable side through // deprecated setter. - return !!r && r.readable !== false && !r.destroyed && !r.errorEmitted && !r.endEmitted; + return ( + !!r && + r.readable !== false && + !r.destroyed && + !r.errorEmitted && + !r.endEmitted + ); }, set(val) { // Backwards compat. if (this._readableState) { this._readableState.readable = !!val; } - } + }, }, readableDidRead: { enumerable: false, get: function () { - return !!(this._readableState?.dataEmitted); - } + return !!this._readableState?.dataEmitted; + }, }, readableAborted: { enumerable: false, @@ -1054,105 +1092,105 @@ Object.defineProperties(Readable.prototype, { (this._readableState?.destroyed || this._readableState?.errored) && !this._readableState?.endEmitted ); - } + }, }, readableHighWaterMark: { enumerable: false, get: function () { return this._readableState?.highWaterMark; - } + }, }, readableBuffer: { enumerable: false, get: function () { return this._readableState?.buffer; - } + }, }, readableFlowing: { enumerable: false, get: function () { - return !!(this._readableState?.flowing); + return !!this._readableState?.flowing; }, set: function (state) { if (this._readableState) { - this._readableState.flowing = state + this._readableState.flowing = state; } - } + }, }, readableLength: { enumerable: false, get() { return this._readableState?.length | 0; - } + }, }, readableObjectMode: { enumerable: false, get() { return this._readableState ? this._readableState.objectMode : false; - } + }, }, readableEncoding: { enumerable: false, get() { return this._readableState?.encoding || null; - } + }, }, errored: { enumerable: false, get() { return this._readableState?.errored || null; - } + }, }, closed: { get() { - return !!(this._readableState?.closed); - } + return !!this._readableState?.closed; + }, }, destroyed: { enumerable: false, get() { - return !!(this._readableState?.destroyed); + return !!this._readableState?.destroyed; }, set(value) { // We ignore the value if the stream // has not been initialized yet. if (!this._readableState) { - return + return; } // Backward compatibility, the user is explicitly // managing destroyed. - this._readableState.destroyed = value - } + this._readableState.destroyed = value; + }, }, readableEnded: { enumerable: false, get() { - return !!(this._readableState?.endEmitted); - } - } + return !!this._readableState?.endEmitted; + }, + }, }); Object.defineProperties(ReadableState.prototype, { // Legacy getter for `pipesCount`. pipesCount: { get() { - return this.pipes.length - } + return this.pipes.length; + }, }, // Legacy property for `paused`. paused: { get() { - return this[kPaused] !== false + return this[kPaused] !== false; }, set(value) { - this[kPaused] = !!value - } - } + this[kPaused] = !!value; + }, + }, }); // Exposed for testing purposes only. -Readable._fromList = fromList +Readable._fromList = fromList; // Pluck off n bytes from an array of buffers. // Length is the combined lengths of all the buffers in the list. @@ -1160,24 +1198,24 @@ Readable._fromList = fromList // changes to the function body. function fromList(n, state) { // nothing buffered. - if (state.length === 0) return null - let ret - if (state.objectMode) ret = state.buffer.shift() + if (state.length === 0) return null; + let ret; + if (state.objectMode) ret = state.buffer.shift(); else if (!n || n >= state.length) { // Read it all, truncate the list. - if (state.decoder) ret = state.buffer.join('') + if (state.decoder) ret = state.buffer.join(''); else if (state.buffer.length === 1) ret = state.buffer.first(); else ret = state.buffer.concat(state.length); - state.buffer.clear() + state.buffer.clear(); } else { // read part of list. ret = state.buffer.consume(n, !!state.decoder); } - return ret + return ret; } function endReadable(stream) { - const state = stream._readableState + const state = stream._readableState; if (!state.endEmitted) { state.ended = true; process.nextTick(endReadableNT, state, stream); @@ -1186,41 +1224,47 @@ function endReadable(stream) { function endReadableNT(state, stream) { // Check that we didn't get one last unshift. - if (!state.errored && !state.closeEmitted && !state.endEmitted && state.length === 0) { - state.endEmitted = true - stream.emit('end') + if ( + !state.errored && + !state.closeEmitted && + !state.endEmitted && + state.length === 0 + ) { + state.endEmitted = true; + stream.emit('end'); if (stream.writable && stream.allowHalfOpen === false) { process.nextTick(endWritableNT, stream); } else if (state.autoDestroy) { // In case of duplex streams we need a way to detect // if the writable side is ready for autoDestroy as well. - const wState = stream._writableState + const wState = stream._writableState; const autoDestroy = !wState || (wState.autoDestroy && // We don't expect the writable to ever 'finish' // if writable is explicitly set to false. - (wState.finished || wState.writable === false)) + (wState.finished || wState.writable === false)); if (autoDestroy) { - stream.destroy() + stream.destroy(); } } } } function endWritableNT(stream) { - const writable = stream.writable && !stream.writableEnded && !stream.destroyed + const writable = + stream.writable && !stream.writableEnded && !stream.destroyed; if (writable) { - stream.end() + stream.end(); } } export function fromWeb(readableStream, options) { - return newStreamReadableFromReadableStream(readableStream, options) + return newStreamReadableFromReadableStream(readableStream, options); } export function toWeb(streamReadable, options) { - return newReadableStreamFromStreamReadable(streamReadable, options) + return newReadableStreamFromStreamReadable(streamReadable, options); } export function wrap(src, options) { @@ -1228,16 +1272,17 @@ export function wrap(src, options) { return new Readable({ objectMode: (_ref = - (_src$readableObjectMo = src.readableObjectMode) !== null && _src$readableObjectMo !== undefined + (_src$readableObjectMo = src.readableObjectMode) !== null && + _src$readableObjectMo !== undefined ? _src$readableObjectMo : src.objectMode) !== null && _ref !== undefined ? _ref : true, ...options, destroy(err, callback) { - destroyer(src, err) - callback(err) - } + destroyer(src, err); + callback(err); + }, }).wrap(src); } @@ -1245,12 +1290,11 @@ Readable.toWeb = toWeb; Readable.fromWeb = fromWeb; Readable.wrap = wrap; - // ====================================================================================== // Readable.from = function (iterable, opts) { - return from(Readable, iterable, opts) + return from(Readable, iterable, opts); }; export function from(Readable, iterable, opts) { @@ -1260,93 +1304,97 @@ export function from(Readable, iterable, opts) { objectMode: true, ...opts, read() { - this.push(iterable) - this.push(null) - } - }) + this.push(iterable); + this.push(null); + }, + }); } let isAsync; if (iterable && iterable[Symbol.asyncIterator]) { - isAsync = true - iterator = iterable[Symbol.asyncIterator]() + isAsync = true; + iterator = iterable[Symbol.asyncIterator](); } else if (iterable && iterable[Symbol.iterator]) { - isAsync = false - iterator = iterable[Symbol.iterator]() + isAsync = false; + iterator = iterable[Symbol.iterator](); } else { - throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable) + throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable); } const readable = new Readable({ objectMode: true, highWaterMark: 1, // TODO(ronag): What options should be allowed? - ...opts - }) + ...opts, + }); // Flag to protect against _read // being called before last iteration completion. - let reading = false + let reading = false; readable._read = function () { if (!reading) { - reading = true - next() + reading = true; + next(); } - } + }; readable._destroy = function (error, cb) { close(error).then( () => process.nextTick(cb, error), - (err) => process.nextTick(cb, err || error)); - } + (err) => process.nextTick(cb, err || error) + ); + }; async function close(error) { - const hadError = error !== undefined && error !== null - const hasThrow = typeof iterator.throw === 'function' + const hadError = error !== undefined && error !== null; + const hasThrow = typeof iterator.throw === 'function'; if (hadError && hasThrow) { - const { value, done } = await iterator.throw(error) - await value + const { value, done } = await iterator.throw(error); + await value; if (done) { - return + return; } } if (typeof iterator.return === 'function') { - const { value } = await iterator.return() - await value + const { value } = await iterator.return(); + await value; } } async function next() { for (;;) { try { - const { value, done } = isAsync ? await iterator.next() : iterator.next() + const { value, done } = isAsync + ? await iterator.next() + : iterator.next(); if (done) { - readable.push(null) + readable.push(null); } else { - const res = value && typeof value.then === 'function' ? await value : value + const res = + value && typeof value.then === 'function' ? await value : value; if (res === null) { - reading = false - throw new ERR_STREAM_NULL_VALUES() + reading = false; + throw new ERR_STREAM_NULL_VALUES(); } else if (readable.push(res)) { - continue + continue; } else { - reading = false + reading = false; } } } catch (err) { - readable.destroy(err) + readable.destroy(err); } - break + break; } } - return readable + return readable; } // ====================================================================================== // Operators -const kWeakHandler = Symbol('kWeak') -const kEmpty = Symbol('kEmpty') -const kEof = Symbol('kEof') +const kWeakHandler = Symbol('kWeak'); +const kEmpty = Symbol('kEmpty'); +const kEof = Symbol('kEof'); function map(fn, options) { if (typeof fn !== 'function') { - throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn) + throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn); } if (options != null) { validateObject(options, 'options', options); @@ -1366,7 +1414,7 @@ function map(fn, options) { const queue = []; const signal = ac.signal; const signalOpt = { - signal + signal, }; const abort = () => ac.abort(); if ( @@ -1380,9 +1428,10 @@ function map(fn, options) { } options === null || options === undefined ? undefined - : (_options$signal2 = options.signal) === null || _options$signal2 === undefined - ? undefined - : _options$signal2.addEventListener('abort', abort); + : (_options$signal2 = options.signal) === null || + _options$signal2 === undefined + ? undefined + : _options$signal2.addEventListener('abort', abort); let next; let resume; let done = false; @@ -1407,7 +1456,11 @@ function map(fn, options) { if (val === kEmpty) { continue; } - if (typeof ((_val = val) === null || _val === undefined ? undefined : _val.catch) === 'function') { + if ( + typeof ((_val = val) === null || _val === undefined + ? undefined + : _val.catch) === 'function' + ) { val.catch(onDone); } queue.push(val); @@ -1424,7 +1477,7 @@ function map(fn, options) { queue.push(kEof); } catch (err) { const val = Promise.reject(err); - val.then(undefined, onDone);; + val.then(undefined, onDone); queue.push(val); } finally { let _options$signal3; @@ -1435,9 +1488,10 @@ function map(fn, options) { } options === null || options === undefined ? undefined - : (_options$signal3 = options.signal) === null || _options$signal3 === undefined - ? undefined - : _options$signal3.removeEventListener('abort', abort); + : (_options$signal3 = options.signal) === null || + _options$signal3 === undefined + ? undefined + : _options$signal3.removeEventListener('abort', abort); } } pump(); @@ -1454,14 +1508,14 @@ function map(fn, options) { if (val !== kEmpty) { yield val; } - queue.shift() + queue.shift(); if (resume) { resume(); resume = null; } } await new Promise((resolve) => { - next = resolve + next = resolve; }); } } finally { @@ -1479,7 +1533,10 @@ function asIndexedPairs(options) { if (options != null) { validateObject(options, 'options', options); } - if ((options === null || options === undefined ? undefined : options.signal) != null) { + if ( + (options === null || options === undefined ? undefined : options.signal) != + null + ) { validateAbortSignal(options.signal, 'options.signal'); } return async function* asIndexedPairs() { @@ -1494,7 +1551,7 @@ function asIndexedPairs(options) { _options$signal4.aborted ) { throw new AbortError('Aborted', { - cause: options.signal?.reason + cause: options.signal?.reason, }); } yield [index++, val]; @@ -1520,7 +1577,7 @@ async function every(fn, options) { return !(await some.call( this, async (...args) => { - return !(await fn(...args)) + return !(await fn(...args)); }, options )); @@ -1535,11 +1592,11 @@ async function find(fn, options) { async function forEach(fn, options) { if (typeof fn !== 'function') { - throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn) + throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn); } async function forEachFn(value, options) { await fn(value, options); - return kEmpty + return kEmpty; } // eslint-disable-next-line no-unused-vars for await (const _ of map.call(this, forEachFn, options)); @@ -1547,30 +1604,34 @@ async function forEach(fn, options) { function filter(fn, options) { if (typeof fn !== 'function') { - throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn) + throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn); } async function filterFn(value, options) { if (await fn(value, options)) { - return value + return value; } - return kEmpty + return kEmpty; } - return map.call(this, filterFn, options) + return map.call(this, filterFn, options); } // Specific to provide better error to reduce since the argument is only // missing if the stream has no items in it - but the code is still appropriate class ReduceAwareErrMissingArgs extends ERR_MISSING_ARGS { constructor() { - super('reduce') - this.message = 'Reduce of an empty stream requires an initial value' + super('reduce'); + this.message = 'Reduce of an empty stream requires an initial value'; } } async function reduce(reducer, initialValue, options) { let _options$signal5; if (typeof reducer !== 'function') { - throw new ERR_INVALID_ARG_TYPE('reducer', ['Function', 'AsyncFunction'], reducer); + throw new ERR_INVALID_ARG_TYPE( + 'reducer', + ['Function', 'AsyncFunction'], + reducer + ); } if (options != null) { validateObject(options, 'options', options); @@ -1587,8 +1648,8 @@ async function reduce(reducer, initialValue, options) { _options$signal5.aborted ) { const err = new AbortError(undefined, { - cause: options.signal?.reason - }) + cause: options.signal?.reason, + }); this.once('error', () => {}); // The error is already propagated await finished(this.destroy(err)); throw err; @@ -1598,7 +1659,7 @@ async function reduce(reducer, initialValue, options) { if (options?.signal) { const opts = { once: true, - [kWeakHandler]: this + [kWeakHandler]: this, }; options.signal.addEventListener('abort', () => ac.abort(), opts); } @@ -1621,7 +1682,7 @@ async function reduce(reducer, initialValue, options) { hasInitialValue = true; } else { initialValue = await reducer(initialValue, value, { - signal + signal, }); } } @@ -1639,7 +1700,7 @@ async function toArray(options) { validateObject(options, 'options', options); } if (options?.signal != null) { - validateAbortSignal(options?.signal, 'options.signal') + validateAbortSignal(options?.signal, 'options.signal'); } const result = []; for await (const val of this) { @@ -1652,7 +1713,7 @@ async function toArray(options) { _options$signal7.aborted ) { throw new AbortError(undefined, { - cause: options.signal?.reason + cause: options.signal?.reason, }); } result.push(val); @@ -1661,25 +1722,25 @@ async function toArray(options) { } function flatMap(fn, options) { - const values = map.call(this, fn, options) + const values = map.call(this, fn, options); return async function* flatMap() { for await (const val of values) { - yield* val + yield* val; } - }.call(this) + }.call(this); } function toIntegerOrInfinity(number) { // We coerce here to align with the spec // https://github.com/tc39/proposal-iterator-helpers/issues/169 - number = Number(number) + number = Number(number); if (Number.isNaN(number)) { - return 0 + return 0; } if (number < 0) { - throw new ERR_OUT_OF_RANGE('number', '>= 0', number) + throw new ERR_OUT_OF_RANGE('number', '>= 0', number); } - return number + return number; } function drop(number, options) { @@ -1758,29 +1819,29 @@ function take(number, options) { }.call(this); } -Readable.prototype.map = function(fn, options) { +Readable.prototype.map = function (fn, options) { return from(Readable, map.call(this, fn, options)); -} +}; -Readable.prototype.asIndexedPairs = function(options) { +Readable.prototype.asIndexedPairs = function (options) { return from(Readable, asIndexedPairs.call(this, options)); -} +}; -Readable.prototype.drop = function(number, options) { +Readable.prototype.drop = function (number, options) { return from(Readable, drop.call(this, number, options)); -} +}; -Readable.prototype.filter = function(fn, options) { +Readable.prototype.filter = function (fn, options) { return from(Readable, filter.call(this, fn, options)); -} +}; -Readable.prototype.flatMap = function(fn, options) { +Readable.prototype.flatMap = function (fn, options) { return from(Readable, flatMap.call(this, fn, options)); }; -Readable.prototype.take = function(number, options) { +Readable.prototype.take = function (number, options) { return from(Readable, take.call(this, number, options)); -} +}; Readable.prototype.every = every; Readable.prototype.forEach = forEach; @@ -1788,4 +1849,3 @@ Readable.prototype.reduce = reduce; Readable.prototype.toArray = toArray; Readable.prototype.some = some; Readable.prototype.find = find; - diff --git a/src/node/internal/streams_transform.d.ts b/src/node/internal/streams_transform.d.ts index d5420e08b3b..4f923fe1130 100644 --- a/src/node/internal/streams_transform.d.ts +++ b/src/node/internal/streams_transform.d.ts @@ -31,15 +31,31 @@ interface WritableOptions { defaultEncoding?: BufferEncoding | undefined; objectMode?: boolean | undefined; emitClose?: boolean | undefined; - write?(this: Writable, chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; - writev?(this: Writable, chunks: Array<{ chunk: any, encoding: BufferEncoding }>, callback: (error?: Error | null) => void): void; - destroy?(this: Writable, error: Error | null, callback: (error: Error | null) => void): void; + write?( + this: Writable, + chunk: any, + encoding: BufferEncoding, + callback: (error?: Error | null) => void + ): void; + writev?( + this: Writable, + chunks: Array<{ chunk: any; encoding: BufferEncoding }>, + callback: (error?: Error | null) => void + ): void; + destroy?( + this: Writable, + error: Error | null, + callback: (error: Error | null) => void + ): void; final?(this: Writable, callback: (error?: Error | null) => void): void; autoDestroy?: boolean | undefined; } export class internal extends EventEmitter { - pipe(destination: T, options?: { end?: boolean | undefined; }): T; + pipe( + destination: T, + options?: { end?: boolean | undefined } + ): T; } export class Stream extends internal { @@ -51,12 +67,19 @@ interface ReadableOptions { encoding?: BufferEncoding | undefined; objectMode?: boolean | undefined; read?(this: Readable, size: number): void; - destroy?(this: Readable, error: Error | null, callback: (error: Error | null) => void): void; + destroy?( + this: Readable, + error: Error | null, + callback: (error: Error | null) => void + ): void; autoDestroy?: boolean | undefined; } export class Readable extends Stream implements NodeJS.ReadableStream { - static from(iterable: Iterable | AsyncIterable, options?: ReadableOptions): Readable; + static from( + iterable: Iterable | AsyncIterable, + options?: ReadableOptions + ): Readable; readable: boolean; readonly readableEncoding: BufferEncoding | null; @@ -80,68 +103,77 @@ export class Readable extends Stream implements NodeJS.ReadableStream { _destroy(error: Error | null, callback: (error?: Error | null) => void): void; destroy(error?: Error): this; - addListener(event: "close", listener: () => void): this; - addListener(event: "data", listener: (chunk: any) => void): this; - addListener(event: "end", listener: () => void): this; - addListener(event: "error", listener: (err: Error) => void): this; - addListener(event: "pause", listener: () => void): this; - addListener(event: "readable", listener: () => void): this; - addListener(event: "resume", listener: () => void): this; + addListener(event: 'close', listener: () => void): this; + addListener(event: 'data', listener: (chunk: any) => void): this; + addListener(event: 'end', listener: () => void): this; + addListener(event: 'error', listener: (err: Error) => void): this; + addListener(event: 'pause', listener: () => void): this; + addListener(event: 'readable', listener: () => void): this; + addListener(event: 'resume', listener: () => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this; - emit(event: "close"): boolean; - emit(event: "data", chunk: any): boolean; - emit(event: "end"): boolean; - emit(event: "error", err: Error): boolean; - emit(event: "pause"): boolean; - emit(event: "readable"): boolean; - emit(event: "resume"): boolean; + emit(event: 'close'): boolean; + emit(event: 'data', chunk: any): boolean; + emit(event: 'end'): boolean; + emit(event: 'error', err: Error): boolean; + emit(event: 'pause'): boolean; + emit(event: 'readable'): boolean; + emit(event: 'resume'): boolean; emit(event: string | symbol, ...args: any[]): boolean; - on(event: "close", listener: () => void): this; - on(event: "data", listener: (chunk: any) => void): this; - on(event: "end", listener: () => void): this; - on(event: "error", listener: (err: Error) => void): this; - on(event: "pause", listener: () => void): this; - on(event: "readable", listener: () => void): this; - on(event: "resume", listener: () => void): this; + on(event: 'close', listener: () => void): this; + on(event: 'data', listener: (chunk: any) => void): this; + on(event: 'end', listener: () => void): this; + on(event: 'error', listener: (err: Error) => void): this; + on(event: 'pause', listener: () => void): this; + on(event: 'readable', listener: () => void): this; + on(event: 'resume', listener: () => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this; - once(event: "close", listener: () => void): this; - once(event: "data", listener: (chunk: any) => void): this; - once(event: "end", listener: () => void): this; - once(event: "error", listener: (err: Error) => void): this; - once(event: "pause", listener: () => void): this; - once(event: "readable", listener: () => void): this; - once(event: "resume", listener: () => void): this; + once(event: 'close', listener: () => void): this; + once(event: 'data', listener: (chunk: any) => void): this; + once(event: 'end', listener: () => void): this; + once(event: 'error', listener: (err: Error) => void): this; + once(event: 'pause', listener: () => void): this; + once(event: 'readable', listener: () => void): this; + once(event: 'resume', listener: () => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this; - prependListener(event: "close", listener: () => void): this; - prependListener(event: "data", listener: (chunk: any) => void): this; - prependListener(event: "end", listener: () => void): this; - prependListener(event: "error", listener: (err: Error) => void): this; - prependListener(event: "pause", listener: () => void): this; - prependListener(event: "readable", listener: () => void): this; - prependListener(event: "resume", listener: () => void): this; - prependListener(event: string | symbol, listener: (...args: any[]) => void): this; - - prependOnceListener(event: "close", listener: () => void): this; - prependOnceListener(event: "data", listener: (chunk: any) => void): this; - prependOnceListener(event: "end", listener: () => void): this; - prependOnceListener(event: "error", listener: (err: Error) => void): this; - prependOnceListener(event: "pause", listener: () => void): this; - prependOnceListener(event: "readable", listener: () => void): this; - prependOnceListener(event: "resume", listener: () => void): this; - prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; - - removeListener(event: "close", listener: () => void): this; - removeListener(event: "data", listener: (chunk: any) => void): this; - removeListener(event: "end", listener: () => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - removeListener(event: "pause", listener: () => void): this; - removeListener(event: "readable", listener: () => void): this; - removeListener(event: "resume", listener: () => void): this; - removeListener(event: string | symbol, listener: (...args: any[]) => void): this; + prependListener(event: 'close', listener: () => void): this; + prependListener(event: 'data', listener: (chunk: any) => void): this; + prependListener(event: 'end', listener: () => void): this; + prependListener(event: 'error', listener: (err: Error) => void): this; + prependListener(event: 'pause', listener: () => void): this; + prependListener(event: 'readable', listener: () => void): this; + prependListener(event: 'resume', listener: () => void): this; + prependListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; + + prependOnceListener(event: 'close', listener: () => void): this; + prependOnceListener(event: 'data', listener: (chunk: any) => void): this; + prependOnceListener(event: 'end', listener: () => void): this; + prependOnceListener(event: 'error', listener: (err: Error) => void): this; + prependOnceListener(event: 'pause', listener: () => void): this; + prependOnceListener(event: 'readable', listener: () => void): this; + prependOnceListener(event: 'resume', listener: () => void): this; + prependOnceListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; + + removeListener(event: 'close', listener: () => void): this; + removeListener(event: 'data', listener: (chunk: any) => void): this; + removeListener(event: 'end', listener: () => void): this; + removeListener(event: 'error', listener: (err: Error) => void): this; + removeListener(event: 'pause', listener: () => void): this; + removeListener(event: 'readable', listener: () => void): this; + removeListener(event: 'resume', listener: () => void): this; + removeListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; [Symbol.asyncIterator](): AsyncIterableIterator; } @@ -156,12 +188,23 @@ export class Writable extends Stream implements NodeJS.WritableStream { readonly writableCorked: number; destroyed: boolean; constructor(opts?: WritableOptions); - _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; - _writev?(chunks: Array<{ chunk: any, encoding: BufferEncoding }>, callback: (error?: Error | null) => void): void; + _write( + chunk: any, + encoding: BufferEncoding, + callback: (error?: Error | null) => void + ): void; + _writev?( + chunks: Array<{ chunk: any; encoding: BufferEncoding }>, + callback: (error?: Error | null) => void + ): void; _destroy(error: Error | null, callback: (error?: Error | null) => void): void; _final(callback: (error?: Error | null) => void): void; write(chunk: any, cb?: (error: Error | null | undefined) => void): boolean; - write(chunk: any, encoding: BufferEncoding, cb?: (error: Error | null | undefined) => void): boolean; + write( + chunk: any, + encoding: BufferEncoding, + cb?: (error: Error | null | undefined) => void + ): boolean; setDefaultEncoding(encoding: BufferEncoding): this; end(cb?: () => void): this; end(chunk: any, cb?: () => void): this; @@ -170,63 +213,71 @@ export class Writable extends Stream implements NodeJS.WritableStream { uncork(): void; destroy(error?: Error): this; - addListener(event: "close", listener: () => void): this; - addListener(event: "drain", listener: () => void): this; - addListener(event: "error", listener: (err: Error) => void): this; - addListener(event: "finish", listener: () => void): this; - addListener(event: "pipe", listener: (src: Readable) => void): this; - addListener(event: "unpipe", listener: (src: Readable) => void): this; + addListener(event: 'close', listener: () => void): this; + addListener(event: 'drain', listener: () => void): this; + addListener(event: 'error', listener: (err: Error) => void): this; + addListener(event: 'finish', listener: () => void): this; + addListener(event: 'pipe', listener: (src: Readable) => void): this; + addListener(event: 'unpipe', listener: (src: Readable) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this; - emit(event: "close"): boolean; - emit(event: "drain"): boolean; - emit(event: "error", err: Error): boolean; - emit(event: "finish"): boolean; - emit(event: "pipe", src: Readable): boolean; - emit(event: "unpipe", src: Readable): boolean; + emit(event: 'close'): boolean; + emit(event: 'drain'): boolean; + emit(event: 'error', err: Error): boolean; + emit(event: 'finish'): boolean; + emit(event: 'pipe', src: Readable): boolean; + emit(event: 'unpipe', src: Readable): boolean; emit(event: string | symbol, ...args: any[]): boolean; - on(event: "close", listener: () => void): this; - on(event: "drain", listener: () => void): this; - on(event: "error", listener: (err: Error) => void): this; - on(event: "finish", listener: () => void): this; - on(event: "pipe", listener: (src: Readable) => void): this; - on(event: "unpipe", listener: (src: Readable) => void): this; + on(event: 'close', listener: () => void): this; + on(event: 'drain', listener: () => void): this; + on(event: 'error', listener: (err: Error) => void): this; + on(event: 'finish', listener: () => void): this; + on(event: 'pipe', listener: (src: Readable) => void): this; + on(event: 'unpipe', listener: (src: Readable) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this; - once(event: "close", listener: () => void): this; - once(event: "drain", listener: () => void): this; - once(event: "error", listener: (err: Error) => void): this; - once(event: "finish", listener: () => void): this; - once(event: "pipe", listener: (src: Readable) => void): this; - once(event: "unpipe", listener: (src: Readable) => void): this; + once(event: 'close', listener: () => void): this; + once(event: 'drain', listener: () => void): this; + once(event: 'error', listener: (err: Error) => void): this; + once(event: 'finish', listener: () => void): this; + once(event: 'pipe', listener: (src: Readable) => void): this; + once(event: 'unpipe', listener: (src: Readable) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this; - prependListener(event: "close", listener: () => void): this; - prependListener(event: "drain", listener: () => void): this; - prependListener(event: "error", listener: (err: Error) => void): this; - prependListener(event: "finish", listener: () => void): this; - prependListener(event: "pipe", listener: (src: Readable) => void): this; - prependListener(event: "unpipe", listener: (src: Readable) => void): this; - prependListener(event: string | symbol, listener: (...args: any[]) => void): this; - - prependOnceListener(event: "close", listener: () => void): this; - prependOnceListener(event: "drain", listener: () => void): this; - prependOnceListener(event: "error", listener: (err: Error) => void): this; - prependOnceListener(event: "finish", listener: () => void): this; - prependOnceListener(event: "pipe", listener: (src: Readable) => void): this; - prependOnceListener(event: "unpipe", listener: (src: Readable) => void): this; - prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; - - removeListener(event: "close", listener: () => void): this; - removeListener(event: "drain", listener: () => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - removeListener(event: "finish", listener: () => void): this; - removeListener(event: "pipe", listener: (src: Readable) => void): this; - removeListener(event: "unpipe", listener: (src: Readable) => void): this; - removeListener(event: string | symbol, listener: (...args: any[]) => void): this; -} + prependListener(event: 'close', listener: () => void): this; + prependListener(event: 'drain', listener: () => void): this; + prependListener(event: 'error', listener: (err: Error) => void): this; + prependListener(event: 'finish', listener: () => void): this; + prependListener(event: 'pipe', listener: (src: Readable) => void): this; + prependListener(event: 'unpipe', listener: (src: Readable) => void): this; + prependListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; + + prependOnceListener(event: 'close', listener: () => void): this; + prependOnceListener(event: 'drain', listener: () => void): this; + prependOnceListener(event: 'error', listener: (err: Error) => void): this; + prependOnceListener(event: 'finish', listener: () => void): this; + prependOnceListener(event: 'pipe', listener: (src: Readable) => void): this; + prependOnceListener(event: 'unpipe', listener: (src: Readable) => void): this; + prependOnceListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; + removeListener(event: 'close', listener: () => void): this; + removeListener(event: 'drain', listener: () => void): this; + removeListener(event: 'error', listener: (err: Error) => void): this; + removeListener(event: 'finish', listener: () => void): this; + removeListener(event: 'pipe', listener: (src: Readable) => void): this; + removeListener(event: 'unpipe', listener: (src: Readable) => void): this; + removeListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; +} export class Duplex extends Readable implements Writable { readonly writable: boolean; @@ -238,11 +289,22 @@ export class Duplex extends Readable implements Writable { readonly writableCorked: number; allowHalfOpen: boolean; constructor(opts?: DuplexOptions); - _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; - _writev?(chunks: Array<{ chunk: any, encoding: BufferEncoding }>, callback: (error?: Error | null) => void): void; + _write( + chunk: any, + encoding: BufferEncoding, + callback: (error?: Error | null) => void + ): void; + _writev?( + chunks: Array<{ chunk: any; encoding: BufferEncoding }>, + callback: (error?: Error | null) => void + ): void; _destroy(error: Error | null, callback: (error: Error | null) => void): void; _final(callback: (error?: Error | null) => void): void; - write(chunk: any, encoding?: BufferEncoding, cb?: (error: Error | null | undefined) => void): boolean; + write( + chunk: any, + encoding?: BufferEncoding, + cb?: (error: Error | null | undefined) => void + ): boolean; write(chunk: any, cb?: (error: Error | null | undefined) => void): boolean; setDefaultEncoding(encoding: BufferEncoding): this; end(cb?: () => void): this; @@ -309,7 +371,10 @@ export class Duplex extends Readable implements Writable { prependListener(event: 'readable', listener: () => void): this; prependListener(event: 'resume', listener: () => void): this; prependListener(event: 'unpipe', listener: (src: Readable) => void): this; - prependListener(event: string | symbol, listener: (...args: any[]) => void): this; + prependListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; prependOnceListener(event: 'close', listener: () => void): this; prependOnceListener(event: 'data', listener: (chunk: any) => void): this; prependOnceListener(event: 'drain', listener: () => void): this; @@ -321,7 +386,10 @@ export class Duplex extends Readable implements Writable { prependOnceListener(event: 'readable', listener: () => void): this; prependOnceListener(event: 'resume', listener: () => void): this; prependOnceListener(event: 'unpipe', listener: (src: Readable) => void): this; - prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; + prependOnceListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; removeListener(event: 'close', listener: () => void): this; removeListener(event: 'data', listener: (chunk: any) => void): this; removeListener(event: 'drain', listener: () => void): this; @@ -333,7 +401,10 @@ export class Duplex extends Readable implements Writable { removeListener(event: 'readable', listener: () => void): this; removeListener(event: 'resume', listener: () => void): this; removeListener(event: 'unpipe', listener: (src: Readable) => void): this; - removeListener(event: string | symbol, listener: (...args: any[]) => void): this; + removeListener( + event: string | symbol, + listener: (...args: any[]) => void + ): this; } interface DuplexOptions extends ReadableOptions, WritableOptions { @@ -344,19 +415,50 @@ interface DuplexOptions extends ReadableOptions, WritableOptions { writableHighWaterMark?: number | undefined; writableCorked?: number | undefined; read?(this: Duplex, size: number): void; - write?(this: Duplex, chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; - writev?(this: Duplex, chunks: Array<{ chunk: any, encoding: BufferEncoding }>, callback: (error?: Error | null) => void): void; + write?( + this: Duplex, + chunk: any, + encoding: BufferEncoding, + callback: (error?: Error | null) => void + ): void; + writev?( + this: Duplex, + chunks: Array<{ chunk: any; encoding: BufferEncoding }>, + callback: (error?: Error | null) => void + ): void; final?(this: Duplex, callback: (error?: Error | null) => void): void; - destroy?(this: Duplex, error: Error | null, callback: (error: Error | null) => void): void; + destroy?( + this: Duplex, + error: Error | null, + callback: (error: Error | null) => void + ): void; } interface TransformOptions extends DuplexOptions { read?(this: Transform, size: number): void; - write?(this: Transform, chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; - writev?(this: Transform, chunks: Array<{ chunk: any, encoding: BufferEncoding }>, callback: (error?: Error | null) => void): void; + write?( + this: Transform, + chunk: any, + encoding: BufferEncoding, + callback: (error?: Error | null) => void + ): void; + writev?( + this: Transform, + chunks: Array<{ chunk: any; encoding: BufferEncoding }>, + callback: (error?: Error | null) => void + ): void; final?(this: Transform, callback: (error?: Error | null) => void): void; - destroy?(this: Transform, error: Error | null, callback: (error: Error | null) => void): void; - transform?(this: Transform, chunk: any, encoding: BufferEncoding, callback: TransformCallback): void; + destroy?( + this: Transform, + error: Error | null, + callback: (error: Error | null) => void + ): void; + transform?( + this: Transform, + chunk: any, + encoding: BufferEncoding, + callback: TransformCallback + ): void; flush?(this: Transform, callback: TransformCallback): void; } @@ -364,6 +466,10 @@ type TransformCallback = (error?: Error | null, data?: any) => void; export class Transform extends Duplex { constructor(opts?: TransformOptions); - _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void; + _transform( + chunk: any, + encoding: BufferEncoding, + callback: TransformCallback + ): void; _flush(callback: TransformCallback): void; } diff --git a/src/node/internal/streams_transform.js b/src/node/internal/streams_transform.js index 7237a7e1196..1c6e58ad2de 100644 --- a/src/node/internal/streams_transform.js +++ b/src/node/internal/streams_transform.js @@ -26,7 +26,6 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ - // a transform stream is a readable/writable stream where you do // something with the data. Sometimes it's called a "filter", // but that's not a great name for it, since that implies a thing where @@ -69,19 +68,13 @@ // would be consumed, and then the rest would wait (un-transformed) until // the results of the previous transformed chunk were consumed. -'use strict' +'use strict'; -import { - ERR_METHOD_NOT_IMPLEMENTED -} from 'node-internal:internal_errors'; +import { ERR_METHOD_NOT_IMPLEMENTED } from 'node-internal:internal_errors'; -import { - Duplex, -} from 'node-internal:streams_duplex'; +import { Duplex } from 'node-internal:streams_duplex'; -import { - getHighWaterMark, -} from 'node-internal:streams_util'; +import { getHighWaterMark } from 'node-internal:streams_util'; Object.setPrototypeOf(Transform.prototype, Duplex.prototype); Object.setPrototypeOf(Transform, Duplex); @@ -94,7 +87,9 @@ export function Transform(options) { // TODO (ronag): This should preferably always be // applied but would be semver-major. Or even better; // make Transform a Readable with the Writable interface. - const readableHighWaterMark = options ? getHighWaterMark(options, 'readableHighWaterMark', true) : null; + const readableHighWaterMark = options + ? getHighWaterMark(options, 'readableHighWaterMark', true) + : null; if (readableHighWaterMark === 0) { // A Duplex will buffer both on the writable and readable side while // a Transform just wants to buffer hwm number of elements. To avoid @@ -107,7 +102,7 @@ export function Transform(options) { // a "bug" where we check needDrain before calling _write and not after. // Refs: https://github.com/nodejs/node/pull/32887 // Refs: https://github.com/nodejs/node/pull/35941 - writableHighWaterMark: options?.writableHighWaterMark || 0 + writableHighWaterMark: options?.writableHighWaterMark || 0, }; } Duplex.call(this, options); @@ -118,7 +113,8 @@ export function Transform(options) { this._readableState.sync = false; this[kCallback] = null; if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; + if (typeof options.transform === 'function') + this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } @@ -147,7 +143,7 @@ function final(cb) { if (cb) { cb(); } - }) + }); } else { this.push(null); if (cb) { @@ -164,8 +160,8 @@ function prefinish() { Transform.prototype._final = final; Transform.prototype._transform = function () { - throw new ERR_METHOD_NOT_IMPLEMENTED('_transform()') -} + throw new ERR_METHOD_NOT_IMPLEMENTED('_transform()'); +}; Transform.prototype._write = function (chunk, encoding, callback) { const rState = this._readableState; @@ -190,8 +186,8 @@ Transform.prototype._write = function (chunk, encoding, callback) { } else { this[kCallback] = callback; } - }) -} + }); +}; Transform.prototype._read = function (_size) { if (this[kCallback]) { @@ -199,7 +195,7 @@ Transform.prototype._read = function (_size) { this[kCallback] = null; callback(); } -} +}; Object.setPrototypeOf(PassThrough.prototype, Transform.prototype); Object.setPrototypeOf(PassThrough, Transform); @@ -215,4 +211,4 @@ export function PassThrough(options) { PassThrough.prototype._transform = function (chunk, _, cb) { cb(null, chunk); -} +}; diff --git a/src/node/internal/streams_util.js b/src/node/internal/streams_util.js index fbe7a567002..e7eec219264 100644 --- a/src/node/internal/streams_util.js +++ b/src/node/internal/streams_util.js @@ -61,12 +61,14 @@ export function isReadableNodeStream(obj, strict = false) { obj && typeof obj.pipe === 'function' && typeof obj.on === 'function' && - (!strict || (typeof obj.pause === 'function' && - typeof obj.resume === 'function')) && + (!strict || + (typeof obj.pause === 'function' && + typeof obj.resume === 'function')) && (!obj._writableState || ((_obj$_readableState = obj._readableState) === null || - _obj$_readableState === undefined ? undefined - : _obj$_readableState.readable) !== false) && + _obj$_readableState === undefined + ? undefined + : _obj$_readableState.readable) !== false) && // Duplex (!obj._writableState || obj._readableState) ) // Writable has .pipe. @@ -82,8 +84,9 @@ export function isWritableNodeStream(obj) { typeof obj.on === 'function' && (!obj._readableState || ((_obj$_writableState = obj._writableState) === null || - _obj$_writableState === undefined ? undefined - : _obj$_writableState.writable) !== false) + _obj$_writableState === undefined + ? undefined + : _obj$_writableState.writable) !== false) ) // Duplex ); } @@ -103,10 +106,8 @@ export function isNodeStream(obj) { obj && (obj._readableState || obj._writableState || - (typeof obj.write === 'function' && - typeof obj.on === 'function') || - (typeof obj.pipe === 'function' && - typeof obj.on === 'function')) + (typeof obj.write === 'function' && typeof obj.on === 'function') || + (typeof obj.pipe === 'function' && typeof obj.on === 'function')) ); } @@ -114,8 +115,10 @@ export function isIterable(obj, isAsync = false) { if (obj == null) return false; if (isAsync === true) return typeof obj[Symbol.asyncIterator] === 'function'; if (isAsync === false) return typeof obj[Symbol.iterator] === 'function'; - return typeof obj[Symbol.asyncIterator] === 'function' || - typeof obj[Symbol.iterator] === 'function'; + return ( + typeof obj[Symbol.asyncIterator] === 'function' || + typeof obj[Symbol.iterator] === 'function' + ); } export function isDestroyed(stream) { @@ -123,7 +126,11 @@ export function isDestroyed(stream) { const wState = stream._writableState; const rState = stream._readableState; const state = wState || rState; - return !!(stream.destroyed || stream[kDestroyed] || (state !== null && state !== undefined && state.destroyed)); + return !!( + stream.destroyed || + stream[kDestroyed] || + (state !== null && state !== undefined && state.destroyed) + ); } export function isWritableEnded(stream) { @@ -131,7 +138,12 @@ export function isWritableEnded(stream) { if (stream.writableEnded === true) return true; const wState = stream._writableState; if (wState !== null && wState !== undefined && wState.errored) return false; - if (typeof (wState === null || wState === undefined ? undefined : wState.ended) !== 'boolean') return null; + if ( + typeof (wState === null || wState === undefined + ? undefined + : wState.ended) !== 'boolean' + ) + return null; return wState.ended; } @@ -140,8 +152,16 @@ export function isWritableFinished(stream, strict = false) { if (stream.writableFinished === true) return true; const wState = stream._writableState; if (wState !== null && wState !== undefined && wState.errored) return false; - if (typeof (wState === null || wState === undefined ? undefined : wState.finished) !== 'boolean') return null; - return !!(wState.finished || (strict === false && wState.ended === true && wState.length === 0)); + if ( + typeof (wState === null || wState === undefined + ? undefined + : wState.finished) !== 'boolean' + ) + return null; + return !!( + wState.finished || + (strict === false && wState.ended === true && wState.length === 0) + ); } export function isReadableEnded(stream) { @@ -149,7 +169,12 @@ export function isReadableEnded(stream) { if (stream.readableEnded === true) return true; const rState = stream._readableState; if (!rState || rState.errored) return false; - if (typeof (rState === null || rState === undefined ? undefined : rState.ended) !== 'boolean') return null; + if ( + typeof (rState === null || rState === undefined + ? undefined + : rState.ended) !== 'boolean' + ) + return null; return rState.ended; } @@ -157,21 +182,45 @@ export function isReadableFinished(stream, strict = false) { if (!isReadableNodeStream(stream)) return null; const rState = stream._readableState; if (rState !== null && rState !== undefined && rState.errored) return false; - if (typeof (rState === null || rState === undefined ? undefined : rState.endEmitted) !== 'boolean') return null; - return !!(rState.endEmitted || (strict === false && rState.ended === true && rState.length === 0)); + if ( + typeof (rState === null || rState === undefined + ? undefined + : rState.endEmitted) !== 'boolean' + ) + return null; + return !!( + rState.endEmitted || + (strict === false && rState.ended === true && rState.length === 0) + ); } export function isReadable(stream) { if (stream && stream[kIsReadable] != null) return stream[kIsReadable]; - if (typeof (stream === null || stream === undefined ? undefined : stream.readable) !== 'boolean') return null; + if ( + typeof (stream === null || stream === undefined + ? undefined + : stream.readable) !== 'boolean' + ) + return null; if (isDestroyed(stream)) return false; - return isReadableNodeStream(stream) && stream.readable && !isReadableFinished(stream); + return ( + isReadableNodeStream(stream) && + stream.readable && + !isReadableFinished(stream) + ); } export function isWritable(stream) { - if (typeof (stream === null || stream === undefined ? undefined : stream.writable) !== 'boolean') return null; + if ( + typeof (stream === null || stream === undefined + ? undefined + : stream.writable) !== 'boolean' + ) + return null; if (isDestroyed(stream)) return false; - return isWritableNodeStream(stream) && stream.writable && !isWritableEnded(stream); + return ( + isWritableNodeStream(stream) && stream.writable && !isWritableEnded(stream) + ); } export function isFinished(stream, opts = {}) { @@ -181,12 +230,18 @@ export function isFinished(stream, opts = {}) { if (isDestroyed(stream)) { return true; } - if ((opts === null || opts === undefined ? undefined : opts.readable) !== false && - isReadable(stream)) { + if ( + (opts === null || opts === undefined ? undefined : opts.readable) !== + false && + isReadable(stream) + ) { return false; } - if ((opts === null || opts === undefined ? undefined : opts.writable) !== false && - isWritable(stream)) { + if ( + (opts === null || opts === undefined ? undefined : opts.writable) !== + false && + isWritable(stream) + ) { return false; } return true; @@ -201,9 +256,11 @@ export function isWritableErrored(stream) { return stream.writableErrored; } return (_stream$_writableStat = - (_stream$_writableStat2 = stream._writableState) === null || _stream$_writableStat2 === undefined + (_stream$_writableStat2 = stream._writableState) === null || + _stream$_writableStat2 === undefined ? undefined - : _stream$_writableStat2.errored) !== null && _stream$_writableStat !== undefined + : _stream$_writableStat2.errored) !== null && + _stream$_writableStat !== undefined ? _stream$_writableStat : null; } @@ -217,35 +274,41 @@ export function isReadableErrored(stream) { return stream.readableErrored; } return (_stream$_readableStat = - (_stream$_readableStat2 = stream._readableState) === null || _stream$_readableStat2 === undefined + (_stream$_readableStat2 = stream._readableState) === null || + _stream$_readableStat2 === undefined ? undefined - : _stream$_readableStat2.errored) !== null && _stream$_readableStat !== undefined + : _stream$_readableStat2.errored) !== null && + _stream$_readableStat !== undefined ? _stream$_readableStat : null; } export function isClosed(stream) { if (!isNodeStream(stream)) { - return null + return null; } if (typeof stream.closed === 'boolean') { - return stream.closed + return stream.closed; } - const wState = stream._writableState - const rState = stream._readableState + const wState = stream._writableState; + const rState = stream._readableState; if ( - typeof (wState === null || wState === undefined ? undefined : wState.closed) === 'boolean' || - typeof (rState === null || rState === undefined ? undefined : rState.closed) === 'boolean' + typeof (wState === null || wState === undefined + ? undefined + : wState.closed) === 'boolean' || + typeof (rState === null || rState === undefined + ? undefined + : rState.closed) === 'boolean' ) { return ( (wState === null || wState === undefined ? undefined : wState.closed) || (rState === null || rState === undefined ? undefined : rState.closed) - ) + ); } if (typeof stream._closed === 'boolean' && isOutgoingMessage(stream)) { - return stream._closed + return stream._closed; } - return null + return null; } // TODO(later): We do not actually support OutgoingMessage yet. Might not ever? @@ -272,8 +335,9 @@ export function isServerRequest(stream) { return ( typeof stream._consuming === 'boolean' && typeof stream._dumped === 'boolean' && - ((_stream$req = stream.req) === null || _stream$req === undefined ? undefined : _stream$req.upgradeOrConnect) === - undefined + ((_stream$req = stream.req) === null || _stream$req === undefined + ? undefined + : _stream$req.upgradeOrConnect) === undefined ); } @@ -283,7 +347,8 @@ export function willEmitClose(stream) { const rState = stream._readableState; const state = wState || rState; return ( - (!state && isServerResponse(stream)) || !!(state && state.autoDestroy && state.emitClose && state.closed === false) + (!state && isServerResponse(stream)) || + !!(state && state.autoDestroy && state.emitClose && state.closed === false) ); } @@ -291,7 +356,8 @@ export function isDisturbed(stream) { let _stream$kIsDisturbed; return !!( stream && - ((_stream$kIsDisturbed = stream[kIsDisturbed]) !== null && _stream$kIsDisturbed !== undefined + ((_stream$kIsDisturbed = stream[kIsDisturbed]) !== null && + _stream$kIsDisturbed !== undefined ? _stream$kIsDisturbed : stream.readableDidRead || stream.readableAborted) ); @@ -307,7 +373,7 @@ export function isErrored(stream) { _stream$_readableStat3, _stream$_writableStat3, _stream$_readableStat4, - _stream$_writableStat4 + _stream$_writableStat4; return !!( stream && ((_ref = @@ -315,61 +381,73 @@ export function isErrored(stream) { (_ref3 = (_ref4 = (_ref5 = - (_stream$kIsErrored = stream[kIsErrored]) !== null && _stream$kIsErrored !== undefined + (_stream$kIsErrored = stream[kIsErrored]) !== null && + _stream$kIsErrored !== undefined ? _stream$kIsErrored : stream.readableErrored) !== null && _ref5 !== undefined ? _ref5 : stream.writableErrored) !== null && _ref4 !== undefined ? _ref4 - : (_stream$_readableStat3 = stream._readableState) === null || _stream$_readableStat3 === undefined - ? undefined - : _stream$_readableStat3.errorEmitted) !== null && _ref3 !== undefined + : (_stream$_readableStat3 = stream._readableState) === null || + _stream$_readableStat3 === undefined + ? undefined + : _stream$_readableStat3.errorEmitted) !== null && + _ref3 !== undefined ? _ref3 - : (_stream$_writableStat3 = stream._writableState) === null || _stream$_writableStat3 === undefined - ? undefined - : _stream$_writableStat3.errorEmitted) !== null && _ref2 !== undefined + : (_stream$_writableStat3 = stream._writableState) === null || + _stream$_writableStat3 === undefined + ? undefined + : _stream$_writableStat3.errorEmitted) !== null && + _ref2 !== undefined ? _ref2 - : (_stream$_readableStat4 = stream._readableState) === null || _stream$_readableStat4 === undefined - ? undefined - : _stream$_readableStat4.errored) !== null && _ref !== undefined + : (_stream$_readableStat4 = stream._readableState) === null || + _stream$_readableStat4 === undefined + ? undefined + : _stream$_readableStat4.errored) !== null && _ref !== undefined ? _ref - : (_stream$_writableStat4 = stream._writableState) === null || _stream$_writableStat4 === undefined - ? undefined - : _stream$_writableStat4.errored) - ) + : (_stream$_writableStat4 = stream._writableState) === null || + _stream$_writableStat4 === undefined + ? undefined + : _stream$_writableStat4.errored) + ); } export const nop = () => {}; export function once(callback) { - let called = false + let called = false; return function (...args) { if (called) { - return + return; } - called = true - callback.apply(this, args) - } + called = true; + callback.apply(this, args); + }; } // ====================================================================================== // highWaterMark handling export function highWaterMarkFrom(options, isDuplex, duplexKey) { - return options.highWaterMark != null ? options.highWaterMark : - isDuplex ? options[duplexKey] : null + return options.highWaterMark != null + ? options.highWaterMark + : isDuplex + ? options[duplexKey] + : null; } export function getDefaultHighWaterMark(objectMode = false) { - return objectMode ? 16 : 16 * 1024 + return objectMode ? 16 : 16 * 1024; } export function setDefaultHighWaterMark() { - throw new Error("Setting the default high water mark is currently not implemented"); + throw new Error( + 'Setting the default high water mark is currently not implemented' + ); } export function getHighWaterMark(state, options, duplexKey, isDuplex) { - const hwm = highWaterMarkFrom(options, isDuplex, duplexKey) + const hwm = highWaterMarkFrom(options, isDuplex, duplexKey); if (hwm != null) { if (!Number.isInteger(hwm) || hwm < 0) { const name = isDuplex ? `options.${duplexKey}` : 'options.highWaterMark'; @@ -379,7 +457,7 @@ export function getHighWaterMark(state, options, duplexKey, isDuplex) { } // Default value - return getDefaultHighWaterMark(state.objectMode) + return getDefaultHighWaterMark(state.objectMode); } // ====================================================================================== @@ -393,10 +471,10 @@ export function addAbortSignal(signal, stream) { const onAbort = () => { stream.destroy( new AbortError(undefined, { - cause: signal.reason + cause: signal.reason, }) ); - } + }; if (signal.aborted) { onAbort(); } else { @@ -418,7 +496,7 @@ export class BufferList { const entry = { data: v, next: null, - } + }; if (this.length > 0) this.tail.next = entry; else this.head = entry; this.tail = entry; @@ -428,7 +506,7 @@ export class BufferList { const entry = { data: v, next: this.head, - } + }; if (this.length === 0) this.tail = entry; this.head = entry; ++this.length; @@ -505,8 +583,8 @@ export class BufferList { n -= str.length; } else { if (n === str.length) { - ret += str - ++c + ret += str; + ++c; if (p.next) this.head = p.next; else this.head = this.tail = null; } else { @@ -545,7 +623,7 @@ export class BufferList { } break; } - ++c + ++c; } while ((p = p.next) !== null); this.length -= c; return ret; @@ -556,7 +634,7 @@ export class BufferList { // TODO(later): We do not current implement Node.js' Request object. Might never? function isRequest(stream) { - return stream && stream.setHeader && typeof stream.abort === 'function' + return stream && stream.setHeader && typeof stream.abort === 'function'; } export function eos(stream, options, callback) { @@ -573,11 +651,13 @@ export function eos(stream, options, callback) { validateAbortSignal(options.signal, 'options.signal'); callback = once(callback); const readable = - (_options$readable = options.readable) !== null && _options$readable !== undefined + (_options$readable = options.readable) !== null && + _options$readable !== undefined ? _options$readable : isReadableNodeStream(stream); const writable = - (_options$writable = options.writable) !== null && _options$writable !== undefined + (_options$writable = options.writable) !== null && + _options$writable !== undefined ? _options$writable : isWritableNodeStream(stream); if (!isNodeStream(stream)) { @@ -596,8 +676,10 @@ export function eos(stream, options, callback) { // common ecosystem modules that do properly emit 'close' but fail // this generic check. let _willEmitClose = - willEmitClose(stream) && isReadableNodeStream(stream) === readable && isWritableNodeStream(stream) === writable; - let writableFinished = isWritableFinished((stream), false); + willEmitClose(stream) && + isReadableNodeStream(stream) === readable && + isWritableNodeStream(stream) === writable; + let writableFinished = isWritableFinished(stream, false); const onfinish = () => { writableFinished = true; // Stream should not be destroyed here. If it is that @@ -635,15 +717,17 @@ export function eos(stream, options, callback) { let closed = isClosed(stream); const onclose = () => { closed = true; - const errored = isWritableErrored(stream) || isReadableErrored(stream) + const errored = isWritableErrored(stream) || isReadableErrored(stream); if (errored && typeof errored !== 'boolean') { return callback.call(stream, errored); } if (readable && !readableFinished && isReadableNodeStream(stream, true)) { - if (!isReadableFinished(stream, false)) return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + if (!isReadableFinished(stream, false)) + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); } if (writable && !writableFinished) { - if (!isWritableFinished(stream, false)) return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + if (!isWritableFinished(stream, false)) + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); } callback.call(stream); }; @@ -706,32 +790,32 @@ export function eos(stream, options, callback) { stream.removeListener('complete', onfinish); stream.removeListener('abort', onclose); stream.removeListener('request', onrequest); - if (stream.req) stream .req.removeListener('finish', onfinish); + if (stream.req) stream.req.removeListener('finish', onfinish); stream.removeListener('end', onlegacyfinish); stream.removeListener('close', onlegacyfinish); stream.removeListener('finish', onfinish); stream.removeListener('end', onend); stream.removeListener('error', onerror); stream.removeListener('close', onclose); - } + }; if (options.signal && !closed) { const abort = () => { // Keep it because cleanup removes it. - const endCallback = callback - cleanup() + const endCallback = callback; + cleanup(); endCallback.call( stream, new AbortError(undefined, { - cause: options.signal?.reason + cause: options.signal?.reason, }) - ) - } + ); + }; if (options.signal.aborted) { process.nextTick(abort); } else { const originalCallback = callback; callback = once((...args) => { - options.signal.removeEventListener('abort', abort) + options.signal.removeEventListener('abort', abort); originalCallback.apply(stream, args); }); options.signal.addEventListener('abort', abort); @@ -748,7 +832,7 @@ export function finished(stream, opts) { } else { resolve(); } - }) + }); }); } @@ -925,7 +1009,7 @@ export function errorOrDestroy(stream, err, sync = false) { if (sync) { process.nextTick(emitErrorNT, stream, err); } else { - emitErrorNT(stream, err) + emitErrorNT(stream, err); } } } @@ -942,7 +1026,7 @@ export function construct(stream, cb) { if (w) { w.constructed = false; } - stream.once(kConstruct, cb) + stream.once(kConstruct, cb); if (stream.listenerCount(kConstruct) > 1) { // Duplex return; @@ -954,7 +1038,10 @@ function constructNT(stream) { let called = false; function onConstruct(err) { if (called) { - errorOrDestroy(stream, err !== null && err !== undefined ? err : new ERR_MULTIPLE_CALLBACK()); + errorOrDestroy( + stream, + err !== null && err !== undefined ? err : new ERR_MULTIPLE_CALLBACK() + ); return; } called = true; @@ -1026,4 +1113,3 @@ export function destroyer(stream, err) { stream[kDestroyed] = true; } } - diff --git a/src/node/internal/streams_writable.js b/src/node/internal/streams_writable.js index e6211f3be85..aadc98b1b46 100644 --- a/src/node/internal/streams_writable.js +++ b/src/node/internal/streams_writable.js @@ -26,17 +26,11 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - EventEmitter, -} from 'node-internal:events'; +import { EventEmitter } from 'node-internal:events'; -import { - Stream -} from 'node-internal:streams_legacy'; +import { Stream } from 'node-internal:streams_legacy'; -import { - Buffer, -} from 'node-internal:internal_buffer'; +import { Buffer } from 'node-internal:internal_buffer'; import * as process from 'node-internal:process'; @@ -66,7 +60,7 @@ import { ERR_STREAM_ALREADY_FINISHED, ERR_STREAM_NULL_VALUES, ERR_STREAM_WRITE_AFTER_END, - ERR_UNKNOWN_ENCODING + ERR_UNKNOWN_ENCODING, } from 'node-internal:internal_errors'; import { isDuplexInstance } from 'node-internal:streams_duplex'; @@ -84,8 +78,9 @@ export function WritableState(options, stream, isDuplex) { // Object stream flag to indicate whether or not this stream // contains buffers or objects. - this.objectMode = !!(options?.objectMode); - if (isDuplex) this.objectMode = this.objectMode || !!(options?.writableObjectMode); + this.objectMode = !!options?.objectMode; + if (isDuplex) + this.objectMode = this.objectMode || !!options?.writableObjectMode; // The point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if @@ -118,7 +113,7 @@ export function WritableState(options, stream, isDuplex) { // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = (options?.defaultEncoding) || 'utf8'; + this.defaultEncoding = options?.defaultEncoding || 'utf8'; // Not an actual buffer we keep track of, but a measurement // of how much we're waiting to get pushed to some underlying @@ -202,12 +197,12 @@ function resetBuffer(state) { WritableState.prototype.getBuffer = function getBuffer() { return this.buffered.slice(this.bufferedIndex); -} +}; Object.defineProperty(WritableState.prototype, 'bufferedRequestCount', { get() { return this.buffered.length - this.bufferedIndex; - } + }, }); // ====================================================================================== @@ -230,14 +225,16 @@ export function Writable(options) { // Checking for a Stream.Duplex instance is faster here instead of inside // the WritableState constructor, at least with V8 6.5. const isDuplex = isDuplexInstance(this); - if (!isDuplex && !Writable[Symbol.hasInstance](this)) return new Writable(options); - this._writableState = new WritableState(options, this, isDuplex) + if (!isDuplex && !Writable[Symbol.hasInstance](this)) + return new Writable(options); + this._writableState = new WritableState(options, this, isDuplex); if (options) { if (typeof options.write === 'function') this._write = options.write; if (typeof options.writev === 'function') this._writev = options.writev; if (typeof options.destroy === 'function') this._destroy = options.destroy; if (typeof options.final === 'function') this._final = options.final; - if (typeof options.construct === 'function') this._construct = options.construct; + if (typeof options.construct === 'function') + this._construct = options.construct; if (options.signal) addAbortSignal(options.signal, this); } Stream.call(this, options); @@ -247,7 +244,7 @@ export function Writable(options) { clearBuffer(this, state); } finishMaybe(this, state); - }) + }); } Object.defineProperty(Writable, Symbol.hasInstance, { @@ -255,13 +252,13 @@ Object.defineProperty(Writable, Symbol.hasInstance, { if (Function.prototype[Symbol.hasInstance].call(this, object)) return true; if (this !== Writable) return false; return object?._writableState instanceof WritableState; - } -}) + }, +}); // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function (_1, _2) { errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); -} +}; function _write(stream, chunk, encoding, cb) { const state = stream._writableState; @@ -289,7 +286,11 @@ function _write(stream, chunk, encoding, cb) { chunk = Stream._uint8ArrayToBuffer(chunk); encoding = 'buffer'; } else { - throw new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + throw new ERR_INVALID_ARG_TYPE( + 'chunk', + ['string', 'Buffer', 'Uint8Array'], + chunk + ); } } let err; @@ -315,7 +316,7 @@ Writable.prototype.write = write; Writable.prototype.cork = function () { this._writableState.corked++; -} +}; Writable.prototype.uncork = function () { const state = this._writableState; @@ -323,7 +324,7 @@ Writable.prototype.uncork = function () { state.corked--; if (!state.writing) clearBuffer(this, state); } -} +}; function setDefaultEncoding(encoding) { if (typeof encoding === 'string') encoding = encoding.toLowerCase(); @@ -433,14 +434,17 @@ function onwrite(stream, er) { // the same. In that case, we do not schedule a new nextTick(), but // rather just increase a counter, to improve performance and avoid // memory allocations. - if (state.afterWriteTickInfo !== null && state.afterWriteTickInfo.cb === cb) { + if ( + state.afterWriteTickInfo !== null && + state.afterWriteTickInfo.cb === cb + ) { state.afterWriteTickInfo.count++; } else { state.afterWriteTickInfo = { count: 1, cb, stream, - state + state, }; process.nextTick(afterWriteTick, state.afterWriteTickInfo); } @@ -456,7 +460,8 @@ function afterWriteTick({ stream, state, count, cb }) { } function afterWrite(stream, state, count, cb) { - const needDrain = !state.ending && !stream.destroyed && state.length === 0 && state.needDrain; + const needDrain = + !state.ending && !stream.destroyed && state.length === 0 && state.needDrain; if (needDrain) { state.needDrain = false; stream.emit('drain'); @@ -484,22 +489,30 @@ function errorBuffer(state) { callback( (_state$errored = state.errored) !== null && _state$errored !== undefined ? _state$errored - : new ERR_STREAM_DESTROYED('write')); + : new ERR_STREAM_DESTROYED('write') + ); } const onfinishCallbacks = state[kOnFinished].splice(0); for (let i = 0; i < onfinishCallbacks.length; i++) { let _state$errored2; onfinishCallbacks[i]( - (_state$errored2 = state.errored) !== null && _state$errored2 !== undefined + (_state$errored2 = state.errored) !== null && + _state$errored2 !== undefined ? _state$errored2 - : new ERR_STREAM_DESTROYED('end')); + : new ERR_STREAM_DESTROYED('end') + ); } resetBuffer(state); } // If there's something in the buffer waiting, then process it. function clearBuffer(stream, state) { - if (state.corked || state.bufferProcessing || state.destroyed || !state.constructed) { + if ( + state.corked || + state.bufferProcessing || + state.destroyed || + !state.constructed + ) { return; } const { buffered, bufferedIndex, objectMode } = state; @@ -515,7 +528,7 @@ function clearBuffer(stream, state) { ? nop : (err) => { for (let n = i; n < buffered.length; ++n) { - buffered[n].callback(err) + buffered[n].callback(err); } }; // Make a copy of `buffered` if it's going to be used by `callback` above, @@ -530,7 +543,7 @@ function clearBuffer(stream, state) { buffered[i++] = null; const len = objectMode ? 1 : chunk.length; doWrite(stream, state, false, len, chunk, encoding, callback); - } while (i < buffered.length && !state.writing) + } while (i < buffered.length && !state.writing); if (i === buffered.length) { resetBuffer(state); } else if (i > 256) { @@ -549,15 +562,15 @@ Writable.prototype._write = function (chunk, encoding, cb) { [ { chunk, - encoding - } + encoding, + }, ], - cb, + cb ); } else { throw new ERR_METHOD_NOT_IMPLEMENTED('_write()'); } -} +}; Writable.prototype._writev = null; @@ -725,83 +738,90 @@ function finish(stream, state) { Object.defineProperties(Writable.prototype, { closed: { get() { - return !!(this._writableState?.closed); - } + return !!this._writableState?.closed; + }, }, destroyed: { get() { - return !!(this._writableState?.destroyed); + return !!this._writableState?.destroyed; }, set(value) { // Backward compatibility, the user is explicitly managing destroyed. if (this._writableState) { - this._writableState.destroyed = value + this._writableState.destroyed = value; } - } + }, }, errored: { enumerable: false, get() { return this._writableState?.errored || null; - } + }, }, writable: { get() { - const w = this._writableState + const w = this._writableState; // w.writable === false means that this is part of a Duplex stream // where the writable side was disabled upon construction. // Compat. The user might manually disable writable side through // deprecated setter. - return !!w && w.writable !== false && !w.destroyed && !w.errored && !w.ending && !w.ended; + return ( + !!w && + w.writable !== false && + !w.destroyed && + !w.errored && + !w.ending && + !w.ended + ); }, set(val) { // Backwards compatible. if (this._writableState) { this._writableState.writable = !!val; } - } + }, }, writableFinished: { get() { - return !!(this._writableState?.finished); - } + return !!this._writableState?.finished; + }, }, writableObjectMode: { get() { - return !!(this._writableState?.objectMode); - } + return !!this._writableState?.objectMode; + }, }, writableBuffer: { get() { return this._writableState?.getBuffer(); - } + }, }, writableEnded: { get() { - return !!(this._writableState?.ending); - } + return !!this._writableState?.ending; + }, }, writableNeedDrain: { get() { const wState = this._writableState; if (!wState) return false; return !wState.destroyed && !wState.ending && wState.needDrain; - } + }, }, writableHighWaterMark: { get() { return this._writableState?.highWaterMark; - } + }, }, writableCorked: { get() { return this._writableState?.corked | 0; - } + }, }, writableLength: { get() { return this._writableState?.length; - } + }, }, writableAborted: { enumerable: false, @@ -810,37 +830,40 @@ Object.defineProperties(Writable.prototype, { this._writableState.writable !== false && (this._writableState.destroyed || this._writableState.errored) && !this._writableState.finished - ) - } - } + ); + }, + }, }); Writable.prototype.destroy = function (err, cb) { const state = this._writableState; // Invoke pending callbacks. - if (!state.destroyed && (state.bufferedIndex < state.buffered.length || state[kOnFinished].length)) { + if ( + !state.destroyed && + (state.bufferedIndex < state.buffered.length || state[kOnFinished].length) + ) { process.nextTick(errorBuffer, state); } destroy.call(this, err, cb); return this; -} +}; -Writable.prototype._undestroy = undestroy +Writable.prototype._undestroy = undestroy; Writable.prototype._destroy = function (err, cb) { if (cb) cb(err); -} +}; Writable.prototype[EventEmitter.captureRejectionSymbol] = function (err) { this.destroy(err); -} +}; export function fromWeb(writableStream, options) { - return newStreamWritableFromWritableStream(writableStream, options) + return newStreamWritableFromWritableStream(writableStream, options); } export function toWeb(streamWritable) { - return newWritableStreamFromStreamWritable(streamWritable) + return newWritableStreamFromStreamWritable(streamWritable); } Writable.fromWeb = fromWeb; diff --git a/src/node/internal/util.d.ts b/src/node/internal/util.d.ts index 30ce928307c..a39181b230c 100644 --- a/src/node/internal/util.d.ts +++ b/src/node/internal/util.d.ts @@ -18,7 +18,7 @@ export abstract class MIMEType { export abstract class MIMEParams { public constructor(); public delete(name: string): void; - public get(name: string): string|undefined; + public get(name: string): string | undefined; public has(name: string): boolean; public set(name: string, value: string): void; public entries(): Iterable; @@ -30,7 +30,10 @@ export const kResourceTypeInspect: unique symbol; export const ALL_PROPERTIES: 0; export const ONLY_ENUMERABLE: 1; -export function getOwnNonIndexProperties(value: unknown, filter: typeof ALL_PROPERTIES | typeof ONLY_ENUMERABLE): PropertyKey[]; +export function getOwnNonIndexProperties( + value: unknown, + filter: typeof ALL_PROPERTIES | typeof ONLY_ENUMERABLE +): PropertyKey[]; export const kPending: 0; export const kFulfilled: 1; @@ -87,7 +90,9 @@ export function isInt8Array(value: unknown): value is Int8Array; export function isInt16Array(value: unknown): value is Int16Array; export function isInt32Array(value: unknown): value is Int32Array; export function isMap(value: unknown): value is Map; -export function isMapIterator(value: unknown): value is IterableIterator; +export function isMapIterator( + value: unknown +): value is IterableIterator; export function isModuleNamespaceObject(value: unknown): boolean; export function isNativeError(value: unknown): value is Error; export function isNumberObject(value: unknown): value is Number; @@ -95,7 +100,9 @@ export function isPromise(value: unknown): value is Promise; export function isProxy(value: unknown): boolean; export function isRegExp(value: unknown): value is RegExp; export function isSet(value: unknown): value is Set; -export function isSetIterator(value: unknown): value is IterableIterator; +export function isSetIterator( + value: unknown +): value is IterableIterator; export function isSharedArrayBuffer(value: unknown): value is SharedArrayBuffer; export function isStringObject(value: unknown): value is String; export function isSymbolObject(value: unknown): value is Symbol; @@ -106,7 +113,11 @@ export function isUint16Array(value: unknown): value is Uint16Array; export function isUint32Array(value: unknown): value is Uint32Array; export function isWeakMap(value: unknown): value is WeakMap; export function isWeakSet(value: unknown): value is WeakSet; -export function isAnyArrayBuffer(value: unknown): value is ArrayBuffer | SharedArrayBuffer; -export function isBoxedPrimitive(value: unknown): value is Number | String | Boolean | BigInt | Symbol; +export function isAnyArrayBuffer( + value: unknown +): value is ArrayBuffer | SharedArrayBuffer; +export function isBoxedPrimitive( + value: unknown +): value is Number | String | Boolean | BigInt | Symbol; export function getBuiltinModule(id: string): any; diff --git a/src/node/internal/validators.ts b/src/node/internal/validators.ts index 09efb29e877..79c67e1e132 100644 --- a/src/node/internal/validators.ts +++ b/src/node/internal/validators.ts @@ -29,40 +29,41 @@ //import { codes } from "node-internal:error-codes"; // import { hideStackFrames } from "node-internal:hide-stack-frames"; -import { isArrayBufferView } from "node-internal:internal_types"; -import { normalizeEncoding } from "node-internal:internal_utils"; +import { isArrayBufferView } from 'node-internal:internal_types'; +import { normalizeEncoding } from 'node-internal:internal_utils'; import { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_OUT_OF_RANGE, -} from "node-internal:internal_errors"; +} from 'node-internal:internal_errors'; import { default as bufferUtil } from 'node-internal:buffer'; // TODO(someday): Not current implementing parseFileMode, validatePort export const isInt32 = (value: any) => value === (value | 0); -export const isUint32 = (value: any) => value === (value >>> 0); +export const isUint32 = (value: any) => value === value >>> 0; -export function validateBuffer(buffer: unknown, name = "buffer") { +export function validateBuffer(buffer: unknown, name = 'buffer') { if (!isArrayBufferView(buffer)) { throw new ERR_INVALID_ARG_TYPE( name, - ["Buffer", "TypedArray", "DataView"], - buffer, + ['Buffer', 'TypedArray', 'DataView'], + buffer ); } -}; +} export function validateInteger( - value: unknown, - name: string, - min = Number.MIN_SAFE_INTEGER, - max = Number.MAX_SAFE_INTEGER) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + value: unknown, + name: string, + min = Number.MIN_SAFE_INTEGER, + max = Number.MAX_SAFE_INTEGER +) { + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } if (!Number.isInteger(value)) { - throw new ERR_OUT_OF_RANGE(name, "an integer", value); + throw new ERR_OUT_OF_RANGE(name, 'an integer', value); } if (value < min || value > max) { throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value); @@ -73,9 +74,13 @@ export interface ValidateObjectOptions { allowArray?: boolean; allowFunction?: boolean; nullable?: boolean; -}; +} -export function validateObject(value: unknown, name: string, options?: ValidateObjectOptions) { +export function validateObject( + value: unknown, + name: string, + options?: ValidateObjectOptions +) { const useDefaultOptions = options == null; const allowArray = useDefaultOptions ? false : options.allowArray; const allowFunction = useDefaultOptions ? false : options.allowFunction; @@ -83,22 +88,26 @@ export function validateObject(value: unknown, name: string, options?: ValidateO if ( (!nullable && value === null) || (!allowArray && Array.isArray(value)) || - (typeof value !== "object" && ( - !allowFunction || typeof value !== "function" - )) + (typeof value !== 'object' && + (!allowFunction || typeof value !== 'function')) ) { - throw new ERR_INVALID_ARG_TYPE(name, "Object", value); + throw new ERR_INVALID_ARG_TYPE(name, 'Object', value); } -}; +} -export function validateInt32(value: any, name: string, min = -2147483648, max = 2147483647) { +export function validateInt32( + value: any, + name: string, + min = -2147483648, + max = 2147483647 +) { if (!isInt32(value)) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } if (!Number.isInteger(value)) { - throw new ERR_OUT_OF_RANGE(name, "an integer", value); + throw new ERR_OUT_OF_RANGE(name, 'an integer', value); } throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value); @@ -109,55 +118,54 @@ export function validateInt32(value: any, name: string, min = -2147483648, max = } } -export function validateUint32(value: unknown, name: string, positive?: boolean) { +export function validateUint32( + value: unknown, + name: string, + positive?: boolean +) { if (!isUint32(value)) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } if (!Number.isInteger(value)) { - throw new ERR_OUT_OF_RANGE(name, "an integer", value); + throw new ERR_OUT_OF_RANGE(name, 'an integer', value); } const min = positive ? 1 : 0; // 2 ** 32 === 4294967296 - throw new ERR_OUT_OF_RANGE( - name, - `>= ${min} && < 4294967296`, - value, - ); + throw new ERR_OUT_OF_RANGE(name, `>= ${min} && < 4294967296`, value); } if (positive && value === 0) { - throw new ERR_OUT_OF_RANGE(name, ">= 1 && < 4294967296", value); + throw new ERR_OUT_OF_RANGE(name, '>= 1 && < 4294967296', value); } } export function validateString(value: unknown, name: string) { - if (typeof value !== "string") { - throw new ERR_INVALID_ARG_TYPE(name, "string", value); + if (typeof value !== 'string') { + throw new ERR_INVALID_ARG_TYPE(name, 'string', value); } } export function validateNumber(value: unknown, name: string) { - if (typeof value !== "number") { - throw new ERR_INVALID_ARG_TYPE(name, "number", value); + if (typeof value !== 'number') { + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); } } export function validateBoolean(value: unknown, name: string) { - if (typeof value !== "boolean") { - throw new ERR_INVALID_ARG_TYPE(name, "boolean", value); + if (typeof value !== 'boolean') { + throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value); } } export function validateOneOf(value: unknown, name: string, oneOf: any[]) { if (!Array.prototype.includes.call(oneOf, value)) { const allowed = Array.prototype.join.call( - Array.prototype.map.call( - oneOf, - (v) => (typeof v === "string" ? `'${v}'` : String(v)), + Array.prototype.map.call(oneOf, (v) => + typeof v === 'string' ? `'${v}'` : String(v) ), - ", ", + ', ' ); - const reason = "must be one of: " + allowed; + const reason = 'must be one of: ' + allowed; throw new ERR_INVALID_ARG_VALUE(name, value, reason); } @@ -169,9 +177,9 @@ export function validateEncoding(data: unknown, encoding: string): void { if (normalizedEncoding === bufferUtil.HEX && length % 2 !== 0) { throw new ERR_INVALID_ARG_VALUE( - "encoding", + 'encoding', encoding, - `is invalid for data of length ${length}`, + `is invalid for data of length ${length}` ); } } @@ -179,23 +187,21 @@ export function validateEncoding(data: unknown, encoding: string): void { export function validateAbortSignal(signal: unknown, name: string) { if ( signal !== undefined && - (signal === null || - typeof signal !== "object" || - !("aborted" in signal)) + (signal === null || typeof signal !== 'object' || !('aborted' in signal)) ) { - throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal); + throw new ERR_INVALID_ARG_TYPE(name, 'AbortSignal', signal); } -}; +} export function validateFunction(value: unknown, name: string) { - if (typeof value !== "function") { - throw new ERR_INVALID_ARG_TYPE(name, "Function", value); + if (typeof value !== 'function') { + throw new ERR_INVALID_ARG_TYPE(name, 'Function', value); } } export function validateArray(value: unknown, name: string, minLength = 0) { if (!Array.isArray(value)) { - throw new ERR_INVALID_ARG_TYPE(name, "Array", value); + throw new ERR_INVALID_ARG_TYPE(name, 'Array', value); } if (value.length < minLength) { const reason = `must be longer than ${minLength}`; diff --git a/src/node/internal/web_crypto.d.ts b/src/node/internal/web_crypto.d.ts index ea465710acc..3ec332bfaf6 100644 --- a/src/node/internal/web_crypto.d.ts +++ b/src/node/internal/web_crypto.d.ts @@ -5,5 +5,5 @@ type CryptoKey = unknown; declare const CryptoKey: { prototype: CryptoKey; - new(): CryptoKey; + new (): CryptoKey; }; diff --git a/src/node/path.ts b/src/node/path.ts index f50150a7961..ebeea16fbbe 100644 --- a/src/node/path.ts +++ b/src/node/path.ts @@ -5,10 +5,7 @@ /* eslint-disable */ -import { - posix, - win32, -} from 'node-internal:internal_path'; +import { posix, win32 } from 'node-internal:internal_path'; const { resolve, diff --git a/src/node/stream.js b/src/node/stream.js index 617a9cc6a42..ffeff6ebcd7 100644 --- a/src/node/stream.js +++ b/src/node/stream.js @@ -18,9 +18,7 @@ import { setDefaultHighWaterMark, isWritable, } from 'node-internal:streams_util'; -import { - compose, -} from 'node-internal:streams_compose'; +import { compose } from 'node-internal:streams_compose'; import { Stream } from 'node-internal:streams_legacy'; import { Writable } from 'node-internal:streams_writable'; import { Readable } from 'node-internal:streams_readable'; diff --git a/src/node/stream/consumers.js b/src/node/stream/consumers.js index 18944649f3e..03aa471bd0e 100644 --- a/src/node/stream/consumers.js +++ b/src/node/stream/consumers.js @@ -29,8 +29,7 @@ import { Buffer } from 'node-internal:internal_buffer'; export async function blob(stream) { const chunks = []; - for await (const chunk of stream) - chunks.push(chunk); + for await (const chunk of stream) chunks.push(chunk); return new Blob(chunks); } @@ -47,10 +46,8 @@ export async function text(stream) { const dec = new TextDecoder(); let str = ''; for await (const chunk of stream) { - if (typeof chunk === 'string') - str += chunk; - else - str += dec.decode(chunk, { stream: true }); + if (typeof chunk === 'string') str += chunk; + else str += dec.decode(chunk, { stream: true }); } // Flush the streaming TextDecoder so that any pending // incomplete multibyte characters are handled. diff --git a/src/node/stream/web.js b/src/node/stream/web.js index 36eeffb2ada..4245c3ab17e 100644 --- a/src/node/stream/web.js +++ b/src/node/stream/web.js @@ -5,16 +5,22 @@ /* eslint-disable */ export const ReadableStream = globalThis.ReadableStream; -export const ReadableStreamDefaultReader = globalThis.ReadableStreamDefaultReader; +export const ReadableStreamDefaultReader = + globalThis.ReadableStreamDefaultReader; export const ReadableStreamBYOBReader = globalThis.ReadableStreamBYOBReader; export const ReadableStreamBYOBRequest = globalThis.ReadableStreamBYOBRequest; -export const ReadableByteStreamController = globalThis.ReadableByteStreamController; -export const ReadableStreamDefaultController = globalThis.ReadableStreamDefaultController; +export const ReadableByteStreamController = + globalThis.ReadableByteStreamController; +export const ReadableStreamDefaultController = + globalThis.ReadableStreamDefaultController; export const TransformStream = globalThis.TransformStream; -export const TransformStreamDefaultController = globalThis.TransformStreamDefaultController; +export const TransformStreamDefaultController = + globalThis.TransformStreamDefaultController; export const WritableStream = globalThis.WritableStream; -export const WritableStreamDefaultWriter = globalThis.WritableStreamDefaultWriter; -export const WritableStreamDefaultController = globalThis.WritableStreamDefaultController; +export const WritableStreamDefaultWriter = + globalThis.WritableStreamDefaultWriter; +export const WritableStreamDefaultController = + globalThis.WritableStreamDefaultController; export const ByteLengthQueuingStrategy = globalThis.ByteLengthQueuingStrategy; export const CountQueuingStrategy = globalThis.CountQueuingStrategy; export const TextEncoderStream = globalThis.TextEncoderStream; @@ -40,4 +46,4 @@ export default { TextDecoderStream, CompressionStream, DecompressionStream, -} +}; diff --git a/src/node/tsconfig.json b/src/node/tsconfig.json index 3a804869a03..fee65ca99c5 100644 --- a/src/node/tsconfig.json +++ b/src/node/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ESNext", "module": "ESNext", - "lib": [ "ESNext" ], + "lib": ["ESNext"], "alwaysStrict": true, "strict": true, "allowJs": true, @@ -20,9 +20,7 @@ "esModuleInterop": true, "moduleResolution": "node", "declaration": true, - "types": [ - "@types/node" - ], + "types": ["@types/node"], "paths": { "node:*": ["./*"], "node:assert/*": ["./*"], diff --git a/src/node/util.ts b/src/node/util.ts index b051d642049..27c99867464 100644 --- a/src/node/util.ts +++ b/src/node/util.ts @@ -14,9 +14,7 @@ import { validateObject, } from 'node-internal:validators'; -import { - debuglog, -} from 'node-internal:debuglog'; +import { debuglog } from 'node-internal:debuglog'; export const debug = debuglog; export { debuglog }; @@ -31,41 +29,37 @@ import { formatWithOptions, stripVTControlCharacters, } from 'node-internal:internal_inspect'; -export { - inspect, - format, - formatWithOptions, - stripVTControlCharacters, -}; +export { inspect, format, formatWithOptions, stripVTControlCharacters }; export const types = internalTypes; -export const { - MIMEParams, - MIMEType, -} = utilImpl; +export const { MIMEParams, MIMEType } = utilImpl; -const callbackifyOnRejected = (reason: unknown, cb : Function) => { +const callbackifyOnRejected = (reason: unknown, cb: Function) => { if (!reason) { reason = new ERR_FALSY_VALUE_REJECTION(`${reason}`); } return cb(reason); }; -export function callbackify - Promise>(original: T): - T extends (...args: infer TArgs) => Promise ? (...params: [...TArgs, (err: Error, ret: TReturn) => any]) => void : never { +export function callbackify Promise>( + original: T +): T extends (...args: infer TArgs) => Promise + ? (...params: [...TArgs, (err: Error, ret: TReturn) => any]) => void + : never { validateFunction(original, 'original'); - function callbackified(this: unknown, - ...args: [...unknown[], - (err: unknown, ret: unknown) => void]) : any { + function callbackified( + this: unknown, + ...args: [...unknown[], (err: unknown, ret: unknown) => void] + ): any { const maybeCb = args.pop(); validateFunction(maybeCb, 'last argument'); const cb = (maybeCb as Function).bind(this); - Reflect.apply(original, this, args) - .then((ret: any) => queueMicrotask(() => cb(null, ret)), - (rej: any) => queueMicrotask(() => callbackifyOnRejected(rej, cb))); + Reflect.apply(original, this, args).then( + (ret: any) => queueMicrotask(() => cb(null, ret)), + (rej: any) => queueMicrotask(() => callbackifyOnRejected(rej, cb)) + ); } const descriptors = Object.getOwnPropertyDescriptors(original); @@ -99,7 +93,7 @@ export function promisify(original: Function): Function { value: fn, enumerable: false, writable: false, - configurable: true + configurable: true, }); } @@ -132,7 +126,7 @@ export function promisify(original: Function): Function { value: fn, enumerable: false, writable: false, - configurable: true + configurable: true, }); const descriptors = Object.getOwnPropertyDescriptors(original); @@ -148,7 +142,6 @@ export function promisify(original: Function): Function { promisify.custom = kCustomPromisifiedSymbol; export function inherits(ctor: Function, superCtor: Function) { - if (ctor === undefined || ctor === null) throw new ERR_INVALID_ARG_TYPE('ctor', 'Function', ctor); @@ -156,13 +149,16 @@ export function inherits(ctor: Function, superCtor: Function) { throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor); if (superCtor.prototype === undefined) { - throw new ERR_INVALID_ARG_TYPE('superCtor.prototype', - 'Object', superCtor.prototype); + throw new ERR_INVALID_ARG_TYPE( + 'superCtor.prototype', + 'Object', + superCtor.prototype + ); } Object.defineProperty(ctor, 'super_', { value: superCtor, writable: true, - configurable: true + configurable: true, }); Object.setPrototypeOf(ctor.prototype, superCtor.prototype); } @@ -182,42 +178,41 @@ export function _extend(target: Object, source: Object) { export const TextDecoder = globalThis.TextDecoder; export const TextEncoder = globalThis.TextEncoder; -export function toUSVString(input : any) { +export function toUSVString(input: any) { // TODO(cleanup): Apparently the typescript types for this aren't available yet? return (`${input}` as any).toWellFormed(); } -function pad(n: any) : string { +function pad(n: any): string { return `${n}`.padStart(2, '0'); } +// prettier-ignore const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -function timestamp() : string { +function timestamp(): string { const d = new Date(); - const t = [ - pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds()), - ].join(':'); + const t = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join( + ':' + ); return `${d.getDate()} ${months[d.getMonth()]} ${t}`; } -export function log(...args : any[]) { +export function log(...args: any[]) { console.log('%s - %s', timestamp(), format(...args)); } -export function parseArgs(..._ : any[]) : any { +export function parseArgs(..._: any[]): any { // We currently have no plans to implement the util.parseArgs API. throw new Error('node:util parseArgs is not implemented'); } -export function transferableAbortController(..._ : any[]) : any { +export function transferableAbortController(..._: any[]): any { throw new Error('node:util transferableAbortController is not implemented'); } -export function transferableAbortSignal(..._ : any[]) : any { +export function transferableAbortSignal(..._: any[]): any { throw new Error('node:util transferableAbortSignal is not implemented'); } @@ -231,7 +226,10 @@ export async function aborted(signal: AbortSignal, resource: object) { // this additional option. Unfortunately Node.js does not make this argument optional. // We'll just ignore it. validateAbortSignal(signal, 'signal'); - validateObject(resource, 'resource', { allowArray: true, allowFunction: true }); + validateObject(resource, 'resource', { + allowArray: true, + allowFunction: true, + }); if (signal.aborted) return Promise.resolve(); // TODO(cleanup): Apparently withResolvers isn't part of type defs we use yet const { promise, resolve } = (Promise as any).withResolvers(); @@ -240,7 +238,12 @@ export async function aborted(signal: AbortSignal, resource: object) { return promise; } -export function deprecate(fn: Function, _1?: string, _2?: string, _3? : boolean) { +export function deprecate( + fn: Function, + _1?: string, + _2?: string, + _3?: boolean +) { // TODO(soon): Node.js's implementation wraps the given function in a new function that // logs a warning to the console if the function is called. Do we want to support that? // For now, we're just going to silently return the input method unmodified. diff --git a/src/node/zlib.ts b/src/node/zlib.ts index 488c0057fb6..ec400f88d0c 100644 --- a/src/node/zlib.ts +++ b/src/node/zlib.ts @@ -1,11 +1,8 @@ import { crc32, constants } from 'node-internal:internal_zlib'; -export { - crc32, - constants, -} +export { crc32, constants }; export default { crc32, constants, -} +}; diff --git a/src/pyodide/internal/builtin_wrappers.ts b/src/pyodide/internal/builtin_wrappers.ts index d6cf00918a0..9f45ff5f0d8 100644 --- a/src/pyodide/internal/builtin_wrappers.ts +++ b/src/pyodide/internal/builtin_wrappers.ts @@ -1,5 +1,5 @@ -import { default as UnsafeEval } from "internal:unsafe-eval"; -export { getRandomValues } from "pyodide-internal:topLevelEntropy/lib"; +import { default as UnsafeEval } from 'internal:unsafe-eval'; +export { getRandomValues } from 'pyodide-internal:topLevelEntropy/lib'; let lastTime: number; let lastDelta = 0; @@ -73,7 +73,7 @@ function checkCallee(): void { Error.prepareStackTrace = origPrepareStackTrace; } if (!isOkay) { - console.warn("Invalid call to `WebAssembly.Module`"); + console.warn('Invalid call to `WebAssembly.Module`'); throw new Error(); } } @@ -95,10 +95,10 @@ function prepareStackTrace(_error: Error, stack: StackItem[]): boolean { try { const funcName = stack[2].getFunctionName(); const fileName = stack[2].getFileName(); - if (fileName !== "pyodide-internal:generated/pyodide.asm") { + if (fileName !== 'pyodide-internal:generated/pyodide.asm') { return false; } - return ["loadModule", "convertJsFunctionToWasm"].includes(funcName); + return ['loadModule', 'convertJsFunctionToWasm'].includes(funcName); } catch (e) { console.warn(e); return false; @@ -107,7 +107,7 @@ function prepareStackTrace(_error: Error, stack: StackItem[]): boolean { export async function wasmInstantiate( mod: WebAssembly.Module | Uint8Array, - imports: WebAssembly.Imports, + imports: WebAssembly.Imports ): Promise<{ module: WebAssembly.Module; instance: WebAssembly.Instance }> { let module; if (mod instanceof WebAssembly.Module) { diff --git a/src/pyodide/internal/jaeger.ts b/src/pyodide/internal/jaeger.ts index d51e3b11953..a3575a9024c 100644 --- a/src/pyodide/internal/jaeger.ts +++ b/src/pyodide/internal/jaeger.ts @@ -1,4 +1,4 @@ -import { default as internalJaeger } from "pyodide-internal:internalJaeger"; +import { default as internalJaeger } from 'pyodide-internal:internalJaeger'; /** * Used for tracing via Jaeger. diff --git a/src/pyodide/internal/loadPackage.ts b/src/pyodide/internal/loadPackage.ts index 97753e074cf..fb8bc2480d4 100644 --- a/src/pyodide/internal/loadPackage.ts +++ b/src/pyodide/internal/loadPackage.ts @@ -9,33 +9,33 @@ * that contains all the packages ready to go. */ -import { default as LOCKFILE } from "pyodide-internal:generated/pyodide-lock.json"; -import { WORKERD_INDEX_URL } from "pyodide-internal:metadata"; +import { default as LOCKFILE } from 'pyodide-internal:generated/pyodide-lock.json'; +import { WORKERD_INDEX_URL } from 'pyodide-internal:metadata'; import { SITE_PACKAGES, LOAD_WHEELS_FROM_R2, getSitePackagesPath, -} from "pyodide-internal:setupPackages"; -import { parseTarInfo } from "pyodide-internal:tar"; -import { default as DiskCache } from "pyodide-internal:disk_cache"; -import { createTarFS } from "pyodide-internal:tarfs"; +} from 'pyodide-internal:setupPackages'; +import { parseTarInfo } from 'pyodide-internal:tar'; +import { default as DiskCache } from 'pyodide-internal:disk_cache'; +import { createTarFS } from 'pyodide-internal:tarfs'; async function decompressArrayBuffer( - arrBuf: ArrayBuffer, + arrBuf: ArrayBuffer ): Promise { const resp = new Response(arrBuf); if (resp && resp.body) { return await new Response( - resp.body.pipeThrough(new DecompressionStream("gzip")), + resp.body.pipeThrough(new DecompressionStream('gzip')) ).arrayBuffer(); } else { - throw new Error("Failed to decompress array buffer"); + throw new Error('Failed to decompress array buffer'); } } async function loadBundle(requirement: string): Promise<[string, ArrayBuffer]> { // first check if the disk cache has what we want - const filename = LOCKFILE["packages"][requirement]["file_name"]; + const filename = LOCKFILE['packages'][requirement]['file_name']; const cached = DiskCache.get(filename); if (cached) { const decompressed = await decompressArrayBuffer(cached); @@ -84,7 +84,7 @@ export async function loadPackages(Module: Module, requirements: Set) { loading.push(req); } - console.log("Loading " + loading.join(", ")); + console.log('Loading ' + loading.join(', ')); const buffers = await Promise.all(loadPromises); for (const [requirement, buffer] of buffers) { @@ -93,7 +93,7 @@ export async function loadPackages(Module: Module, requirements: Set) { SITE_PACKAGES.addSmallBundle(tarInfo, soFiles, requirement); } - console.log("Loaded " + loading.join(", ")); + console.log('Loaded ' + loading.join(', ')); const tarFS = createTarFS(Module); const path = getSitePackagesPath(Module); diff --git a/src/pyodide/internal/metadata.ts b/src/pyodide/internal/metadata.ts index 5e33d61e082..70b4fadea1d 100644 --- a/src/pyodide/internal/metadata.ts +++ b/src/pyodide/internal/metadata.ts @@ -1,7 +1,7 @@ -import { default as MetadataReader } from "pyodide-internal:runtime-generated/metadata"; -export { default as LOCKFILE } from "pyodide-internal:generated/pyodide-lock.json"; -import { default as PYODIDE_BUCKET } from "pyodide-internal:generated/pyodide-bucket.json"; -import { default as ArtifactBundler } from "pyodide-internal:artifacts"; +import { default as MetadataReader } from 'pyodide-internal:runtime-generated/metadata'; +export { default as LOCKFILE } from 'pyodide-internal:generated/pyodide-lock.json'; +import { default as PYODIDE_BUCKET } from 'pyodide-internal:generated/pyodide-bucket.json'; +import { default as ArtifactBundler } from 'pyodide-internal:artifacts'; export const IS_WORKERD = MetadataReader.isWorkerd(); export const IS_TRACING = MetadataReader.isTracing(); diff --git a/src/pyodide/internal/metadatafs.ts b/src/pyodide/internal/metadatafs.ts index c701313cb62..f2d6ca54817 100644 --- a/src/pyodide/internal/metadatafs.ts +++ b/src/pyodide/internal/metadatafs.ts @@ -1,11 +1,11 @@ -import { default as MetadataReader } from "pyodide-internal:runtime-generated/metadata"; -import { createReadonlyFS } from "pyodide-internal:readOnlyFS"; +import { default as MetadataReader } from 'pyodide-internal:runtime-generated/metadata'; +import { createReadonlyFS } from 'pyodide-internal:readOnlyFS'; function createTree(paths: string[]): MetadataFSInfo { const tree = new Map(); paths.forEach((elt: string, idx: number) => { let subTree = tree; - const parts = elt.split("/"); + const parts = elt.split('/'); const name = parts.pop(); for (const part of parts) { let next = subTree.get(part); @@ -20,7 +20,8 @@ function createTree(paths: string[]): MetadataFSInfo { return tree; } -export function createMetadataFS(Module: Module): object { // TODO: Make this type more specific +export function createMetadataFS(Module: Module): object { + // TODO: Make this type more specific const TIMESTAMP = Date.now(); const names = MetadataReader.getNames(); const sizes = MetadataReader.getSizes(); @@ -29,7 +30,7 @@ export function createMetadataFS(Module: Module): object { // TODO: Make this ty getNodeMode(parent, name, info) { return { permissions: 0o555, // read and execute but not write - isDir: typeof info !== "number", + isDir: typeof info !== 'number', }; }, setNodeAttributes(node, info, isDir) { @@ -47,13 +48,13 @@ export function createMetadataFS(Module: Module): object { // TODO: Make this ty }, readdir(node) { if (node.tree == undefined) { - throw new Error("cannot read directory, tree is undefined"); + throw new Error('cannot read directory, tree is undefined'); } return Array.from(node.tree.keys()); }, lookup(parent, name) { if (parent.tree == undefined) { - throw new Error("cannot lookup directory, tree is undefined"); + throw new Error('cannot lookup directory, tree is undefined'); } return parent.tree.get(name)!; }, diff --git a/src/pyodide/internal/python.ts b/src/pyodide/internal/python.ts index e31735c4ce2..81050365188 100644 --- a/src/pyodide/internal/python.ts +++ b/src/pyodide/internal/python.ts @@ -1,24 +1,24 @@ Error.stackTraceLimit = Infinity; -import { enterJaegerSpan } from "pyodide-internal:jaeger"; +import { enterJaegerSpan } from 'pyodide-internal:jaeger'; import { TRANSITIVE_REQUIREMENTS, SITE_PACKAGES, adjustSysPath, mountLib, -} from "pyodide-internal:setupPackages"; -import { reportError } from "pyodide-internal:util"; +} from 'pyodide-internal:setupPackages'; +import { reportError } from 'pyodide-internal:util'; import { SHOULD_RESTORE_SNAPSHOT, finishSnapshotSetup, getSnapshotSettings, maybeSetupSnapshotUpload, restoreSnapshot, -} from "pyodide-internal:snapshot"; +} from 'pyodide-internal:snapshot'; import { entropyMountFiles, entropyAfterRuntimeInit, entropyBeforeTopLevel, -} from "pyodide-internal:topLevelEntropy/lib"; +} from 'pyodide-internal:topLevelEntropy/lib'; /** * This file is a simplified version of the Pyodide loader: @@ -32,8 +32,8 @@ import { * _createPyodideModule and pyodideWasmModule together are produced by the * Emscripten linker */ -import { _createPyodideModule } from "pyodide-internal:generated/pyodide.asm"; -import pyodideWasmModule from "pyodide-internal:generated/pyodide.asm.wasm"; +import { _createPyodideModule } from 'pyodide-internal:generated/pyodide.asm'; +import pyodideWasmModule from 'pyodide-internal:generated/pyodide.asm.wasm'; /** * The Python and Pyodide stdlib zipped together. The zip format is convenient @@ -44,7 +44,7 @@ import pyodideWasmModule from "pyodide-internal:generated/pyodide.asm.wasm"; * with a bunch of C libs to unpack various archive formats, but they need stuff * in this zip file to initialize their runtime state. */ -import stdlib from "pyodide-internal:generated/python_stdlib.zip"; +import stdlib from 'pyodide-internal:generated/python_stdlib.zip'; /** * A hook that the Emscripten runtime calls to perform the WebAssembly @@ -62,16 +62,13 @@ import stdlib from "pyodide-internal:generated/python_stdlib.zip"; */ function instantiateWasm( wasmImports: WebAssembly.Imports, - successCallback: ( - inst: WebAssembly.Instance, - mod: WebAssembly.Module, - ) => void, + successCallback: (inst: WebAssembly.Instance, mod: WebAssembly.Module) => void ): WebAssembly.Exports { (async function () { // Instantiate pyodideWasmModule with wasmImports const instance = await WebAssembly.instantiate( pyodideWasmModule, - wasmImports, + wasmImports ); successCallback(instance, pyodideWasmModule); })(); @@ -107,7 +104,7 @@ function prepareFileSystem(Module: Module): void { Module.FS.writeFile( `/lib/python${pymajor}${pyminor}.zip`, new Uint8Array(stdlib), - { canOwn: true }, + { canOwn: true } ); Module.FS.mkdirTree(Module.API.config.env.HOME); } catch (e) { @@ -129,18 +126,18 @@ function setEnv(Module: Module): void { */ function getEmscriptenSettings( lockfile: PackageLock, - indexURL: string, + indexURL: string ): EmscriptenSettings { const config = { // jsglobals is used for the js module. jsglobals: globalThis, // environment variables go here env: { - HOME: "/session", + HOME: '/session', // We don't have access to entropy at startup so we cannot support hash // randomization. Setting `PYTHONHASHSEED` disables it. See further // discussion in topLevelEntropy/entropy_patches.py - PYTHONHASHSEED: "111", + PYTHONHASHSEED: '111', }, // This is the index that we use as the base URL to fetch the wheels. indexURL, @@ -171,7 +168,7 @@ function getEmscriptenSettings( * Returns the instantiated emscriptenModule object. */ async function instantiateEmscriptenModule( - emscriptenSettings: EmscriptenSettings, + emscriptenSettings: EmscriptenSettings ): Promise { try { // Force Emscripten to feature detect the way we want @@ -190,7 +187,7 @@ async function instantiateEmscriptenModule( const emscriptenModule = await p; return emscriptenModule; } catch (e) { - console.warn("Error in instantiateEmscriptenModule"); + console.warn('Error in instantiateEmscriptenModule'); reportError(e); } } @@ -221,19 +218,19 @@ async function prepareWasmLinearMemory(Module: Module): Promise { export async function loadPyodide( lockfile: PackageLock, - indexURL: string, + indexURL: string ): Promise { const emscriptenSettings = getEmscriptenSettings(lockfile, indexURL); - const Module = await enterJaegerSpan("instantiate_emscripten", () => - instantiateEmscriptenModule(emscriptenSettings), + const Module = await enterJaegerSpan('instantiate_emscripten', () => + instantiateEmscriptenModule(emscriptenSettings) ); - await enterJaegerSpan("prepare_wasm_linear_memory", () => - prepareWasmLinearMemory(Module), + await enterJaegerSpan('prepare_wasm_linear_memory', () => + prepareWasmLinearMemory(Module) ); maybeSetupSnapshotUpload(Module); // Finish setting up Pyodide's ffi so we can use the nice Python interface - await enterJaegerSpan("finalize_bootstrap", Module.API.finalizeBootstrap); + await enterJaegerSpan('finalize_bootstrap', Module.API.finalizeBootstrap); const pyodide = Module.API.public_api; finishSnapshotSetup(pyodide); return pyodide; diff --git a/src/pyodide/internal/readOnlyFS.ts b/src/pyodide/internal/readOnlyFS.ts index cf5d0ffb70f..f3ebf5ac521 100644 --- a/src/pyodide/internal/readOnlyFS.ts +++ b/src/pyodide/internal/readOnlyFS.ts @@ -1,8 +1,11 @@ -export function createReadonlyFS(FSOps: FSOps, Module: Module): EmscriptenFS { +export function createReadonlyFS( + FSOps: FSOps, + Module: Module +): EmscriptenFS { const FS = Module.FS; const ReadOnlyFS: EmscriptenFS = { mount(mount) { - return ReadOnlyFS.createNode(null, "/", mount.opts.info); + return ReadOnlyFS.createNode(null, '/', mount.opts.info); }, createNode(parent, name, info): FSNode { let { permissions: mode, isDir } = FSOps.getNodeMode(parent, name, info); @@ -60,8 +63,8 @@ export function createReadonlyFS(FSOps: FSOps, Module: Module): Emsc } else if (whence === 2) { // SEEK_END if (FS.isFile(stream.node.mode)) { - if ((stream.node.info as any).size == undefined){ - throw new Error("File size is undefined"); + if ((stream.node.info as any).size == undefined) { + throw new Error('File size is undefined'); } position += (stream.node.info as any).size; } diff --git a/src/pyodide/internal/setupPackages.ts b/src/pyodide/internal/setupPackages.ts index e9144eb4a4f..9734902cabb 100644 --- a/src/pyodide/internal/setupPackages.ts +++ b/src/pyodide/internal/setupPackages.ts @@ -1,9 +1,9 @@ -import { parseTarInfo } from "pyodide-internal:tar"; -import { createTarFS } from "pyodide-internal:tarfs"; -import { createMetadataFS } from "pyodide-internal:metadatafs"; -import { default as LOCKFILE } from "pyodide-internal:generated/pyodide-lock.json"; -import { REQUIREMENTS, WORKERD_INDEX_URL } from "pyodide-internal:metadata"; -import { simpleRunPython } from "pyodide-internal:util"; +import { parseTarInfo } from 'pyodide-internal:tar'; +import { createTarFS } from 'pyodide-internal:tarfs'; +import { createMetadataFS } from 'pyodide-internal:metadatafs'; +import { default as LOCKFILE } from 'pyodide-internal:generated/pyodide-lock.json'; +import { REQUIREMENTS, WORKERD_INDEX_URL } from 'pyodide-internal:metadata'; +import { simpleRunPython } from 'pyodide-internal:util'; const canonicalizeNameRegex = /[-_.]+/g; @@ -14,12 +14,12 @@ const canonicalizeNameRegex = /[-_.]+/g; * @private */ function canonicalizePackageName(name: string): string { - return name.replace(canonicalizeNameRegex, "-").toLowerCase(); + return name.replace(canonicalizeNameRegex, '-').toLowerCase(); } // The "name" field in the lockfile is not canonicalized const STDLIB_PACKAGES: string[] = Object.values(LOCKFILE.packages) - .filter(({ install_dir }) => install_dir === "stdlib") + .filter(({ install_dir }) => install_dir === 'stdlib') .map(({ name }) => canonicalizePackageName(name)); /** @@ -34,11 +34,11 @@ class SitePackagesDir { this.rootInfo = { children: new Map(), mode: 0o777, - type: "5", + type: '5', modtime: 0, size: 0, - path: "", - name: "", + path: '', + name: '', parts: [], }; this.soFiles = []; @@ -55,7 +55,7 @@ class SitePackagesDir { overlayInfo.children!.forEach((val, key) => { if (this.rootInfo.children!.has(key)) { throw new Error( - `File/folder ${key} being written by multiple packages`, + `File/folder ${key} being written by multiple packages` ); } this.rootInfo.children!.set(key, val); @@ -72,10 +72,10 @@ class SitePackagesDir { addSmallBundle( tarInfo: TarFSInfo, soFiles: string[], - requirement: string, + requirement: string ): void { for (const soFile of soFiles) { - this.soFiles.push(soFile.split("/")); + this.soFiles.push(soFile.split('/')); } this.mountOverlay(tarInfo); this.loadedRequirements.add(requirement); @@ -91,12 +91,12 @@ class SitePackagesDir { addBigBundle( tarInfo: TarFSInfo, soFiles: string[], - requirements: Set, + requirements: Set ): void { // add all the .so files we will need to preload from the big bundle for (const soFile of soFiles) { // If folder is in list of requirements include .so file in list to preload. - const [pkg, ...rest] = soFile.split("/"); + const [pkg, ...rest] = soFile.split('/'); if (requirements.has(pkg)) { this.soFiles.push(rest); } @@ -123,7 +123,7 @@ class SitePackagesDir { * directory so we can preload them. */ export function buildSitePackages( - requirements: Set, + requirements: Set ): [SitePackagesDir, boolean] { const [bigTarInfo, bigTarSoFiles] = parseTarInfo(); @@ -154,7 +154,7 @@ export function patchLoadPackage(pyodide: Pyodide): void { function disabledLoadPackage(): never { throw new Error( - "pyodide.loadPackage is disabled because packages are encoded in the binary", + 'pyodide.loadPackage is disabled because packages are encoded in the binary' ); } @@ -187,14 +187,14 @@ export function mountLib(Module: Module, info: TarFSInfo): void { const mdFS = createMetadataFS(Module); const site_packages = getSitePackagesPath(Module); Module.FS.mkdirTree(site_packages); - Module.FS.mkdirTree("/session/metadata"); + Module.FS.mkdirTree('/session/metadata'); if (!LOAD_WHEELS_FROM_R2) { // if we are not loading additional wheels from R2, then we're done // with site-packages and we can mount it here. Otherwise, we must mount it in // loadPackages(). Module.FS.mount(tarFS, { info }, site_packages); } - Module.FS.mount(mdFS, {}, "/session/metadata"); + Module.FS.mount(mdFS, {}, '/session/metadata'); } /** @@ -205,13 +205,13 @@ export function adjustSysPath(Module: Module): void { const site_packages = getSitePackagesPath(Module); simpleRunPython( Module, - `import sys; sys.path.append("/session/metadata"); sys.path.append("${site_packages}"); del sys`, + `import sys; sys.path.append("/session/metadata"); sys.path.append("${site_packages}"); del sys` ); } function recursiveDependencies( lockfile: PackageLock, - names: string[], + names: string[] ): PackageDeclaration[] { const toLoad = new Map(); for (const name of names) { @@ -230,7 +230,7 @@ function recursiveDependencies( function addPackageToLoad( lockfile: PackageLock, name: string, - toLoad: Map, + toLoad: Map ): void { const normalizedName = canonicalizePackageName(name); if (toLoad.has(normalizedName)) { @@ -240,7 +240,7 @@ function addPackageToLoad( if (!pkgInfo) { throw new Error( `It appears that a package ("${name}") you requested is not available yet in workerd. \n` + - "If you would like this package to be included, please open an issue at https://github.com/cloudflare/workerd/discussions/new?category=python-packages.", + 'If you would like this package to be included, please open an issue at https://github.com/cloudflare/workerd/discussions/new?category=python-packages.' ); } @@ -254,5 +254,5 @@ function addPackageToLoad( export { REQUIREMENTS }; export const TRANSITIVE_REQUIREMENTS = getTransitiveRequirements(); export const [SITE_PACKAGES, LOAD_WHEELS_FROM_R2] = buildSitePackages( - TRANSITIVE_REQUIREMENTS, + TRANSITIVE_REQUIREMENTS ); diff --git a/src/pyodide/internal/snapshot.ts b/src/pyodide/internal/snapshot.ts index 5c66a4c0939..6ad4131202e 100644 --- a/src/pyodide/internal/snapshot.ts +++ b/src/pyodide/internal/snapshot.ts @@ -1,18 +1,18 @@ -import { default as ArtifactBundler } from "pyodide-internal:artifacts"; -import { default as UnsafeEval } from "internal:unsafe-eval"; -import { default as DiskCache } from "pyodide-internal:disk_cache"; +import { default as ArtifactBundler } from 'pyodide-internal:artifacts'; +import { default as UnsafeEval } from 'internal:unsafe-eval'; +import { default as DiskCache } from 'pyodide-internal:disk_cache'; import { SITE_PACKAGES, getSitePackagesPath, -} from "pyodide-internal:setupPackages"; -import { default as TarReader } from "pyodide-internal:packages_tar_reader"; -import processScriptImports from "pyodide-internal:process_script_imports.py"; +} from 'pyodide-internal:setupPackages'; +import { default as TarReader } from 'pyodide-internal:packages_tar_reader'; +import processScriptImports from 'pyodide-internal:process_script_imports.py'; import { SHOULD_SNAPSHOT_TO_DISK, IS_CREATING_BASELINE_SNAPSHOT, MEMORY_SNAPSHOT_READER, -} from "pyodide-internal:metadata"; -import { reportError, simpleRunPython } from "pyodide-internal:util"; +} from 'pyodide-internal:metadata'; +import { reportError, simpleRunPython } from 'pyodide-internal:util'; let LOADED_BASELINE_SNAPSHOT: number; @@ -58,10 +58,11 @@ export async function uploadArtifacts(): Promise { /** * Used to hold the memory that needs to be uploaded for the validator. */ -let MEMORY_TO_UPLOAD: ArtifactBundler.MemorySnapshotResult | undefined = undefined; +let MEMORY_TO_UPLOAD: ArtifactBundler.MemorySnapshotResult | undefined = + undefined; function getMemoryToUpload(): ArtifactBundler.MemorySnapshotResult { if (!MEMORY_TO_UPLOAD) { - throw new TypeError("Expected MEMORY_TO_UPLOAD to be set"); + throw new TypeError('Expected MEMORY_TO_UPLOAD to be set'); } const tmp = MEMORY_TO_UPLOAD; MEMORY_TO_UPLOAD = undefined; @@ -80,10 +81,10 @@ function getMemoryToUpload(): ArtifactBundler.MemorySnapshotResult { function loadDynlib( Module: Module, path: string, - wasmModuleData: Uint8Array, + wasmModuleData: Uint8Array ): void { const wasmModule = UnsafeEval.newWasmModule(wasmModuleData); - const dso = Module.newDSO(path, undefined, "loading"); + const dso = Module.newDSO(path, undefined, 'loading'); // even though these are used via dlopen, we are allocating them in an arena // outside the heap and the memory cannot be reclaimed. So I don't think it // would help us to allow them to be dealloc'd. @@ -121,17 +122,17 @@ export function preloadDynamicLibs(Module: Module): void { // [[ '_lzma.so' ], [ '_ssl.so' ]] // but we put a few more because we messed up the memory snapshot... SO_FILES_TO_LOAD = [ - ["_hashlib.so"], - ["_lzma.so"], - ["_sqlite3.so"], - ["_ssl.so"], + ['_hashlib.so'], + ['_lzma.so'], + ['_sqlite3.so'], + ['_ssl.so'], ]; } if ( IS_CREATING_BASELINE_SNAPSHOT || (LOADED_BASELINE_SNAPSHOT && LOADED_SNAPSHOT_VERSION === 2) ) { - SO_FILES_TO_LOAD = [["_lzma.so"], ["_ssl.so"]]; + SO_FILES_TO_LOAD = [['_lzma.so'], ['_ssl.so']]; } try { const sitePackages = getSitePackagesPath(Module); @@ -141,20 +142,20 @@ export function preloadDynamicLibs(Module: Module): void { node = node?.children?.get(part); } if (!node) { - throw Error("fs node could not be found for " + soFile); + throw Error('fs node could not be found for ' + soFile); } const { contentsOffset, size } = node; if (contentsOffset === undefined) { - throw Error("contentsOffset not defined for " + soFile); + throw Error('contentsOffset not defined for ' + soFile); } const wasmModuleData = new Uint8Array(size); TarReader.read(contentsOffset, wasmModuleData); - const path = sitePackages + "/" + soFile.join("/"); + const path = sitePackages + '/' + soFile.join('/'); PRELOADED_SO_FILES.push(path); loadDynlib(Module, path, wasmModuleData); } } catch (e) { - console.warn("Error in preloadDynamicLibs"); + console.warn('Error in preloadDynamicLibs'); reportError(e); } } @@ -184,7 +185,7 @@ type DylinkInfo = { function recordDsoHandles(Module: Module): DylinkInfo { const dylinkInfo: DylinkInfo = {}; for (const [handle, { name }] of Object.entries( - Module.LDSO.loadedLibsByHandle, + Module.LDSO.loadedLibsByHandle )) { if (Number(handle) === 0) { continue; @@ -207,25 +208,25 @@ function recordDsoHandles(Module: Module): DylinkInfo { // Can get this list by starting Python and filtering sys.modules for modules // whose importer is not FrozenImporter or BuiltinImporter. const SNAPSHOT_IMPORTS = [ - "_pyodide.docstring", - "_pyodide._core_docs", - "traceback", - "collections.abc", + '_pyodide.docstring', + '_pyodide._core_docs', + 'traceback', + 'collections.abc', // Asyncio is the really slow one here. In native Python on my machine, `import asyncio` takes ~50 // ms. - "asyncio", - "inspect", - "tarfile", - "importlib.metadata", - "re", - "shutil", - "sysconfig", - "importlib.machinery", - "pathlib", - "site", - "tempfile", - "typing", - "zipfile", + 'asyncio', + 'inspect', + 'tarfile', + 'importlib.metadata', + 're', + 'shutil', + 'sysconfig', + 'importlib.machinery', + 'pathlib', + 'site', + 'tempfile', + 'typing', + 'zipfile', ]; /** @@ -247,12 +248,12 @@ const SNAPSHOT_IMPORTS = [ * This function returns a list of modules that have been imported. */ function memorySnapshotDoImports(Module: Module): Array { - const toImport = SNAPSHOT_IMPORTS.join(","); + const toImport = SNAPSHOT_IMPORTS.join(','); const toDelete = Array.from( - new Set(SNAPSHOT_IMPORTS.map((x) => x.split(".", 1)[0])), - ).join(","); + new Set(SNAPSHOT_IMPORTS.map((x) => x.split('.', 1)[0])) + ).join(','); simpleRunPython(Module, `import ${toImport}`); - simpleRunPython(Module, "sysconfig.get_config_vars()"); + simpleRunPython(Module, 'sysconfig.get_config_vars()'); // Delete to avoid polluting globals simpleRunPython(Module, `del ${toDelete}`); if (IS_CREATING_BASELINE_SNAPSHOT) { @@ -266,20 +267,23 @@ function memorySnapshotDoImports(Module: Module): Array { // // See process_script_imports.py. const processScriptImportsString = new TextDecoder().decode( - new Uint8Array(processScriptImports), + new Uint8Array(processScriptImports) ); simpleRunPython(Module, processScriptImportsString); - const importedModules: Array = JSON.parse(simpleRunPython( - Module, "import sys, json; print(json.dumps(CF_LOADED_MODULES), file=sys.stderr)" - )); + const importedModules: Array = JSON.parse( + simpleRunPython( + Module, + 'import sys, json; print(json.dumps(CF_LOADED_MODULES), file=sys.stderr)' + ) + ); return importedModules; } function checkLoadedSoFiles(dsoJSON: DylinkInfo): void { PRELOADED_SO_FILES.sort(); - const keys = Object.keys(dsoJSON).filter((k) => k.startsWith("/")); + const keys = Object.keys(dsoJSON).filter((k) => k.startsWith('/')); keys.sort(); const msg = `Internal error taking snapshot: mismatch: ${JSON.stringify(keys)} vs ${JSON.stringify(PRELOADED_SO_FILES)}`; if (keys.length !== PRELOADED_SO_FILES.length) { @@ -297,18 +301,26 @@ function checkLoadedSoFiles(dsoJSON: DylinkInfo): void { * are initialized in the linear memory snapshot and then saving a copy of the * linear memory into MEMORY. */ -function makeLinearMemorySnapshot(Module: Module): ArtifactBundler.MemorySnapshotResult { +function makeLinearMemorySnapshot( + Module: Module +): ArtifactBundler.MemorySnapshotResult { const importedModulesList = memorySnapshotDoImports(Module); const dsoJSON = recordDsoHandles(Module); if (IS_CREATING_BASELINE_SNAPSHOT) { // checkLoadedSoFiles(dsoJSON); } - return { snapshot: encodeSnapshot(Module.HEAP8, dsoJSON), importedModulesList }; + return { + snapshot: encodeSnapshot(Module.HEAP8, dsoJSON), + importedModulesList, + }; } -function setUploadFunction(snapshot: Uint8Array, importedModulesList: Array): void { - if (snapshot.constructor.name !== "Uint8Array") { - throw new TypeError("Expected TO_UPLOAD to be a Uint8Array"); +function setUploadFunction( + snapshot: Uint8Array, + importedModulesList: Array +): void { + if (snapshot.constructor.name !== 'Uint8Array') { + throw new TypeError('Expected TO_UPLOAD to be a Uint8Array'); } if (TOP_LEVEL_SNAPSHOT) { MEMORY_TO_UPLOAD = { snapshot, importedModulesList }; @@ -343,7 +355,7 @@ function encodeSnapshot(heap: Uint8Array, dsoJSON: object): Uint8Array { const encoder = new TextEncoder(); const { written: jsonLength } = encoder.encodeInto( dsoString, - toUpload.subarray(HEADER_SIZE), + toUpload.subarray(HEADER_SIZE) ); const uint32View = new Uint32Array(toUpload.buffer); uint32View[0] = SNAPSHOT_MAGIC; @@ -359,7 +371,7 @@ function encodeSnapshot(heap: Uint8Array, dsoJSON: object): Uint8Array { */ function decodeSnapshot(): void { if (!MEMORY_SNAPSHOT_READER) { - throw Error("Memory snapshot reader not available"); + throw Error('Memory snapshot reader not available'); } let buf = new Uint32Array(2); let offset = 0; @@ -383,7 +395,7 @@ function decodeSnapshot(): void { READ_MEMORY = function (Module) { // restore memory from snapshot if (!MEMORY_SNAPSHOT_READER) { - throw Error("Memory snapshot reader not available when reading memory"); + throw Error('Memory snapshot reader not available when reading memory'); } MEMORY_SNAPSHOT_READER.readMemorySnapshot(snapshotOffset, Module.HEAP8); MEMORY_SNAPSHOT_READER.disposeMemorySnapshot(); @@ -393,7 +405,7 @@ function decodeSnapshot(): void { export function restoreSnapshot(Module: Module): void { if (!READ_MEMORY) { - throw Error("READ_MEMORY not defined when restoring snapshot"); + throw Error('READ_MEMORY not defined when restoring snapshot'); } READ_MEMORY(Module); } @@ -419,7 +431,7 @@ let TEST_SNAPSHOT: Uint8Array | undefined = undefined; } decodeSnapshot(); } catch (e) { - console.warn("Error in top level of python.js"); + console.warn('Error in top level of python.js'); reportError(e); } })(); @@ -430,14 +442,14 @@ export function finishSnapshotSetup(pyodide: Pyodide): void { // have changed. simpleRunPython( pyodide._module, - "from importlib import invalidate_caches as f; f(); del f", + 'from importlib import invalidate_caches as f; f(); del f' ); } // This is just here for our test suite. Ugly but just about the only way to test this. if (TEST_SNAPSHOT) { const snapshotString = new TextDecoder().decode(TEST_SNAPSHOT); - pyodide.registerJsModule("cf_internal_test_utils", { + pyodide.registerJsModule('cf_internal_test_utils', { snapshot: snapshotString, }); } @@ -447,7 +459,7 @@ export function maybeStoreMemorySnapshot() { if (ArtifactBundler.isEwValidating()) { ArtifactBundler.storeMemorySnapshot(getMemoryToUpload()); } else if (SHOULD_SNAPSHOT_TO_DISK) { - DiskCache.put("snapshot.bin", getMemoryToUpload().snapshot); - console.log("Saved snapshot to disk"); + DiskCache.put('snapshot.bin', getMemoryToUpload().snapshot); + console.log('Saved snapshot to disk'); } } diff --git a/src/pyodide/internal/tar.ts b/src/pyodide/internal/tar.ts index d816f0f7085..05dd754234b 100644 --- a/src/pyodide/internal/tar.ts +++ b/src/pyodide/internal/tar.ts @@ -1,4 +1,4 @@ -import { default as TarReader } from "pyodide-internal:packages_tar_reader"; +import { default as TarReader } from 'pyodide-internal:packages_tar_reader'; // This is based on the info about the tar file format on wikipedia // And some trial and error with real tar files. @@ -24,7 +24,7 @@ function decodeHeader(buf: Uint8Array, reader: Reader): TarFSInfo { const namePrefix = decodeField(buf, 345, 155); let path = namePrefix + nameBase; // Trim possible leading ./ - if (path.startsWith("./")) { + if (path.startsWith('./')) { path = path.slice(2); } const mode = decodeNumber(buf, 100, 8); @@ -50,11 +50,11 @@ export function parseTarInfo(reader = TarReader): [TarFSInfo, string[]] { const root: TarFSInfo = { children: new Map(), mode: 0o777, - type: "5", + type: '5', modtime: 0, size: 0, - path: "", - name: "", + path: '', + name: '', parts: [], reader, }; @@ -76,18 +76,18 @@ export function parseTarInfo(reader = TarReader): [TarFSInfo, string[]] { } const contentsOffset = offset + 512; offset += 512 * Math.ceil(info.size / 512 + 1); - if (info.path === "") { + if (info.path === '') { // skip possible leading ./ directory continue; } - if (info.path.includes("PaxHeader")) { + if (info.path.includes('PaxHeader')) { // Ignore PaxHeader extension // These metadata directories don't actually have a directory entry which // is going to cause us to crash below. // Our tar files shouldn't have these anyways... continue; } - if (info.type === "L") { + if (info.type === 'L') { const buf = new Uint8Array(info.size); reader.read(contentsOffset, buf); longName = decodeString(buf); @@ -111,12 +111,12 @@ export function parseTarInfo(reader = TarReader): [TarFSInfo, string[]] { } // go down to target (in many tar files this second loop body is evaluated 0 // times) - const parts = info.path.slice(0, -1).split("/"); + const parts = info.path.slice(0, -1).split('/'); for (let i = directories.length; i < parts.length - 1; i++) { directories.push(directory); directory = directory.children!.get(parts[i])!; } - if (info.type === "5") { + if (info.type === '5') { // a directory directories.push(directory); info.parts = parts; @@ -124,11 +124,11 @@ export function parseTarInfo(reader = TarReader): [TarFSInfo, string[]] { info.children = new Map(); directory.children!.set(info.name, info); directory = info; - } else if (info.type === "0") { + } else if (info.type === '0') { // a normal file info.contentsOffset = contentsOffset; info.name = info.path.slice(directory.path.length); - if (info.name.endsWith(".so")) { + if (info.name.endsWith('.so')) { soFiles.push(info.path); } directory.children!.set(info.name, info); diff --git a/src/pyodide/internal/tarfs.ts b/src/pyodide/internal/tarfs.ts index 0b4f13f527a..0580b2b1bf2 100644 --- a/src/pyodide/internal/tarfs.ts +++ b/src/pyodide/internal/tarfs.ts @@ -1,4 +1,4 @@ -import { createReadonlyFS } from "pyodide-internal:readOnlyFS"; +import { createReadonlyFS } from 'pyodide-internal:readOnlyFS'; const FSOps: FSOps = { getNodeMode(parent, name, info) { @@ -18,26 +18,26 @@ const FSOps: FSOps = { }, readdir(node) { if (!node.info.children) { - throw new Error("Trying to readdir from a non-dir node"); + throw new Error('Trying to readdir from a non-dir node'); } return Array.from(node.info.children.keys()); }, lookup(parent, name) { if (!parent.info.children) { - throw new Error("Trying to lookup from a non-dir node"); + throw new Error('Trying to lookup from a non-dir node'); } return parent.info.children.get(name)!; }, read(stream, position, buffer) { if (stream.node.contentsOffset == undefined) { - throw new Error("contentsOffset is undefined"); + throw new Error('contentsOffset is undefined'); } if (!stream.node.info.reader) { - throw new Error("reader is undefined"); + throw new Error('reader is undefined'); } return stream.node.info.reader.read( stream.node.contentsOffset + position, - buffer, + buffer ); }, }; diff --git a/src/pyodide/internal/topLevelEntropy/lib.ts b/src/pyodide/internal/topLevelEntropy/lib.ts index 214a9e7f2bc..9c45f6a4450 100644 --- a/src/pyodide/internal/topLevelEntropy/lib.ts +++ b/src/pyodide/internal/topLevelEntropy/lib.ts @@ -6,12 +6,12 @@ * entropy_patches.py. setupShouldAllowBadEntropy reads out the address of the * byte that we use to control calls to crypto.getRandomValues from Python. */ -import { default as entropyPatches } from "pyodide-internal:topLevelEntropy/entropy_patches.py"; -import { default as entropyImportContext } from "pyodide-internal:topLevelEntropy/entropy_import_context.py"; -import { default as importPatchManager } from "pyodide-internal:topLevelEntropy/import_patch_manager.py"; -import { IS_TRACING } from "pyodide-internal:metadata"; -import { LOADED_SNAPSHOT_VERSION } from "pyodide-internal:snapshot"; -import { simpleRunPython } from "pyodide-internal:util"; +import { default as entropyPatches } from 'pyodide-internal:topLevelEntropy/entropy_patches.py'; +import { default as entropyImportContext } from 'pyodide-internal:topLevelEntropy/entropy_import_context.py'; +import { default as importPatchManager } from 'pyodide-internal:topLevelEntropy/import_patch_manager.py'; +import { IS_TRACING } from 'pyodide-internal:metadata'; +import { LOADED_SNAPSHOT_VERSION } from 'pyodide-internal:snapshot'; +import { simpleRunPython } from 'pyodide-internal:util'; // TODO: When we've updated all the snapshots, remove this. const SHOULD_GATE_ENTROPY = @@ -31,9 +31,9 @@ function setupShouldAllowBadEntropy(Module: Module) { // We parse this as an integer. const res = simpleRunPython( Module, - "from _cloudflare.entropy_import_context import get_bad_entropy_flag;" + - "get_bad_entropy_flag();" + - "del get_bad_entropy_flag", + 'from _cloudflare.entropy_import_context import get_bad_entropy_flag;' + + 'get_bad_entropy_flag();' + + 'del get_bad_entropy_flag' ); allowed_entropy_calls_addr = Number(res); } @@ -69,7 +69,7 @@ export function getRandomValues(Module: Module, arr: Uint8Array) { } if (!shouldAllowBadEntropy(Module)) { Module._dump_traceback(); - throw new Error("Disallowed operation called within global scope"); + throw new Error('Disallowed operation called within global scope'); } // "entropy" in the test suite is a bunch of 42's. Good to use a readily identifiable pattern // here which is different than the test suite. @@ -87,22 +87,22 @@ export function entropyMountFiles(Module: Module) { Module.FS.writeFile( `/lib/python3.12/site-packages/_cloudflare/__init__.py`, new Uint8Array(0), - { canOwn: true }, + { canOwn: true } ); Module.FS.writeFile( `/lib/python3.12/site-packages/_cloudflare/entropy_patches.py`, new Uint8Array(entropyPatches), - { canOwn: true }, + { canOwn: true } ); Module.FS.writeFile( `/lib/python3.12/site-packages/_cloudflare/entropy_import_context.py`, new Uint8Array(entropyImportContext), - { canOwn: true }, + { canOwn: true } ); Module.FS.writeFile( `/lib/python3.12/site-packages/_cloudflare/import_patch_manager.py`, new Uint8Array(importPatchManager), - { canOwn: true }, + { canOwn: true } ); } @@ -130,7 +130,7 @@ export function entropyBeforeTopLevel(Module: Module) { from _cloudflare.entropy_patches import before_top_level before_top_level() del before_top_level -`, +` ); } @@ -152,7 +152,7 @@ export function entropyBeforeRequest(Module: Module) { from _cloudflare.entropy_patches import before_first_request before_first_request() del before_first_request - `, + ` ); } else { // If we shouldn't gate entropy, we just need to reseed_rng. We first have @@ -167,7 +167,7 @@ del invalidate_caches from _cloudflare.entropy_patches import reseed_rng reseed_rng() del reseed_rng - `, + ` ); } } diff --git a/src/pyodide/internal/util.ts b/src/pyodide/internal/util.ts index d09436c6f44..1ee9dfb1b9e 100644 --- a/src/pyodide/internal/util.ts +++ b/src/pyodide/internal/util.ts @@ -1,5 +1,5 @@ export function reportError(e: any): never { - e.stack?.split("\n").forEach((s: any) => console.warn(s)); + e.stack?.split('\n').forEach((s: any) => console.warn(s)); throw e; } @@ -30,19 +30,19 @@ export function reportError(e: any): never { */ export function simpleRunPython( emscriptenModule: Module, - code: string, + code: string ): string { const [status, err] = emscriptenModule.API.rawRun(code); // status 0: Ok // status -1: Error if (status) { // PyRun_SimpleString will have written a Python traceback to stderr. - console.warn("Command failed:", code); - console.warn("Error was:"); - for (const line of err.split("\n")) { + console.warn('Command failed:', code); + console.warn('Error was:'); + for (const line of err.split('\n')) { console.warn(line); } - throw new Error("Failed"); + throw new Error('Failed'); } return err; } diff --git a/src/pyodide/python-entrypoint-helper.ts b/src/pyodide/python-entrypoint-helper.ts index 743ed9180fa..b48346329c4 100644 --- a/src/pyodide/python-entrypoint-helper.ts +++ b/src/pyodide/python-entrypoint-helper.ts @@ -1,31 +1,31 @@ // This file is a BUILTIN module that provides the actual implementation for the // python-entrypoint.js USER module. -import { loadPyodide } from "pyodide-internal:python"; +import { loadPyodide } from 'pyodide-internal:python'; import { uploadArtifacts, maybeStoreMemorySnapshot, -} from "pyodide-internal:snapshot"; -import { enterJaegerSpan } from "pyodide-internal:jaeger"; +} from 'pyodide-internal:snapshot'; +import { enterJaegerSpan } from 'pyodide-internal:jaeger'; import { TRANSITIVE_REQUIREMENTS, patchLoadPackage, -} from "pyodide-internal:setupPackages"; +} from 'pyodide-internal:setupPackages'; import { IS_TRACING, IS_WORKERD, LOCKFILE, MAIN_MODULE_NAME, WORKERD_INDEX_URL, -} from "pyodide-internal:metadata"; -import { reportError } from "pyodide-internal:util"; -import { default as Limiter } from "pyodide-internal:limiter"; -import { entropyBeforeRequest } from "pyodide-internal:topLevelEntropy/lib"; -import { loadPackages } from "pyodide-internal:loadPackage"; +} from 'pyodide-internal:metadata'; +import { reportError } from 'pyodide-internal:util'; +import { default as Limiter } from 'pyodide-internal:limiter'; +import { entropyBeforeRequest } from 'pyodide-internal:topLevelEntropy/lib'; +import { loadPackages } from 'pyodide-internal:loadPackage'; function pyimportMainModule(pyodide: Pyodide): PyModule { - if (!MAIN_MODULE_NAME.endsWith(".py")) { - throw new Error("Main module needs to end with a .py file extension"); + if (!MAIN_MODULE_NAME.endsWith('.py')) { + throw new Error('Main module needs to end with a .py file extension'); } const mainModuleName = MAIN_MODULE_NAME.slice(0, -3); return pyodide.pyimport(mainModuleName); @@ -33,7 +33,7 @@ function pyimportMainModule(pyodide: Pyodide): PyModule { let pyodidePromise: Promise | undefined; function getPyodide(): Promise { - return enterJaegerSpan("get_pyodide", () => { + return enterJaegerSpan('get_pyodide', () => { if (pyodidePromise) { return pyodidePromise; } @@ -46,12 +46,16 @@ function getPyodide(): Promise { * Import the data from the data module es6 import called jsModName.py into a module called * pyModName.py. The site_packages directory is on the path. */ -async function injectSitePackagesModule(pyodide: Pyodide, jsModName: string, pyModName: string): Promise { +async function injectSitePackagesModule( + pyodide: Pyodide, + jsModName: string, + pyModName: string +): Promise { const mod = await import(`pyodide-internal:${jsModName}.py`); pyodide.FS.writeFile( `${pyodide.site_packages}/${pyModName}.py`, new Uint8Array(mod.default), - { canOwn: true }, + { canOwn: true } ); } @@ -65,9 +69,9 @@ async function applyPatch(pyodide: Pyodide, patchName: string): Promise { await injectSitePackagesModule( pyodide, `patches/${patchName}`, - patchName + "_patch", + patchName + '_patch' ); - pyodide.pyimport(patchName + "_patch"); + pyodide.pyimport(patchName + '_patch'); } /** @@ -82,7 +86,7 @@ async function applyPatch(pyodide: Pyodide, patchName: string): Promise { * fail from there for some reason. */ export async function setupPackages(pyodide: Pyodide): Promise { - return await enterJaegerSpan("setup_packages", async () => { + return await enterJaegerSpan('setup_packages', async () => { patchLoadPackage(pyodide); await loadPackages(pyodide._module, TRANSITIVE_REQUIREMENTS); // install any extra packages into the site-packages directory, so calculate where that is. @@ -90,21 +94,21 @@ export async function setupPackages(pyodide: Pyodide): Promise { const pyminor = pyodide._module._py_version_minor(); pyodide.site_packages = `/lib/python${pymajor}.${pyminor}/site-packages`; // Install patches as needed - if (TRANSITIVE_REQUIREMENTS.has("aiohttp")) { - await applyPatch(pyodide, "aiohttp"); + if (TRANSITIVE_REQUIREMENTS.has('aiohttp')) { + await applyPatch(pyodide, 'aiohttp'); } - if (TRANSITIVE_REQUIREMENTS.has("httpx")) { - await applyPatch(pyodide, "httpx"); + if (TRANSITIVE_REQUIREMENTS.has('httpx')) { + await applyPatch(pyodide, 'httpx'); } - if (TRANSITIVE_REQUIREMENTS.has("fastapi")) { - await injectSitePackagesModule(pyodide, "asgi", "asgi"); + if (TRANSITIVE_REQUIREMENTS.has('fastapi')) { + await injectSitePackagesModule(pyodide, 'asgi', 'asgi'); } }); } let mainModulePromise: Promise | undefined; function getMainModule(): Promise { - return enterJaegerSpan("get_main_module", async () => { + return enterJaegerSpan('get_main_module', async () => { if (mainModulePromise) { return mainModulePromise; } @@ -113,8 +117,8 @@ function getMainModule(): Promise { await setupPackages(pyodide); Limiter.beginStartup(); try { - return enterJaegerSpan("pyimport_main_module", () => - pyimportMainModule(pyodide), + return enterJaegerSpan('pyimport_main_module', () => + pyimportMainModule(pyodide) ); } finally { Limiter.finishStartup(); @@ -135,14 +139,14 @@ function makeHandler(pyHandlerName: string): Handler { return async function (...args: any[]) { try { const mainModule = await enterJaegerSpan( - "prep_python", - async () => await preparePython(), + 'prep_python', + async () => await preparePython() ); - return await enterJaegerSpan("python_code", () => { + return await enterJaegerSpan('python_code', () => { return mainModule[pyHandlerName].callRelaxed(...args); }); } catch (e) { - console.warn("Error in makeHandler"); + console.warn('Error in makeHandler'); reportError(e); } finally { args[2].waitUntil(uploadArtifacts()); @@ -150,7 +154,7 @@ function makeHandler(pyHandlerName: string): Handler { }; } const handlers: { - [handlerName: string]: Handler + [handlerName: string]: Handler; } = {}; try { @@ -168,20 +172,20 @@ try { } if (IS_WORKERD || IS_TRACING) { - handlers.fetch = makeHandler("on_fetch"); - handlers.test = makeHandler("test"); + handlers.fetch = makeHandler('on_fetch'); + handlers.test = makeHandler('test'); } else { const mainModule = await getMainModule(); for (const handlerName of [ - "fetch", - "alarm", - "scheduled", - "trace", - "queue", - "pubsub", + 'fetch', + 'alarm', + 'scheduled', + 'trace', + 'queue', + 'pubsub', ]) { - const pyHandlerName = "on_" + handlerName; - if (typeof mainModule[pyHandlerName] === "function") { + const pyHandlerName = 'on_' + handlerName; + if (typeof mainModule[pyHandlerName] === 'function') { handlers[handlerName] = makeHandler(pyHandlerName); } } @@ -194,7 +198,7 @@ try { */ maybeStoreMemorySnapshot(); } catch (e) { - console.warn("Error in top level in python-entrypoint-helper.js"); + console.warn('Error in top level in python-entrypoint-helper.js'); reportError(e); } diff --git a/src/pyodide/python-entrypoint.js b/src/pyodide/python-entrypoint.js index 98025a78baf..66829110256 100644 --- a/src/pyodide/python-entrypoint.js +++ b/src/pyodide/python-entrypoint.js @@ -6,4 +6,4 @@ // we delegate the implementation to `python-entrypoint-helper` which is a // BUILTIN module that can see our INTERNAL modules. -export { default } from "pyodide:python-entrypoint-helper"; +export { default } from 'pyodide:python-entrypoint-helper'; diff --git a/src/pyodide/types/FS.d.ts b/src/pyodide/types/FS.d.ts index d11ed38f73a..937b65fd51e 100644 --- a/src/pyodide/types/FS.d.ts +++ b/src/pyodide/types/FS.d.ts @@ -1,4 +1,3 @@ - interface Reader { read: (offset: number, dest: Uint8Array) => number; } @@ -24,24 +23,36 @@ interface FS { mkdirTree: (dirname: string) => void; writeFile: (fname: string, contents: Uint8Array, options: object) => void; mount(fs: object, options: { info?: Info }, path: string): void; - createNode(parent: FSNode | null, name: string, mode: number): FSNode; + createNode( + parent: FSNode | null, + name: string, + mode: number + ): FSNode; isFile: (mode: number) => boolean; genericErrors: Error[]; } interface FSOps { - getNodeMode: (parent: FSNode | null, name: string, info: Info) => { + getNodeMode: ( + parent: FSNode | null, + name: string, + info: Info + ) => { permissions: number; isDir: boolean; }; setNodeAttributes: (node: FSNode, info: Info, isDir: boolean) => void; readdir: (node: FSNode) => string[]; lookup: (parent: FSNode, name: string) => Info; - read: (stream: FSStream, position: number, buffer: Uint8Array) => number; + read: ( + stream: FSStream, + position: number, + buffer: Uint8Array + ) => number; } interface MountOpts { - opts: { info: Info } + opts: { info: Info }; } interface FSNodeOps { @@ -57,7 +68,13 @@ interface FSStream { interface FSStreamOps { llseek: (stream: FSStream, offset: number, whence: number) => number; - read: (stream: FSStream, buffer: Uint8Array, offset: number, length: number, position: number) => number; + read: ( + stream: FSStream, + buffer: Uint8Array, + offset: number, + length: number, + position: number + ) => number; } interface FSNode { @@ -79,19 +96,23 @@ interface FSAttr { mode: number; nlink: number; uid: number; - gid: number, - rdev: number, - size: number, - atime: Date, - mtime: Date, - ctime: Date, + gid: number; + rdev: number; + size: number; + atime: Date; + mtime: Date; + ctime: Date; blksize: number; blocks: number; } interface EmscriptenFS { mount: (mount: MountOpts) => FSNode; - createNode: (parent: FSNode | null, name: string, info: Info) => FSNode; + createNode: ( + parent: FSNode | null, + name: string, + info: Info + ) => FSNode; node_ops: FSNodeOps; stream_ops: FSStreamOps; } diff --git a/src/pyodide/types/Module.d.ts b/src/pyodide/types/Module.d.ts index 04463552bc9..6257162d26f 100644 --- a/src/pyodide/types/Module.d.ts +++ b/src/pyodide/types/Module.d.ts @@ -1,4 +1,3 @@ - interface ENV { HOME: string; } @@ -38,6 +37,6 @@ interface Module { loadWebAssemblyModule: ( mod: WebAssembly.Module, opt: object, - path: string, + path: string ) => WebAssembly.Exports; } diff --git a/src/pyodide/types/Pyodide.d.ts b/src/pyodide/types/Pyodide.d.ts index 544b9a12cc1..b2b245a2490 100644 --- a/src/pyodide/types/Pyodide.d.ts +++ b/src/pyodide/types/Pyodide.d.ts @@ -1,8 +1,8 @@ -declare type Handler = ((...args: any[]) => any); +declare type Handler = (...args: any[]) => any; interface PyModule { [handlerName: string]: { - callRelaxed: (...args: any[]) => any + callRelaxed: (...args: any[]) => any; }; } diff --git a/src/pyodide/types/artifacts.d.ts b/src/pyodide/types/artifacts.d.ts index 4cfa43b7f46..25dbf38d033 100644 --- a/src/pyodide/types/artifacts.d.ts +++ b/src/pyodide/types/artifacts.d.ts @@ -2,13 +2,13 @@ declare namespace ArtifactBundler { type MemorySnapshotResult = { snapshot: Uint8Array; importedModulesList: Array; - } + }; const hasMemorySnapshot: () => boolean; const isEwValidating: () => boolean; const readMemorySnapshot: ( offset: number, - buf: Uint32Array | Uint8Array, + buf: Uint32Array | Uint8Array ) => void; const getMemorySnapshotSize: () => number; const disposeMemorySnapshot: () => void; diff --git a/src/pyodide/types/emscripten.d.ts b/src/pyodide/types/emscripten.d.ts index b6c7f300559..46d465901d5 100644 --- a/src/pyodide/types/emscripten.d.ts +++ b/src/pyodide/types/emscripten.d.ts @@ -4,12 +4,12 @@ interface EmscriptenSettings { wasmImports: WebAssembly.Imports, successCallback: ( inst: WebAssembly.Instance, - mod: WebAssembly.Module, - ) => void, + mod: WebAssembly.Module + ) => void ) => WebAssembly.Exports; reportUndefinedSymbolsNoOp: () => void; noInitialRun: boolean; API: { - config: API["config"]; + config: API['config']; }; } diff --git a/src/pyodide/types/limiter.d.ts b/src/pyodide/types/limiter.d.ts index 4839779bf21..d71b1b6c8f7 100644 --- a/src/pyodide/types/limiter.d.ts +++ b/src/pyodide/types/limiter.d.ts @@ -1,7 +1,6 @@ // A typescript declaration file for the internal Limiter JSG class // see src/workerd/api/pyodide/pyodide.h (SimplePythonLimiter) - interface Limiter { beginStartup: () => void; finishStartup: () => void; diff --git a/src/pyodide/types/packages_tar_reader.d.ts b/src/pyodide/types/packages_tar_reader.d.ts index 82b9011ec39..7a3fc5f2d43 100644 --- a/src/pyodide/types/packages_tar_reader.d.ts +++ b/src/pyodide/types/packages_tar_reader.d.ts @@ -1,4 +1,3 @@ - declare const TarReader: Reader; export default TarReader; diff --git a/src/pyodide/types/pyodide-bucket.d.ts b/src/pyodide/types/pyodide-bucket.d.ts index 8dddf3d5304..64f4bfb716a 100644 --- a/src/pyodide/types/pyodide-bucket.d.ts +++ b/src/pyodide/types/pyodide-bucket.d.ts @@ -2,7 +2,7 @@ interface PYODIDE_BUCKET { PYODIDE_PACKAGE_BUCKET_URL: string; } -declare module "pyodide-internal:generated/pyodide-bucket.json" { +declare module 'pyodide-internal:generated/pyodide-bucket.json' { const bucket: PYODIDE_BUCKET; export default bucket; } diff --git a/src/pyodide/types/pyodide-lock.d.ts b/src/pyodide/types/pyodide-lock.d.ts index 54e6437f175..d769a734a41 100644 --- a/src/pyodide/types/pyodide-lock.d.ts +++ b/src/pyodide/types/pyodide-lock.d.ts @@ -2,7 +2,7 @@ interface PackageDeclaration { depends: string[]; file_name: string; imports: string[]; - install_dir: "site" | "stdlib"; + install_dir: 'site' | 'stdlib'; name: string; package_type: string; sha256: string; @@ -17,7 +17,7 @@ interface PackageLock { }; } -declare module "pyodide-internal:generated/pyodide-lock.json" { +declare module 'pyodide-internal:generated/pyodide-lock.json' { const lock: PackageLock; export default lock; } diff --git a/src/pyodide/types/pyodide.asm.d.ts b/src/pyodide/types/pyodide.asm.d.ts index 973b0612d5f..d3046e3197a 100644 --- a/src/pyodide/types/pyodide.asm.d.ts +++ b/src/pyodide/types/pyodide.asm.d.ts @@ -1,8 +1,8 @@ -declare module "pyodide-internal:generated/pyodide.asm.wasm" { +declare module 'pyodide-internal:generated/pyodide.asm.wasm' { const pyodideWasmModule: WebAssembly.Module; export default pyodideWasmModule; } -declare module "pyodide-internal:generated/pyodide.asm" { +declare module 'pyodide-internal:generated/pyodide.asm' { const _createPyodideModule: (es: EmscriptenSettings) => Module; } diff --git a/src/pyodide/types/python_stdlib.zip.d.ts b/src/pyodide/types/python_stdlib.zip.d.ts index 86cebf724b1..8576bca9be5 100644 --- a/src/pyodide/types/python_stdlib.zip.d.ts +++ b/src/pyodide/types/python_stdlib.zip.d.ts @@ -1,4 +1,4 @@ -declare module "pyodide-internal:generated/python_stdlib.zip" { +declare module 'pyodide-internal:generated/python_stdlib.zip' { const stdlib: Uint8Array; export default stdlib; } diff --git a/src/pyodide/types/runtime-generated/metadata.d.ts b/src/pyodide/types/runtime-generated/metadata.d.ts index 84d4847ae6d..ee0fb110615 100644 --- a/src/pyodide/types/runtime-generated/metadata.d.ts +++ b/src/pyodide/types/runtime-generated/metadata.d.ts @@ -10,7 +10,7 @@ declare namespace MetadataReader { const getSizes: () => number[]; const readMemorySnapshot: ( offset: number, - buf: Uint32Array | Uint8Array, + buf: Uint32Array | Uint8Array ) => void; const getMemorySnapshotSize: () => number; const disposeMemorySnapshot: () => void; diff --git a/src/workerd/api/actor-alarms-delete-test.js b/src/workerd/api/actor-alarms-delete-test.js index 368c7a57c03..2fe2cdf32d0 100644 --- a/src/workerd/api/actor-alarms-delete-test.js +++ b/src/workerd/api/actor-alarms-delete-test.js @@ -5,7 +5,7 @@ // This test is aimed towards validating a correct deleteAlarm behavior in workerd. // Currently running alarms cannot be deleted within alarm() handler, but can delete it everywhere // else. -import * as assert from 'node:assert' +import * as assert from 'node:assert'; export class DurableObjectExample { constructor(state) { @@ -21,13 +21,16 @@ export class DurableObjectExample { try { await prom; if (Date.now() < scheduledTime.valueOf()) { - throw new Error(`Date.now() is before scheduledTime! ${Date.now()} vs ${scheduledTime.valueOf()}`); + throw new Error( + `Date.now() is before scheduledTime! ${Date.now()} vs ${scheduledTime.valueOf()}` + ); } } catch (e) { - throw new Error(`error waiting for alarm at ${scheduledTime.valueOf()}: ${e}`); + throw new Error( + `error waiting for alarm at ${scheduledTime.valueOf()}: ${e}` + ); } - let alarm = await this.state.storage.getAlarm(); if (alarm != null) { throw new Error(`alarm time not cleared when handler ends. ${alarm}`); @@ -72,16 +75,16 @@ export class DurableObjectExample { assert.equal(this.state.alarmsTriggered, 1); // All done, return "OK" because if we reach this, everything worked as expected. - return new Response("OK"); + return new Response('OK'); } } export default { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - assert.equal(text, "OK"); - } -} + assert.equal(text, 'OK'); + }, +}; diff --git a/src/workerd/api/actor-alarms-test.js b/src/workerd/api/actor-alarms-test.js index 234388a3075..7b7887ebbcb 100644 --- a/src/workerd/api/actor-alarms-test.js +++ b/src/workerd/api/actor-alarms-test.js @@ -2,7 +2,7 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from 'node:assert' +import * as assert from 'node:assert'; export class DurableObjectExample { constructor(state, env) { @@ -18,10 +18,14 @@ export class DurableObjectExample { try { await prom; if (Date.now() < scheduledTime.valueOf()) { - throw new Error(`Date.now() is before scheduledTime! ${Date.now()} vs ${scheduledTime.valueOf()}`); + throw new Error( + `Date.now() is before scheduledTime! ${Date.now()} vs ${scheduledTime.valueOf()}` + ); } } catch (e) { - throw new Error(`error waiting for alarm at ${scheduledTime.valueOf()}: ${e}`); + throw new Error( + `error waiting for alarm at ${scheduledTime.valueOf()}: ${e}` + ); } let alarm = await this.state.storage.getAlarm(); @@ -37,7 +41,7 @@ export class DurableObjectExample { await this.waitForAlarm(time); - return new Response("OK"); + return new Response('OK'); } async alarm() { @@ -51,10 +55,10 @@ export class DurableObjectExample { export default { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - assert.equal(text, "OK"); - } -} + assert.equal(text, 'OK'); + }, +}; diff --git a/src/workerd/api/analytics-engine-test.js b/src/workerd/api/analytics-engine-test.js index 00007963593..1b465b7288c 100644 --- a/src/workerd/api/analytics-engine-test.js +++ b/src/workerd/api/analytics-engine-test.js @@ -6,23 +6,23 @@ async function isWritten(timeout) { do { if (written) return true; await scheduler.wait(100); - } while ((Date.now() - start) < timeout); - throw new Error("Test never received request from analytics engine handler"); + } while (Date.now() - start < timeout); + throw new Error('Test never received request from analytics engine handler'); } -export default { +export default { async fetch(ctrl, env, ctx) { - written = true - return new Response(""); + written = true; + return new Response(''); }, async test(ctrl, env, ctx) { env.aebinding.writeDataPoint({ - 'blobs': ["TestBlob"], - 'doubles': [25], - 'indexes': ["testindex"], + blobs: ['TestBlob'], + doubles: [25], + indexes: ['testindex'], }); assert.equal(await isWritten(5000), true); - return new Response(""); - }, -} + return new Response(''); + }, +}; diff --git a/src/workerd/api/gpu/webgpu-buffer-test.js b/src/workerd/api/gpu/webgpu-buffer-test.js index 6a74ec40f1d..cc00a82015d 100644 --- a/src/workerd/api/gpu/webgpu-buffer-test.js +++ b/src/workerd/api/gpu/webgpu-buffer-test.js @@ -1,4 +1,4 @@ -import { deepEqual, ok, equal } from "node:assert"; +import { deepEqual, ok, equal } from 'node:assert'; export class DurableObjectExample { constructor(state) { @@ -20,7 +20,7 @@ export class DurableObjectExample { ); const emptyBufferContents = Array(bufferSize).fill(0); const gpuWriteBuffer = device.createBuffer({ - label: "gpuWriteBuffer", + label: 'gpuWriteBuffer', mappedAtCreation: true, size: bufferSize, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC, @@ -31,7 +31,7 @@ export class DurableObjectExample { deepEqual(gpuWriteBuffer.usage, 6); - deepEqual(gpuWriteBuffer.mapState, "mapped"); + deepEqual(gpuWriteBuffer.mapState, 'mapped'); const arrayBuffer = gpuWriteBuffer.getMappedRange(); ok(arrayBuffer); @@ -44,7 +44,7 @@ export class DurableObjectExample { // Get a GPU buffer for reading in an unmapped state. const gpuReadBuffer = device.createBuffer({ - label: "gpuReadBuffer", + label: 'gpuReadBuffer', mappedAtCreation: false, size: bufferSize, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, @@ -96,7 +96,7 @@ export class DurableObjectExample { const textureSize = 64; const textureDesc = { size: { width: textureSize, height: textureSize, depthOrArrayLayers: 1 }, - format: "rgba8unorm-srgb", + format: 'rgba8unorm-srgb', usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST, }; const texture = device.createTexture(textureDesc); @@ -149,16 +149,16 @@ export class DurableObjectExample { 4 ); - return new Response("OK"); + return new Response('OK'); } } export const buffer_mapping = { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - equal(text, "OK"); + equal(text, 'OK'); }, }; diff --git a/src/workerd/api/gpu/webgpu-compute-test.js b/src/workerd/api/gpu/webgpu-compute-test.js index bf6aba520be..81c2f098a21 100644 --- a/src/workerd/api/gpu/webgpu-compute-test.js +++ b/src/workerd/api/gpu/webgpu-compute-test.js @@ -1,4 +1,4 @@ -import { deepEqual, ok, equal } from "node:assert"; +import { deepEqual, ok, equal } from 'node:assert'; export class DurableObjectExample { constructor(state) { @@ -7,9 +7,9 @@ export class DurableObjectExample { async fetch() { ok(navigator.gpu); - if (!("gpu" in navigator)) { + if (!('gpu' in navigator)) { console.log( - "WebGPU is not supported. Enable chrome://flags/#enable-unsafe-webgpu flag." + 'WebGPU is not supported. Enable chrome://flags/#enable-unsafe-webgpu flag.' ); return; } @@ -17,18 +17,18 @@ export class DurableObjectExample { const adapter = await navigator.gpu.requestAdapter(); ok(adapter); - const adapterInfo = await adapter.requestAdapterInfo(["device"]); + const adapterInfo = await adapter.requestAdapterInfo(['device']); ok(adapterInfo); ok(adapterInfo.device); ok(adapter.features.keys()); - ok(adapter.features.has("depth-clip-control")); + ok(adapter.features.has('depth-clip-control')); ok(adapter.limits); ok(adapter.limits.maxBufferSize); const requiredFeatures = []; - requiredFeatures.push("depth-clip-control"); + requiredFeatures.push('depth-clip-control'); const device = await adapter.requestDevice({ requiredFeatures, }); @@ -37,7 +37,7 @@ export class DurableObjectExample { ok(device.lost); ok(device.features.keys()); - ok(device.features.has("depth-clip-control")); + ok(device.features.has('depth-clip-control')); ok(device.limits); ok(device.limits.maxBufferSize); @@ -46,8 +46,8 @@ export class DurableObjectExample { 2 /* rows */, 4 /* columns */, 1, 2, 3, 4, 5, 6, 7, 8, ]); - device.pushErrorScope("out-of-memory"); - device.pushErrorScope("validation"); + device.pushErrorScope('out-of-memory'); + device.pushErrorScope('validation'); const gpuBufferFirstMatrix = device.createBuffer({ mappedAtCreation: true, @@ -98,21 +98,21 @@ export class DurableObjectExample { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { - type: "read-only-storage", + type: 'read-only-storage', }, }, { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { - type: "read-only-storage", + type: 'read-only-storage', }, }, { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { - type: "storage", + type: 'storage', }, }, ], @@ -190,17 +190,17 @@ export class DurableObjectExample { }), compute: { module: shaderModule, - entryPoint: "main", + entryPoint: 'main', }, }); ok(computePipeline); // Pipeline with auto layout const computePipelineAuto = device.createComputePipeline({ - layout: "auto", + layout: 'auto', compute: { module: shaderModule, - entryPoint: "main", + entryPoint: 'main', }, }); ok(computePipelineAuto); @@ -232,9 +232,9 @@ export class DurableObjectExample { ok(bindGroupAutoLayout); // Commands submission - const commandEncoder = device.createCommandEncoder({ label: "label1" }); + const commandEncoder = device.createCommandEncoder({ label: 'label1' }); ok(commandEncoder); - equal(commandEncoder.label, "label1"); + equal(commandEncoder.label, 'label1'); const passEncoder = commandEncoder.beginComputePass(); ok(passEncoder); @@ -279,16 +279,16 @@ export class DurableObjectExample { new Float32Array([2, 2, 50, 60, 114, 140]) ); - return new Response("OK"); + return new Response('OK'); } } export const compute_shader = { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - equal(text, "OK"); + equal(text, 'OK'); }, }; diff --git a/src/workerd/api/gpu/webgpu-errors-test.js b/src/workerd/api/gpu/webgpu-errors-test.js index 68bf7c2d874..132ba571a4a 100644 --- a/src/workerd/api/gpu/webgpu-errors-test.js +++ b/src/workerd/api/gpu/webgpu-errors-test.js @@ -1,4 +1,4 @@ -import { ok, equal } from "node:assert"; +import { ok, equal } from 'node:assert'; export class DurableObjectExample { constructor(state) { @@ -17,8 +17,11 @@ export class DurableObjectExample { ok(device.features.keys()); let callbackCalled = false; - device.addEventListener("uncapturederror", (event) => { - ok(event.error.message.includes("not a multiple of 4") || event.error.message.includes("Error while parsing WGSL")); + device.addEventListener('uncapturederror', (event) => { + ok( + event.error.message.includes('not a multiple of 4') || + event.error.message.includes('Error while parsing WGSL') + ); callbackCalled = true; }); @@ -28,7 +31,7 @@ export class DurableObjectExample { usage: GPUBufferUsage.STORAGE, }); - device.pushErrorScope("validation"); + device.pushErrorScope('validation'); device.createBuffer({ mappedAtCreation: true, @@ -78,21 +81,21 @@ export class DurableObjectExample { const compilationInfo = await shaderModule.getCompilationInfo(); ok(compilationInfo.messages.length === 1); - ok(compilationInfo.messages[0].type === "error"); + ok(compilationInfo.messages[0].type === 'error'); // ensure callback with error was indeed called ok(callbackCalled); - return new Response("OK"); + return new Response('OK'); } } export const error_handling = { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - equal(text, "OK"); + equal(text, 'OK'); }, }; diff --git a/src/workerd/api/gpu/webgpu-windowless-test.js b/src/workerd/api/gpu/webgpu-windowless-test.js index 8576464ace0..94040fef2c6 100644 --- a/src/workerd/api/gpu/webgpu-windowless-test.js +++ b/src/workerd/api/gpu/webgpu-windowless-test.js @@ -1,11 +1,11 @@ -import { ok, deepEqual, equal } from "node:assert"; +import { ok, deepEqual, equal } from 'node:assert'; async function hash(data) { - const hashBuffer = await crypto.subtle.digest("SHA-256", data); + const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray - .map((bytes) => bytes.toString(16).padStart(2, "0")) - .join(""); + .map((bytes) => bytes.toString(16).padStart(2, '0')) + .join(''); return hashHex; } @@ -17,7 +17,7 @@ export class DurableObjectExample { async fetch() { ok(navigator.gpu); const adapter = await navigator.gpu.requestAdapter({ - powerPreference: "high-performance", + powerPreference: 'high-performance', forceFallbackAdapter: false, }); ok(adapter); @@ -28,7 +28,7 @@ export class DurableObjectExample { const textureSize = 256; const textureDesc = { size: { width: textureSize, height: textureSize, depthOrArrayLayers: 1 }, - format: "rgba8unorm-srgb", + format: 'rgba8unorm-srgb', usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, }; const texture = device.createTexture(textureDesc); @@ -84,12 +84,12 @@ export class DurableObjectExample { layout: pipelineLayout, vertex: { module: shaderModule, - entryPoint: "vs_main", + entryPoint: 'vs_main', buffers: [], }, fragment: { module: shaderModule, - entryPoint: "fs_main", + entryPoint: 'fs_main', targets: [ { format: textureDesc.format, @@ -102,8 +102,8 @@ export class DurableObjectExample { ], }, primitive: { - frontFace: "ccw", - GPUCullMode: "back", + frontFace: 'ccw', + GPUCullMode: 'back', }, multisample: { count: 1, @@ -119,8 +119,8 @@ export class DurableObjectExample { colorAttachments: [ { clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }, - loadOp: "clear", - storeOp: "store", + loadOp: 'clear', + storeOp: 'store', view: textureView, }, ], @@ -134,7 +134,7 @@ export class DurableObjectExample { encoder.copyTextureToBuffer( { - aspect: "all", + aspect: 'all', texture: texture, mipLevel: 0, origin: {}, @@ -159,20 +159,20 @@ export class DurableObjectExample { const result = await hash(data); equal( result, - "dd7fd0917e7f9383fd7f2ae5027bf6a4f8f90b2ab5c69c52d4f29a856bd9165a" + 'dd7fd0917e7f9383fd7f2ae5027bf6a4f8f90b2ab5c69c52d4f29a856bd9165a' ); outputBuffer.unmap(); - return new Response("OK"); + return new Response('OK'); } } export const windowless = { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - equal(text, "OK"); + equal(text, 'OK'); }, }; diff --git a/src/workerd/api/gpu/webgpu-write-test.js b/src/workerd/api/gpu/webgpu-write-test.js index 7e431078869..1471f7627ac 100644 --- a/src/workerd/api/gpu/webgpu-write-test.js +++ b/src/workerd/api/gpu/webgpu-write-test.js @@ -1,4 +1,4 @@ -import { ok, deepEqual, equal } from "node:assert"; +import { ok, deepEqual, equal } from 'node:assert'; export class DurableObjectExample { constructor(state) { @@ -26,16 +26,16 @@ export class DurableObjectExample { new Uint8Array(arrayBuffer).set([0, 1, 2, 3]); deepEqual(new Uint8Array(arrayBuffer), new Uint8Array([0, 1, 2, 3])); - return new Response("OK"); + return new Response('OK'); } } export const buffer_write = { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("A"); + let id = env.ns.idFromName('A'); let obj = env.ns.get(id); - let res = await obj.fetch("http://foo/test"); + let res = await obj.fetch('http://foo/test'); let text = await res.text(); - equal(text, "OK"); + equal(text, 'OK'); }, }; diff --git a/src/workerd/api/http-standard-test.js b/src/workerd/api/http-standard-test.js index 020a25bc2b7..eba3b856ae9 100644 --- a/src/workerd/api/http-standard-test.js +++ b/src/workerd/api/http-standard-test.js @@ -6,22 +6,23 @@ export default { return new Response(null, { status: 302, headers: { - location: ' /\t2 ' - } + location: ' /\t2 ', + }, }); } else if (req.url.endsWith('/2')) { - return new Response("ok"); + return new Response('ok'); } - } + }, }; export const test = { async test(ctrl, env) { - - const resp = await env.SERVICE.fetch(' http://p\tl\na\tc\ne\th\no\tl\nd\te\nr\t/ '); + const resp = await env.SERVICE.fetch( + ' http://p\tl\na\tc\ne\th\no\tl\nd\te\nr\t/ ' + ); console.log(resp.url); - strictEqual(await resp.text(), "ok"); - } + strictEqual(await resp.text(), 'ok'); + }, }; diff --git a/src/workerd/api/http-test-ts.ts b/src/workerd/api/http-test-ts.ts index a01a6786e28..fce4711a8d1 100644 --- a/src/workerd/api/http-test-ts.ts +++ b/src/workerd/api/http-test-ts.ts @@ -2,46 +2,62 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import assert from "node:assert"; +import assert from 'node:assert'; -async function assertRequestCacheThrowsError(cacheHeader: RequestCache, +async function assertRequestCacheThrowsError( + cacheHeader: RequestCache, errorName: String = 'Error', - errorMessage: String = "The 'cache' field on 'RequestInitializerDict' is not implemented.") { - assert.throws(() => { - const header = { cache : cacheHeader}; - const req: RequestInit = header; - new Request('https://example.org', req); - }, { - name: errorName, - message: errorMessage, - }); + errorMessage: String = "The 'cache' field on 'RequestInitializerDict' is not implemented." +) { + assert.throws( + () => { + const header = { cache: cacheHeader }; + const req: RequestInit = header; + new Request('https://example.org', req); + }, + { + name: errorName, + message: errorMessage, + } + ); } -async function assertFetchCacheRejectsError(cacheHeader: RequestCache, +async function assertFetchCacheRejectsError( + cacheHeader: RequestCache, errorName: String = 'Error', - errorMessage: String = "The 'cache' field on 'RequestInitializerDict' is not implemented.") { - await assert.rejects((async () => { - const header = { cache : cacheHeader}; - const req: RequestInit = header; - await fetch('http://example.org', req); - })(), { - name: errorName, - message: errorMessage, - }); + errorMessage: String = "The 'cache' field on 'RequestInitializerDict' is not implemented." +) { + await assert.rejects( + (async () => { + const header = { cache: cacheHeader }; + const req: RequestInit = header; + await fetch('http://example.org', req); + })(), + { + name: errorName, + message: errorMessage, + } + ); } export const cacheMode = { - async test() { - let cacheModes: Array = ['default', 'force-cache', 'no-cache', 'no-store', 'only-if-cached', 'reload']; - assert.strictEqual("cache" in Request.prototype, false); + let cacheModes: Array = [ + 'default', + 'force-cache', + 'no-cache', + 'no-store', + 'only-if-cached', + 'reload', + ]; + assert.strictEqual('cache' in Request.prototype, false); { const req = new Request('https://example.org', {}); assert.strictEqual(req.cache, undefined); } - for(var cacheMode of cacheModes) { + for (var cacheMode of cacheModes) { await assertRequestCacheThrowsError(cacheMode); await assertFetchCacheRejectsError(cacheMode); } - } -} + }, +}; diff --git a/src/workerd/api/http-test.js b/src/workerd/api/http-test.js index 85f456c13a0..936769d6ff9 100644 --- a/src/workerd/api/http-test.js +++ b/src/workerd/api/http-test.js @@ -2,20 +2,20 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import assert from "node:assert"; -import util from "node:util"; +import assert from 'node:assert'; +import util from 'node:util'; let scheduledLastCtrl; export default { async fetch(request, env, ctx) { const { pathname } = new URL(request.url); - if (pathname === "/body-length") { + if (pathname === '/body-length') { return Response.json(Object.fromEntries(request.headers)); } - if (pathname === "/web-socket") { + if (pathname === '/web-socket') { const pair = new WebSocketPair(); - pair[0].addEventListener("message", (event) => { + pair[0].addEventListener('message', (event) => { pair[0].send(util.inspect(event)); }); pair[0].accept(); @@ -29,7 +29,7 @@ export default { async scheduled(ctrl, env, ctx) { scheduledLastCtrl = ctrl; - if (ctrl.cron === "* * * * 30") ctrl.noRetry(); + if (ctrl.cron === '* * * * 30') ctrl.noRetry(); }, async test(ctrl, env, ctx) { @@ -39,13 +39,16 @@ export default { const writer = body.writable.getWriter(); void writer.write(new Uint8Array([1, 2, 3])); void writer.close(); - const response = await env.SERVICE.fetch("http://placeholder/body-length", { - method: "POST", - body: body.readable, - }); + const response = await env.SERVICE.fetch( + 'http://placeholder/body-length', + { + method: 'POST', + body: body.readable, + } + ); const headers = new Headers(await response.json()); - assert.strictEqual(headers.get("Content-Length"), "3"); - assert.strictEqual(headers.get("Transfer-Encoding"), null); + assert.strictEqual(headers.get('Content-Length'), '3'); + assert.strictEqual(headers.get('Transfer-Encoding'), null); } // Check `fetch()` with unknown body length @@ -54,40 +57,47 @@ export default { const writer = body.writable.getWriter(); void writer.write(new Uint8Array([1, 2, 3])); void writer.close(); - const response = await env.SERVICE.fetch("http://placeholder/body-length", { - method: "POST", - body: body.readable, - }); + const response = await env.SERVICE.fetch( + 'http://placeholder/body-length', + { + method: 'POST', + body: body.readable, + } + ); const headers = new Headers(await response.json()); - assert.strictEqual(headers.get("Content-Length"), null); - assert.strictEqual(headers.get("Transfer-Encoding"), "chunked"); + assert.strictEqual(headers.get('Content-Length'), null); + assert.strictEqual(headers.get('Transfer-Encoding'), 'chunked'); } // Call `scheduled()` with no options { const result = await env.SERVICE.scheduled(); - assert.strictEqual(result.outcome, "ok"); + assert.strictEqual(result.outcome, 'ok'); assert(!result.noRetry); assert(Math.abs(Date.now() - scheduledLastCtrl.scheduledTime) < 3_000); - assert.strictEqual(scheduledLastCtrl.cron, ""); + assert.strictEqual(scheduledLastCtrl.cron, ''); } // Call `scheduled()` with options, and noRetry() { - const result = await env.SERVICE.scheduled({ scheduledTime: 1000, cron: "* * * * 30" }); - assert.strictEqual(result.outcome, "ok"); + const result = await env.SERVICE.scheduled({ + scheduledTime: 1000, + cron: '* * * * 30', + }); + assert.strictEqual(result.outcome, 'ok'); assert(result.noRetry); assert.strictEqual(scheduledLastCtrl.scheduledTime, 1000); - assert.strictEqual(scheduledLastCtrl.cron, "* * * * 30"); + assert.strictEqual(scheduledLastCtrl.cron, '* * * * 30'); } - } -} + }, +}; export const inspect = { async test(ctrl, env, ctx) { // Check URL with duplicate search param keys - const url = new URL("http://user:pass@placeholder:8787/path?a=1&a=2&b=3"); - assert.strictEqual(util.inspect(url), + const url = new URL('http://user:pass@placeholder:8787/path?a=1&a=2&b=3'); + assert.strictEqual( + util.inspect(url), `URL { origin: 'http://placeholder:8787', href: 'http://user:pass@placeholder:8787/path?a=1&a=2&b=3', @@ -106,25 +116,33 @@ export const inspect = { // Check FormData with lower depth const formData = new FormData(); - formData.set("string", "hello"); - formData.set("blob", new Blob(["

BLOB

"], { - type: "text/html" - })); - formData.set("file", new File(["password123"], "passwords.txt", { - type: "text/plain", - lastModified: 1000 - })); - assert.strictEqual(util.inspect(formData, { depth: 0 }), + formData.set('string', 'hello'); + formData.set( + 'blob', + new Blob(['

BLOB

'], { + type: 'text/html', + }) + ); + formData.set( + 'file', + new File(['password123'], 'passwords.txt', { + type: 'text/plain', + lastModified: 1000, + }) + ); + assert.strictEqual( + util.inspect(formData, { depth: 0 }), `FormData(3) { 'string' => 'hello', 'blob' => [File], 'file' => [File] }` ); // Check request with mutable headers - const request = new Request("http://placeholder", { - method: "POST", - body: "message", - headers: { "Content-Type": "text/plain" } + const request = new Request('http://placeholder', { + method: 'POST', + body: 'message', + headers: { 'Content-Type': 'text/plain' }, }); - assert.strictEqual(util.inspect(request), + assert.strictEqual( + util.inspect(request), `Request { method: 'POST', url: 'http://placeholder', @@ -146,8 +164,9 @@ export const inspect = { ); // Check response with immutable headers - const response = await env.SERVICE.fetch("http://placeholder/not-found"); - assert.strictEqual(util.inspect(response), + const response = await env.SERVICE.fetch('http://placeholder/not-found'); + assert.strictEqual( + util.inspect(response), `Response { status: 404, statusText: 'Not Found', @@ -168,14 +187,18 @@ export const inspect = { ); // Check `MessageEvent` with unimplemented properties - const webSocketResponse = await env.SERVICE.fetch("http://placeholder/web-socket", { - headers: { "Upgrade": "websocket" }, - }); + const webSocketResponse = await env.SERVICE.fetch( + 'http://placeholder/web-socket', + { + headers: { Upgrade: 'websocket' }, + } + ); const webSocket = webSocketResponse.webSocket; assert.notStrictEqual(webSocket, null); const messagePromise = new Promise((resolve) => { - webSocket.addEventListener("message", (event) => { - assert.strictEqual(event.data, + webSocket.addEventListener('message', (event) => { + assert.strictEqual( + event.data, `MessageEvent { data: 'data', type: 'message', @@ -200,38 +223,47 @@ export const inspect = { }); }); webSocket.accept(); - webSocket.send("data"); + webSocket.send('data'); webSocket.close(); await messagePromise; - } + }, }; -async function assertRequestCacheThrowsError(cacheHeader, +async function assertRequestCacheThrowsError( + cacheHeader, errorName = 'Error', - errorMessage = "The 'cache' field on 'RequestInitializerDict' is not implemented.") { - assert.throws(() => { - new Request('https://example.org', { cache: cacheHeader }); - }, { - name: errorName, - message: errorMessage, - }); + errorMessage = "The 'cache' field on 'RequestInitializerDict' is not implemented." +) { + assert.throws( + () => { + new Request('https://example.org', { cache: cacheHeader }); + }, + { + name: errorName, + message: errorMessage, + } + ); } -async function assertFetchCacheRejectsError(cacheHeader, +async function assertFetchCacheRejectsError( + cacheHeader, errorName = 'Error', - errorMessage = "The 'cache' field on 'RequestInitializerDict' is not implemented.") { - await assert.rejects((async () => { - await fetch('http://example.org', { cache: cacheHeader }); - })(), { - name: errorName, - message: errorMessage, - }); + errorMessage = "The 'cache' field on 'RequestInitializerDict' is not implemented." +) { + await assert.rejects( + (async () => { + await fetch('http://example.org', { cache: cacheHeader }); + })(), + { + name: errorName, + message: errorMessage, + } + ); } export const cacheMode = { - async test() { - assert.strictEqual("cache" in Request.prototype, false); + assert.strictEqual('cache' in Request.prototype, false); { const req = new Request('https://example.org', {}); assert.strictEqual(req.cache, undefined); @@ -244,5 +276,5 @@ export const cacheMode = { await assertFetchCacheRejectsError('no-cache'); await assertFetchCacheRejectsError('no-transform'); await assertFetchCacheRejectsError('unsupported'); - } -} + }, +}; diff --git a/src/workerd/api/node/tests/assert-test.js b/src/workerd/api/node/tests/assert-test.js index 600da4677f6..70236d671c0 100644 --- a/src/workerd/api/node/tests/assert-test.js +++ b/src/workerd/api/node/tests/assert-test.js @@ -77,58 +77,58 @@ export const test_ok = { [false, 0, '', undefined, NaN, null].forEach((val) => { throws(() => ok(val, 'message'), { message: 'message' }); }); - } + }, }; export const test_equal = { test(ctrl, env, ctx) { [ - {a: 1, b: 1}, - {a: 1, b: '1', fails: true}, - {a: 1, b: '1', fails: true, message: 'boom'}, - {a: 'a', b: 'a'}, - {a: ctx, b: ctx}, - ].forEach(({a,b,fails,message}) => { + { a: 1, b: 1 }, + { a: 1, b: '1', fails: true }, + { a: 1, b: '1', fails: true, message: 'boom' }, + { a: 'a', b: 'a' }, + { a: ctx, b: ctx }, + ].forEach(({ a, b, fails, message }) => { if (!fails) { - equal(a,b); - strictEqual(a,b); + equal(a, b); + strictEqual(a, b); if (message) { throws(() => notEqual(a, b, message), { message }); throws(() => notStrictEqual(a, b, message), { message }); } else { - throws(() => notEqual(a,b), { name: 'AssertionError' }); - throws(() => notStrictEqual(a,b), { name: 'AssertionError' }); + throws(() => notEqual(a, b), { name: 'AssertionError' }); + throws(() => notStrictEqual(a, b), { name: 'AssertionError' }); } } else { notEqual(a, b); notStrictEqual(a, b); if (message) { - throws(() => equal(a,b,message), { message }); - throws(() => strictEqual(a,b,message), { message }); + throws(() => equal(a, b, message), { message }); + throws(() => strictEqual(a, b, message), { message }); } else { - throws(() => equal(a,b), { name: 'AssertionError' }); - throws(() => strictEqual(a,b), { name: 'AssertionError' }); + throws(() => equal(a, b), { name: 'AssertionError' }); + throws(() => strictEqual(a, b), { name: 'AssertionError' }); } } }); - } + }, }; export const test_fail = { test(ctrl, env, ctx) { - throws(() => fail("boom"), { message: "boom" }); - throws(() => ifError("boom")); + throws(() => fail('boom'), { message: 'boom' }); + throws(() => ifError('boom')); throws(() => ifError(false)); doesNotThrow(() => ifError(null)); doesNotThrow(() => ifError(undefined)); - } + }, }; export const test_rejects = { async test(ctrl, env, ctx) { await rejects(Promise.reject(new Error('boom')), { message: 'boom' }); await doesNotReject(Promise.resolve(1)); - } + }, }; export const test_matching = { @@ -137,7 +137,7 @@ export const test_matching = { throws(() => match('hello', /not/), { name: 'AssertionError' }); doesNotMatch('hello', /not/); throws(() => doesNotMatch('hello', /hello/), { name: 'AssertionError' }); - } + }, }; export const test_deep_equal = { @@ -145,27 +145,27 @@ export const test_deep_equal = { const a = { b: [ { - c: new Uint8Array([1,2,3]), + c: new Uint8Array([1, 2, 3]), d: false, - e: 'hello' - } + e: 'hello', + }, ], }; const b = { b: [ { - c: new Uint8Array([1,2,3]), + c: new Uint8Array([1, 2, 3]), d: false, - e: 'hello' - } + e: 'hello', + }, ], }; - deepEqual(a,b); - deepStrictEqual(a,b); + deepEqual(a, b); + deepStrictEqual(a, b); b.b[0].c[0] = 4; - notDeepEqual(a,b); - notDeepStrictEqual(a,b); - } + notDeepEqual(a, b); + notDeepStrictEqual(a, b); + }, }; export const test_deep_equal_errors = { @@ -201,7 +201,7 @@ export const test_deep_equal_errors = { (err) => { assert(err instanceof AssertionError); deepEqual(trimMessage(err.message), expectedError); - return true + return true; } ); throws( @@ -209,7 +209,7 @@ export const test_deep_equal_errors = { (err) => { assert(err instanceof AssertionError); deepEqual(trimMessage(err.message), expectedError); - return true + return true; } ); } @@ -229,7 +229,7 @@ export const test_deep_equal_errors = { (err) => { assert(err instanceof AssertionError); deepEqual(trimMessage(err.message), expectedError); - return true + return true; } ); throws( @@ -237,7 +237,7 @@ export const test_deep_equal_errors = { (err) => { assert(err instanceof AssertionError); deepEqual(trimMessage(err.message), expectedError); - return true + return true; } ); } @@ -255,10 +255,10 @@ function trimMessage(msg) { export const test_mocks = { test() { const fn = mock.fn(() => {}); - fn(1,2,3); + fn(1, 2, 3); strictEqual(fn.mock.callCount(), 1); strictEqual(fn.mock.calls[0].arguments.length, 3); - deepStrictEqual(fn.mock.calls[0].arguments, [1,2,3]); + deepStrictEqual(fn.mock.calls[0].arguments, [1, 2, 3]); fn.mock.mockImplementation(() => 42); strictEqual(fn(), 42); @@ -266,7 +266,7 @@ export const test_mocks = { fn.mock.resetCalls(); strictEqual(fn.mock.callCount(), 0); - } + }, }; export const spiesOnFunction = { @@ -293,12 +293,12 @@ export const spiesOnFunction = { strictEqual(call.result, 10); strictEqual(call.target, undefined); strictEqual(call.this, 1000); - } + }, }; export const speiesOnBoundFunction = { test() { - const bound = function(arg1, arg2) { + const bound = function (arg1, arg2) { return this + arg1 + arg2; }.bind(50); const sum = mock.fn(bound); @@ -319,7 +319,7 @@ export const speiesOnBoundFunction = { strictEqual(call.result, 60); strictEqual(call.target, undefined); strictEqual(call.this, undefined); - } + }, }; export const spiesOnConstructor = { @@ -361,7 +361,7 @@ export const spiesOnConstructor = { strictEqual(call.result, instance); strictEqual(call.target, Clazz); strictEqual(call.this, instance); - } + }, }; export const noopSpyCreatedByDefault = { @@ -377,7 +377,7 @@ export const noopSpyCreatedByDefault = { strictEqual(call.result, undefined); strictEqual(call.target, undefined); strictEqual(call.this, undefined); - } + }, }; export const internalNoOpFunctionCanBeReused = { @@ -395,7 +395,7 @@ export const internalNoOpFunctionCanBeReused = { strictEqual(fn2.mock.calls.length, 1); strictEqual(fn1.prop, true); strictEqual(fn2.prop, undefined); - } + }, }; export const functionsCanBeMockedMultipleTimesAtOnce = { @@ -424,7 +424,7 @@ export const functionsCanBeMockedMultipleTimesAtOnce = { notStrictEqual(fn1.mock, fn2.mock); strictEqual(fn1.mock.calls.length, 1); strictEqual(fn2.mock.calls.length, 2); - } + }, }; export const internalNoopFunctionCanBeReusedAsMethods = { @@ -451,7 +451,7 @@ export const internalNoopFunctionCanBeReusedAsMethods = { strictEqual(obj.bar.mock.calls.length, 2); strictEqual(obj.foo.prop, true); strictEqual(obj.bar.prop, undefined); - } + }, }; export const methodsCanBeMockedMultipleTimesButNotAtTheSameTime = { @@ -495,7 +495,7 @@ export const methodsCanBeMockedMultipleTimesButNotAtTheSameTime = { obj.sum.mock.restore(); strictEqual(obj.sum, originalSum); strictEqual(obj.sum.mock, undefined); - } + }, }; export const spiesOnObjectMethod = { @@ -522,7 +522,7 @@ export const spiesOnObjectMethod = { strictEqual(obj.method.mock.restore(), undefined); strictEqual(obj.method(1, 3), 9); strictEqual(obj.method.mock, undefined); - } + }, }; export const spiesOnGetter = { @@ -550,7 +550,7 @@ export const spiesOnGetter = { strictEqual(getter.mock.restore(), undefined); strictEqual(obj.method, 5); - } + }, }; export const spiesOnSetter = { @@ -585,12 +585,12 @@ export const spiesOnSetter = { strictEqual(obj.prop, 77); obj.method = 65; strictEqual(obj.prop, 65); - } + }, }; export const spyFunctionsCanBeBound = { test() { - const sum = mock.fn(function(arg1, arg2) { + const sum = mock.fn(function (arg1, arg2) { return this + arg1 + arg2; }); const bound = sum.bind(1000); @@ -606,7 +606,7 @@ export const spyFunctionsCanBeBound = { strictEqual(sum.mock.restore(), undefined); strictEqual(sum.bind(0)(2, 11), 13); - } + }, }; export const mocksPrototypeMethodsOnAnInstance = { @@ -639,16 +639,13 @@ export const mocksPrototypeMethodsOnAnInstance = { const obj2 = new Runner(); // Ensure that a brand new instance is not mocked - strictEqual( - obj2.someTask.mock, - undefined - ); + strictEqual(obj2.someTask.mock, undefined); strictEqual(obj.someTask.mock.restore(), undefined); strictEqual(await obj.method(msg), msg); strictEqual(obj.someTask.mock, undefined); strictEqual(Runner.prototype.someTask.mock, undefined); - } + }, }; export const spiesOnAsyncStaticClassMethods = { @@ -682,22 +679,21 @@ export const spiesOnAsyncStaticClassMethods = { strictEqual(await Runner.method(msg), msg); strictEqual(Runner.someTask.mock, undefined); strictEqual(Runner.prototype.someTask, undefined); - - } + }, }; export const givenNullToAMockMethodItThrowsAInvalidArgumentError = { test() { throws(() => mock.method(null, {}), { code: 'ERR_INVALID_ARG_TYPE' }); - } -} + }, +}; export const itShouldThrowGivenAnInexistentPropertyOnAObjectInstance = { test() { throws(() => mock.method({ abc: 0 }, 'non-existent'), { - code: 'ERR_INVALID_ARG_VALUE' + code: 'ERR_INVALID_ARG_VALUE', }); - } + }, }; export const spyFunctionsCanBeUsedOnClassesInheritance = { @@ -732,7 +728,7 @@ export const spyFunctionsCanBeUsedOnClassesInheritance = { strictEqual(C.someTask.mock.restore(), undefined); strictEqual(C.method(msg), msg); strictEqual(C.someTask.mock, undefined); - } + }, }; export const spyFunctionsDontAffectThePrototypeChain = { @@ -747,16 +743,34 @@ export const spyFunctionsDontAffectThePrototypeChain = { const msg = 'ok'; - const ABeforeMockIsUnchanged = Object.getOwnPropertyDescriptor(A, A.someTask.name); - const BBeforeMockIsUnchanged = Object.getOwnPropertyDescriptor(B, B.someTask.name); - const CBeforeMockShouldNotHaveDesc = Object.getOwnPropertyDescriptor(C, C.someTask.name); + const ABeforeMockIsUnchanged = Object.getOwnPropertyDescriptor( + A, + A.someTask.name + ); + const BBeforeMockIsUnchanged = Object.getOwnPropertyDescriptor( + B, + B.someTask.name + ); + const CBeforeMockShouldNotHaveDesc = Object.getOwnPropertyDescriptor( + C, + C.someTask.name + ); mock.method(C, C.someTask.name); C.someTask(msg); - const BAfterMockIsUnchanged = Object.getOwnPropertyDescriptor(B, B.someTask.name); + const BAfterMockIsUnchanged = Object.getOwnPropertyDescriptor( + B, + B.someTask.name + ); - const AAfterMockIsUnchanged = Object.getOwnPropertyDescriptor(A, A.someTask.name); - const CAfterMockHasDescriptor = Object.getOwnPropertyDescriptor(C, C.someTask.name); + const AAfterMockIsUnchanged = Object.getOwnPropertyDescriptor( + A, + A.someTask.name + ); + const CAfterMockHasDescriptor = Object.getOwnPropertyDescriptor( + C, + C.someTask.name + ); strictEqual(CBeforeMockShouldNotHaveDesc, undefined); ok(CAfterMockHasDescriptor); @@ -766,9 +780,12 @@ export const spyFunctionsDontAffectThePrototypeChain = { strictEqual(BBeforeMockIsUnchanged, undefined); strictEqual(C.someTask.mock.restore(), undefined); - const CAfterRestoreKeepsDescriptor = Object.getOwnPropertyDescriptor(C, C.someTask.name); + const CAfterRestoreKeepsDescriptor = Object.getOwnPropertyDescriptor( + C, + C.someTask.name + ); ok(CAfterRestoreKeepsDescriptor); - } + }, }; export const mockedFunctionsReportThrownErrors = { @@ -788,7 +805,7 @@ export const mockedFunctionsReportThrownErrors = { strictEqual(call.result, undefined); strictEqual(call.target, undefined); strictEqual(call.this, undefined); - } + }, }; export const mockedConstructorsReportThrownErrors = { @@ -814,7 +831,7 @@ export const mockedConstructorsReportThrownErrors = { strictEqual(call.result, undefined); strictEqual(call.target, Clazz); strictEqual(call.this, undefined); - } + }, }; export const mocksAFunction = { @@ -842,7 +859,7 @@ export const mocksAFunction = { strictEqual(fn.mock.restore(), undefined); strictEqual(fn(2, 11), 13); - } + }, }; export const mocksAConstructor = { @@ -895,7 +912,7 @@ export const mocksAConstructor = { throws(() => { instance.getPrivateValue(); }, /TypeError: Cannot read private member #privateValue /); - } + }, }; export const mocksAnObjectMethod = { @@ -926,7 +943,7 @@ export const mocksAnObjectMethod = { strictEqual(obj.method.mock.restore(), undefined); strictEqual(obj.method(1, 3), 9); strictEqual(obj.method.mock, undefined); - } + }, }; export const mocksAGetter = { @@ -958,7 +975,7 @@ export const mocksAGetter = { strictEqual(getter.mock.restore(), undefined); strictEqual(obj.method, 5); - } + }, }; export const mocksASetter = { @@ -997,7 +1014,7 @@ export const mocksASetter = { strictEqual(obj.prop, -77); obj.method = 65; strictEqual(obj.prop, 65); - } + }, }; export const mocksAGetterWithSyntaxSugar = { @@ -1025,7 +1042,7 @@ export const mocksAGetterWithSyntaxSugar = { strictEqual(getter.mock.restore(), undefined); strictEqual(obj.method, 5); - } + }, }; export const mocksASetterWithSyntaxSugar = { @@ -1064,7 +1081,7 @@ export const mocksASetterWithSyntaxSugar = { strictEqual(obj.prop, -77); obj.method = 65; strictEqual(obj.prop, 65); - } + }, }; export const mockedFunctionsMatchNameAndLength = { @@ -1077,27 +1094,18 @@ export const mockedFunctionsMatchNameAndLength = { } function func1() {} - const func2 = function(a) {}; // eslint-disable-line func-style + const func2 = function (a) {}; // eslint-disable-line func-style const arrow = (a, b, c) => {}; const obj = { method(a, b) {} }; - deepStrictEqual( - getNameAndLength(func1), - getNameAndLength(mock.fn(func1)) - ); - deepStrictEqual( - getNameAndLength(func2), - getNameAndLength(mock.fn(func2)) - ); - deepStrictEqual( - getNameAndLength(arrow), - getNameAndLength(mock.fn(arrow)) - ); + deepStrictEqual(getNameAndLength(func1), getNameAndLength(mock.fn(func1))); + deepStrictEqual(getNameAndLength(func2), getNameAndLength(mock.fn(func2))); + deepStrictEqual(getNameAndLength(arrow), getNameAndLength(mock.fn(arrow))); deepStrictEqual( getNameAndLength(obj.method), getNameAndLength(mock.method(obj, 'method', func1)) ); - } + }, }; export const methodFailsIfMethodCannotBeRedefined = { @@ -1110,7 +1118,7 @@ export const methodFailsIfMethodCannotBeRedefined = { configurable: false, value(a, b) { return a + b + this.prop; - } + }, }); function mockMethod(a) { @@ -1122,7 +1130,7 @@ export const methodFailsIfMethodCannotBeRedefined = { }, /Cannot redefine property: method/); strictEqual(obj.method(1, 3), 9); strictEqual(obj.method.mock, undefined); - } + }, }; export const methodFailsIfFieldIsAPropertyInsteadOfAMethod = { @@ -1141,7 +1149,7 @@ export const methodFailsIfFieldIsAPropertyInsteadOfAMethod = { }, /The argument 'methodName' must be a method/); strictEqual(obj.method, 100); strictEqual(obj.method.mock, undefined); - } + }, }; export const mocksCanBeRestored = { @@ -1164,7 +1172,7 @@ export const mocksCanBeRestored = { strictEqual(fn(), 4); strictEqual(fn(), 5); strictEqual(fn(), 6); - } + }, }; export const mockImplementationCanBeChangedDynamically = { @@ -1187,9 +1195,9 @@ export const mockImplementationCanBeChangedDynamically = { } function mustNotCall() { - return function() { + return function () { throw new Error('This function should not be called'); - } + }; } const fn = mock.fn(addOne); @@ -1224,7 +1232,7 @@ export const mockImplementationCanBeChangedDynamically = { strictEqual(fn(), 18); strictEqual(fn(), 19); strictEqual(fn.mock.callCount(), 12); - } + }, }; export const resetMockCalls = { @@ -1243,7 +1251,7 @@ export const resetMockCalls = { strictEqual(fn.mock.callCount(), 0); strictEqual(fn(3, 2), 1); - } + }, }; export const usesTopLevelMock = { @@ -1264,7 +1272,7 @@ export const usesTopLevelMock = { mock.reset(); strictEqual(fn(3, 4), 7); strictEqual(fn.mock.calls.length, 2); - } + }, }; export const theGetterAndSetterOptionsCannotBeUsedTogether = { @@ -1272,7 +1280,7 @@ export const theGetterAndSetterOptionsCannotBeUsedTogether = { throws(() => { mock.method({}, 'method', { getter: true, setter: true }); }, /The property 'options\.setter' cannot be used with 'options\.getter'/); - } + }, }; export const methodNamesMustBeStringsOrSymbols = { @@ -1289,7 +1297,7 @@ export const methodNamesMustBeStringsOrSymbols = { throws(() => { mock.method(obj, {}); }, /The "methodName" argument must be one of type string or symbol/); - } + }, }; export const theTimesOptionMustBeAnIntegerGreaterOrEqualToOne = { @@ -1305,7 +1313,7 @@ export const theTimesOptionMustBeAnIntegerGreaterOrEqualToOne = { throws(() => { mock.fn(() => {}, { times: 3.14159 }); }, /The value of "options\.times" is out of range/); - } + }, }; export const spiesOnAClassPrototypeMethod = { @@ -1336,7 +1344,7 @@ export const spiesOnAClassPrototypeMethod = { strictEqual(call.error, undefined); strictEqual(call.target, undefined); strictEqual(call.this, instance); - } + }, }; export const getterFailsIfGetterOptionsSetToFalse = { @@ -1344,7 +1352,7 @@ export const getterFailsIfGetterOptionsSetToFalse = { throws(() => { mock.getter({}, 'method', { getter: false }); }, /The property 'options\.getter' cannot be false/); - } + }, }; export const setterFailsIfSetterOptionsSetToFalse = { @@ -1352,7 +1360,7 @@ export const setterFailsIfSetterOptionsSetToFalse = { throws(() => { mock.setter({}, 'method', { setter: false }); }, /The property 'options\.setter' cannot be false/); - } + }, }; export const getterFailsIfSetterOptionsIsTrue = { @@ -1360,7 +1368,7 @@ export const getterFailsIfSetterOptionsIsTrue = { throws(() => { mock.getter({}, 'method', { setter: true }); }, /The property 'options\.setter' cannot be used with 'options\.getter'/); - } + }, }; export const setterFailsIfGetterOptionsIsTrue = { @@ -1368,5 +1376,5 @@ export const setterFailsIfGetterOptionsIsTrue = { throws(() => { mock.setter({}, 'method', { getter: true }); }, /The property 'options\.setter' cannot be used with 'options\.getter'/); - } + }, }; diff --git a/src/workerd/api/node/tests/buffer-nodejs-test.js b/src/workerd/api/node/tests/buffer-nodejs-test.js index f46c143476a..68faa383ae9 100644 --- a/src/workerd/api/node/tests/buffer-nodejs-test.js +++ b/src/workerd/api/node/tests/buffer-nodejs-test.js @@ -46,11 +46,13 @@ import { } from 'node:buffer'; import * as buffer from 'node:buffer'; -if (buffer.Buffer !== Buffer || - buffer.SlowBuffer !== SlowBuffer || - buffer.kMaxLength !== kMaxLength || - buffer.kStringMaxLength !== kStringMaxLength || - buffer.constants !== constants) { +if ( + buffer.Buffer !== Buffer || + buffer.SlowBuffer !== SlowBuffer || + buffer.kMaxLength !== kMaxLength || + buffer.kStringMaxLength !== kStringMaxLength || + buffer.constants !== constants +) { throw new Error('Incorrect default exports'); } @@ -78,8 +80,8 @@ export const simpleAlloc = { const d = Buffer.from([]); strictEqual(d.length, 0); - } -} + }, +}; export const offsetProperties = { test(ctrl, env, ctx) { @@ -87,7 +89,7 @@ export const offsetProperties = { strictEqual(b.length, 128); strictEqual(b.byteOffset, 0); strictEqual(b.offset, 0); - } + }, }; export const bufferFromUint8Array = { @@ -107,7 +109,7 @@ export const bufferFromUint8Array = { strictEqual(value, ui8[key]); } } - } + }, }; export const bufferFromUint32Array = { @@ -126,7 +128,7 @@ export const bufferFromUint32Array = { strictEqual(value, ui32[key]); } } - } + }, }; export const invalidEncodingForToString = { @@ -135,11 +137,14 @@ export const invalidEncodingForToString = { // Test invalid encoding for Buffer.toString throws(() => b.toString('invalid'), /Unknown encoding: invalid/); // // Invalid encoding for Buffer.write - throws(() => b.write('test string', 0, 5, 'invalid'), /Unknown encoding: invalid/); + throws( + () => b.write('test string', 0, 5, 'invalid'), + /Unknown encoding: invalid/ + ); // Unsupported arguments for Buffer.write throws(() => b.write('test', 'utf8', 0), { code: 'ERR_INVALID_ARG_TYPE' }); - } + }, }; export const zeroLengthBuffers = { @@ -154,14 +159,14 @@ export const zeroLengthBuffers = { new Buffer('', 'latin1'); new Buffer('', 'binary'); Buffer(0); - } + }, }; export const outOfBoundsWrites = { test(ctrl, env, ctx) { const outOfRangeError = { code: 'ERR_OUT_OF_RANGE', - name: 'RangeError' + name: 'RangeError', }; const b = Buffer.alloc(1024); @@ -189,23 +194,22 @@ export const outOfBoundsWrites = { b.copy(Buffer.alloc(1), 0, 2048, 2048); Buffer.alloc(1).write('', 1, 0); - } + }, }; export const smartDefaults = { test(ctrl, env, ctx) { - const writeTest = Buffer.from('abcdes'); - writeTest.write('n', 'ascii'); - throws( - () => writeTest.write('o', '1', 'ascii'), - { code: 'ERR_INVALID_ARG_TYPE' } - ); - writeTest.write('o', 1, 'ascii'); - writeTest.write('d', 2, 'ascii'); - writeTest.write('e', 3, 'ascii'); - writeTest.write('j', 4, 'ascii'); - strictEqual(writeTest.toString(), 'nodejs'); - } + const writeTest = Buffer.from('abcdes'); + writeTest.write('n', 'ascii'); + throws(() => writeTest.write('o', '1', 'ascii'), { + code: 'ERR_INVALID_ARG_TYPE', + }); + writeTest.write('o', 1, 'ascii'); + writeTest.write('d', 2, 'ascii'); + writeTest.write('e', 3, 'ascii'); + writeTest.write('j', 4, 'ascii'); + strictEqual(writeTest.toString(), 'nodejs'); + }, }; export const asciiSlice = { @@ -227,7 +231,11 @@ export const asciiSlice = { const offset = 100; strictEqual(asciiString.length, b.write(asciiString, offset, 'ascii')); - const asciiSlice = b.toString('ascii', offset, offset + asciiString.length); + const asciiSlice = b.toString( + 'ascii', + offset, + offset + asciiString.length + ); strictEqual(asciiString, asciiSlice); } @@ -241,7 +249,7 @@ export const asciiSlice = { strictEqual(sliceA[i], sliceB[i]); } } - } + }, }; export const utf8Slice = { @@ -255,8 +263,15 @@ export const utf8Slice = { let utf8Slice = b.toString('utf8', 0, Buffer.byteLength(utf8String)); strictEqual(utf8String, utf8Slice); - strictEqual(Buffer.byteLength(utf8String), b.write(utf8String, offset, 'utf8')); - utf8Slice = b.toString('utf8', offset, offset + Buffer.byteLength(utf8String)); + strictEqual( + Buffer.byteLength(utf8String), + b.write(utf8String, offset, 'utf8') + ); + utf8Slice = b.toString( + 'utf8', + offset, + offset + Buffer.byteLength(utf8String) + ); strictEqual(utf8String, utf8Slice); const sliceA = b.slice(offset, offset + Buffer.byteLength(utf8String)); @@ -313,7 +328,7 @@ export const utf8Slice = { strictEqual(c[0], 6); strictEqual(c[1], 7); } - } + }, }; export const bufferFrom = { @@ -347,7 +362,8 @@ export const bufferFrom = { // Length should be 12 const f = Buffer.from('привет', encoding); deepStrictEqual( - f, Buffer.from([63, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66, 4]) + f, + Buffer.from([63, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66, 4]) ); strictEqual(f.toString(encoding), 'привет'); } @@ -406,8 +422,16 @@ export const bufferFrom = { [ {}, new Boolean(true), - { valueOf() { return null; } }, - { valueOf() { return undefined; } }, + { + valueOf() { + return null; + }, + }, + { + valueOf() { + return undefined; + }, + }, { valueOf: null }, { __proto__: null }, new Number(true), @@ -427,52 +451,79 @@ export const bufferFrom = { Buffer.allocUnsafe(10); // Should not throw. Buffer.from('deadbeaf', 'hex'); // Should not throw. - } - } + }, }; export const base64 = { test(ctrl, env, ctx) { const base64flavors = ['base64', 'base64url']; { - strictEqual((Buffer.from('Man')).toString('base64'), 'TWFu'); - strictEqual((Buffer.from('Woman')).toString('base64'), 'V29tYW4='); - strictEqual((Buffer.from('Man')).toString('base64url'), 'TWFu'); - strictEqual((Buffer.from('Woman')).toString('base64url'), 'V29tYW4'); + strictEqual(Buffer.from('Man').toString('base64'), 'TWFu'); + strictEqual(Buffer.from('Woman').toString('base64'), 'V29tYW4='); + strictEqual(Buffer.from('Man').toString('base64url'), 'TWFu'); + strictEqual(Buffer.from('Woman').toString('base64url'), 'V29tYW4'); } { const expected = [0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff]; - deepStrictEqual(Buffer.from('//++/++/++//', 'base64'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('__--_--_--__', 'base64'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('//++/++/++//', 'base64url'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('__--_--_--__', 'base64url'), Buffer.from(expected)); + deepStrictEqual( + Buffer.from('//++/++/++//', 'base64'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('__--_--_--__', 'base64'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('//++/++/++//', 'base64url'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('__--_--_--__', 'base64url'), + Buffer.from(expected) + ); } { // Test that regular and URL-safe base64 both work both ways with padding - const expected = [0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0xfb]; - deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64url'), Buffer.from(expected)); - deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64url'), Buffer.from(expected)); + const expected = [ + 0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0xfb, + ]; + deepStrictEqual( + Buffer.from('//++/++/++//+w==', 'base64'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('//++/++/++//+w==', 'base64'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('//++/++/++//+w==', 'base64url'), + Buffer.from(expected) + ); + deepStrictEqual( + Buffer.from('//++/++/++//+w==', 'base64url'), + Buffer.from(expected) + ); } { // big example - const quote = 'Man is distinguished, not only by his reason, but by this ' + - 'singular passion from other animals, which is a lust ' + - 'of the mind, that by a perseverance of delight in the ' + - 'continued and indefatigable generation of knowledge, ' + - 'exceeds the short vehemence of any carnal pleasure.'; - const expected = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' + - '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci' + - 'BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQ' + - 'gYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu' + - 'dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ' + - 'GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm' + - '5hbCBwbGVhc3VyZS4='; + const quote = + 'Man is distinguished, not only by his reason, but by this ' + + 'singular passion from other animals, which is a lust ' + + 'of the mind, that by a perseverance of delight in the ' + + 'continued and indefatigable generation of knowledge, ' + + 'exceeds the short vehemence of any carnal pleasure.'; + const expected = + 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' + + '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci' + + 'BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQ' + + 'gYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu' + + 'dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ' + + 'GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm' + + '5hbCBwbGVhc3VyZS4='; strictEqual(Buffer.from(quote).toString('base64'), expected); strictEqual( Buffer.from(quote).toString('base64url'), @@ -486,12 +537,13 @@ export const base64 = { strictEqual(quote, b.toString('ascii', 0, quote.length)); // Check that the base64 decoder ignores whitespace - const expectedWhite = `${expected.slice(0, 60)} \n` + - `${expected.slice(60, 120)} \n` + - `${expected.slice(120, 180)} \n` + - `${expected.slice(180, 240)} \n` + - `${expected.slice(240, 300)}\n` + - `${expected.slice(300, 360)}\n`; + const expectedWhite = + `${expected.slice(0, 60)} \n` + + `${expected.slice(60, 120)} \n` + + `${expected.slice(120, 180)} \n` + + `${expected.slice(180, 240)} \n` + + `${expected.slice(240, 300)}\n` + + `${expected.slice(300, 360)}\n`; b = Buffer.allocUnsafe(1024); bytesWritten = b.write(expectedWhite, 0, encoding); strictEqual(quote.length, bytesWritten); @@ -504,12 +556,18 @@ export const base64 = { strictEqual(quote, b.toString('ascii', 0, quote.length)); // Check that the base64 decoder ignores illegal chars - const expectedIllegal = expected.slice(0, 60) + ' \x80' + - expected.slice(60, 120) + ' \xff' + - expected.slice(120, 180) + ' \x00' + - expected.slice(180, 240) + ' \x98' + - expected.slice(240, 300) + '\x03' + - expected.slice(300, 360); + const expectedIllegal = + expected.slice(0, 60) + + ' \x80' + + expected.slice(60, 120) + + ' \xff' + + expected.slice(120, 180) + + ' \x00' + + expected.slice(180, 240) + + ' \x98' + + expected.slice(240, 300) + + '\x03' + + expected.slice(300, 360); b = Buffer.from(expectedIllegal, encoding); strictEqual(quote.length, b.length); strictEqual(quote, b.toString('ascii', 0, quote.length)); @@ -527,51 +585,171 @@ export const base64 = { strictEqual(Buffer.from('KioqKg==', encoding).toString(), '*'.repeat(4)); strictEqual(Buffer.from('KioqKio=', encoding).toString(), '*'.repeat(5)); strictEqual(Buffer.from('KioqKioq', encoding).toString(), '*'.repeat(6)); - strictEqual(Buffer.from('KioqKioqKg==', encoding).toString(), '*'.repeat(7)); - strictEqual(Buffer.from('KioqKioqKio=', encoding).toString(), '*'.repeat(8)); - strictEqual(Buffer.from('KioqKioqKioq', encoding).toString(), '*'.repeat(9)); - strictEqual(Buffer.from('KioqKioqKioqKg==', encoding).toString(), '*'.repeat(10)); - strictEqual(Buffer.from('KioqKioqKioqKio=', encoding).toString(), '*'.repeat(11)); - strictEqual(Buffer.from('KioqKioqKioqKioq', encoding).toString(), '*'.repeat(12)); - strictEqual(Buffer.from('KioqKioqKioqKioqKg==', encoding).toString(), '*'.repeat(13)); - strictEqual(Buffer.from('KioqKioqKioqKioqKio=', encoding).toString(), '*'.repeat(14)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioq', encoding).toString(), '*'.repeat(15)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKg==', encoding).toString(), '*'.repeat(16)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKio=', encoding).toString(), '*'.repeat(17)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioq', encoding).toString(),'*'.repeat(18)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKg==', encoding).toString(), '*'.repeat(19)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKio=', encoding).toString(), '*'.repeat(20)); + strictEqual( + Buffer.from('KioqKioqKg==', encoding).toString(), + '*'.repeat(7) + ); + strictEqual( + Buffer.from('KioqKioqKio=', encoding).toString(), + '*'.repeat(8) + ); + strictEqual( + Buffer.from('KioqKioqKioq', encoding).toString(), + '*'.repeat(9) + ); + strictEqual( + Buffer.from('KioqKioqKioqKg==', encoding).toString(), + '*'.repeat(10) + ); + strictEqual( + Buffer.from('KioqKioqKioqKio=', encoding).toString(), + '*'.repeat(11) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioq', encoding).toString(), + '*'.repeat(12) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKg==', encoding).toString(), + '*'.repeat(13) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKio=', encoding).toString(), + '*'.repeat(14) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioq', encoding).toString(), + '*'.repeat(15) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKg==', encoding).toString(), + '*'.repeat(16) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKio=', encoding).toString(), + '*'.repeat(17) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKioq', encoding).toString(), + '*'.repeat(18) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKioqKg==', encoding).toString(), + '*'.repeat(19) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKioqKio=', encoding).toString(), + '*'.repeat(20) + ); // No padding, not a multiple of 4 strictEqual(Buffer.from('Kg', encoding).toString(), '*'); strictEqual(Buffer.from('Kio', encoding).toString(), '*'.repeat(2)); strictEqual(Buffer.from('KioqKg', encoding).toString(), '*'.repeat(4)); strictEqual(Buffer.from('KioqKio', encoding).toString(), '*'.repeat(5)); - strictEqual(Buffer.from('KioqKioqKg', encoding).toString(), '*'.repeat(7)); - strictEqual(Buffer.from('KioqKioqKio', encoding).toString(), '*'.repeat(8)); - strictEqual(Buffer.from('KioqKioqKioqKg', encoding).toString(), '*'.repeat(10)); - strictEqual(Buffer.from('KioqKioqKioqKio', encoding).toString(), '*'.repeat(11)); - strictEqual(Buffer.from('KioqKioqKioqKioqKg', encoding).toString(), '*'.repeat(13)); - strictEqual(Buffer.from('KioqKioqKioqKioqKio', encoding).toString(), '*'.repeat(14)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKg', encoding).toString(), '*'.repeat(16)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKio', encoding).toString(), '*'.repeat(17)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKg', encoding).toString(), '*'.repeat(19)); - strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKio', encoding).toString(), '*'.repeat(20)); + strictEqual( + Buffer.from('KioqKioqKg', encoding).toString(), + '*'.repeat(7) + ); + strictEqual( + Buffer.from('KioqKioqKio', encoding).toString(), + '*'.repeat(8) + ); + strictEqual( + Buffer.from('KioqKioqKioqKg', encoding).toString(), + '*'.repeat(10) + ); + strictEqual( + Buffer.from('KioqKioqKioqKio', encoding).toString(), + '*'.repeat(11) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKg', encoding).toString(), + '*'.repeat(13) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKio', encoding).toString(), + '*'.repeat(14) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKg', encoding).toString(), + '*'.repeat(16) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKio', encoding).toString(), + '*'.repeat(17) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKioqKg', encoding).toString(), + '*'.repeat(19) + ); + strictEqual( + Buffer.from('KioqKioqKioqKioqKioqKioqKio', encoding).toString(), + '*'.repeat(20) + ); }); // Handle padding graciously, multiple-of-4 or not - strictEqual(Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw==', 'base64').length, 32); - strictEqual(Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw==', 'base64url').length, 32); - strictEqual(Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw=', 'base64').length, 32); - strictEqual(Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw=', 'base64url').length, 32); - strictEqual(Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw', 'base64').length, 32); - strictEqual(Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw', 'base64url').length, 32); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64').length, 31); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64url').length, 31); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64').length, 31); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64url').length, 31); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64').length, 31); - strictEqual(Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64url').length, 31); + strictEqual( + Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw==', 'base64') + .length, + 32 + ); + strictEqual( + Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw==', 'base64url') + .length, + 32 + ); + strictEqual( + Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw=', 'base64') + .length, + 32 + ); + strictEqual( + Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw=', 'base64url') + .length, + 32 + ); + strictEqual( + Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw', 'base64') + .length, + 32 + ); + strictEqual( + Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw', 'base64url') + .length, + 32 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64') + .length, + 31 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64url') + .length, + 31 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64') + .length, + 31 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64url') + .length, + 31 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64') + .length, + 31 + ); + strictEqual( + Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64url') + .length, + 31 + ); { // This string encodes single '.' character in UTF-16 @@ -628,9 +806,11 @@ export const base64 = { deepStrictEqual(Buffer.from('w0 ', 'base64'), Buffer.from('w0', 'base64')); // // Regression test for https://github.com/nodejs/node/issues/13657. - deepStrictEqual(Buffer.from(' YWJvcnVtLg', 'base64'), Buffer.from('YWJvcnVtLg', 'base64')); - } - + deepStrictEqual( + Buffer.from(' YWJvcnVtLg', 'base64'), + Buffer.from('YWJvcnVtLg', 'base64') + ); + }, }; export const hex = { @@ -642,23 +822,25 @@ export const hex = { hexb[i] = i; } const hexStr = hexb.toString('hex'); - strictEqual(hexStr, - '000102030405060708090a0b0c0d0e0f' + - '101112131415161718191a1b1c1d1e1f' + - '202122232425262728292a2b2c2d2e2f' + - '303132333435363738393a3b3c3d3e3f' + - '404142434445464748494a4b4c4d4e4f' + - '505152535455565758595a5b5c5d5e5f' + - '606162636465666768696a6b6c6d6e6f' + - '707172737475767778797a7b7c7d7e7f' + - '808182838485868788898a8b8c8d8e8f' + - '909192939495969798999a9b9c9d9e9f' + - 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf' + - 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' + - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' + - 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' + - 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' + - 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); + strictEqual( + hexStr, + '000102030405060708090a0b0c0d0e0f' + + '101112131415161718191a1b1c1d1e1f' + + '202122232425262728292a2b2c2d2e2f' + + '303132333435363738393a3b3c3d3e3f' + + '404142434445464748494a4b4c4d4e4f' + + '505152535455565758595a5b5c5d5e5f' + + '606162636465666768696a6b6c6d6e6f' + + '707172737475767778797a7b7c7d7e7f' + + '808182838485868788898a8b8c8d8e8f' + + '909192939495969798999a9b9c9d9e9f' + + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf' + + 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' + + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' + + 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' + + 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' + + 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' + ); const hexb2 = Buffer.from(hexStr, 'hex'); for (let i = 0; i < 256; i++) { @@ -684,7 +866,7 @@ export const hex = { strictEqual(b2, b3); strictEqual(b2, b4); } - } + }, }; export const slicing = { @@ -692,13 +874,15 @@ export const slicing = { function buildBuffer(data) { if (Array.isArray(data)) { const buffer = Buffer.allocUnsafe(data.length); - data.forEach((v, k) => buffer[k] = v); + data.forEach((v, k) => (buffer[k] = v)); return buffer; } return null; } - const x = buildBuffer([0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72]); + const x = buildBuffer([ + 0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72, + ]); { const z = x.slice(4); @@ -739,7 +923,7 @@ export const slicing = { strictEqual(z[0], 0x66); strictEqual(z[1], 0x6f); } - } + }, }; export const writing = { @@ -810,41 +994,41 @@ export const writing = { // https://github.com/nodejs/node-v0.x-archive/issues/243 // Test write() with maxLength const buf = Buffer.allocUnsafe(4); - buf.fill(0xFF); + buf.fill(0xff); strictEqual(buf.write('abcd', 1, 2, 'utf8'), 2); - strictEqual(buf[0], 0xFF); + strictEqual(buf[0], 0xff); strictEqual(buf[1], 0x61); strictEqual(buf[2], 0x62); - strictEqual(buf[3], 0xFF); + strictEqual(buf[3], 0xff); - buf.fill(0xFF); + buf.fill(0xff); strictEqual(buf.write('abcd', 1, 4), 3); - strictEqual(buf[0], 0xFF); + strictEqual(buf[0], 0xff); strictEqual(buf[1], 0x61); strictEqual(buf[2], 0x62); strictEqual(buf[3], 0x63); - buf.fill(0xFF); + buf.fill(0xff); strictEqual(buf.write('abcd', 1, 2, 'utf8'), 2); - strictEqual(buf[0], 0xFF); + strictEqual(buf[0], 0xff); strictEqual(buf[1], 0x61); strictEqual(buf[2], 0x62); - strictEqual(buf[3], 0xFF); + strictEqual(buf[3], 0xff); - buf.fill(0xFF); + buf.fill(0xff); strictEqual(buf.write('abcdef', 1, 2, 'hex'), 2); - strictEqual(buf[0], 0xFF); - strictEqual(buf[1], 0xAB); - strictEqual(buf[2], 0xCD); - strictEqual(buf[3], 0xFF); + strictEqual(buf[0], 0xff); + strictEqual(buf[1], 0xab); + strictEqual(buf[2], 0xcd); + strictEqual(buf[3], 0xff); ['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach((encoding) => { - buf.fill(0xFF); + buf.fill(0xff); strictEqual(buf.write('abcd', 0, 2, encoding), 2); strictEqual(buf[0], 0x61); strictEqual(buf[1], 0x00); - strictEqual(buf[2], 0xFF); - strictEqual(buf[3], 0xFF); + strictEqual(buf[2], 0xff); + strictEqual(buf[3], 0xff); }); } @@ -861,7 +1045,7 @@ export const writing = { { // Test for buffer overrun const buf = Buffer.from([0, 0, 0, 0, 0]); // length: 5 - const sub = buf.slice(0, 4); // length: 4 + const sub = buf.slice(0, 4); // length: 4 strictEqual(sub.write('12345', 'latin1'), 4); strictEqual(buf[4], 0); strictEqual(sub.write('12345', 'binary'), 4); @@ -875,47 +1059,47 @@ export const writing = { deepStrictEqual(buf.toJSON().data, [0x56, 0x34, 0x12]); strictEqual(buf.readUIntLE(0, 3), 0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeUIntBE(0x123456, 0, 3); deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56]); strictEqual(buf.readUIntBE(0, 3), 0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(0x123456, 0, 3); deepStrictEqual(buf.toJSON().data, [0x56, 0x34, 0x12]); strictEqual(buf.readIntLE(0, 3), 0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(0x123456, 0, 3); deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56]); strictEqual(buf.readIntBE(0, 3), 0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(-0x123456, 0, 3); deepStrictEqual(buf.toJSON().data, [0xaa, 0xcb, 0xed]); strictEqual(buf.readIntLE(0, 3), -0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(-0x123456, 0, 3); deepStrictEqual(buf.toJSON().data, [0xed, 0xcb, 0xaa]); strictEqual(buf.readIntBE(0, 3), -0x123456); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(-0x123400, 0, 3); deepStrictEqual(buf.toJSON().data, [0x00, 0xcc, 0xed]); strictEqual(buf.readIntLE(0, 3), -0x123400); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(-0x123400, 0, 3); deepStrictEqual(buf.toJSON().data, [0xed, 0xcc, 0x00]); strictEqual(buf.readIntBE(0, 3), -0x123400); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(-0x120000, 0, 3); deepStrictEqual(buf.toJSON().data, [0x00, 0x00, 0xee]); strictEqual(buf.readIntLE(0, 3), -0x120000); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(-0x120000, 0, 3); deepStrictEqual(buf.toJSON().data, [0xee, 0x00, 0x00]); strictEqual(buf.readIntBE(0, 3), -0x120000); @@ -925,42 +1109,42 @@ export const writing = { deepStrictEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]); strictEqual(buf.readUIntLE(0, 5), 0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeUIntBE(0x1234567890, 0, 5); deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]); strictEqual(buf.readUIntBE(0, 5), 0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(0x1234567890, 0, 5); deepStrictEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]); strictEqual(buf.readIntLE(0, 5), 0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(0x1234567890, 0, 5); deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]); strictEqual(buf.readIntBE(0, 5), 0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(-0x1234567890, 0, 5); deepStrictEqual(buf.toJSON().data, [0x70, 0x87, 0xa9, 0xcb, 0xed]); strictEqual(buf.readIntLE(0, 5), -0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(-0x1234567890, 0, 5); deepStrictEqual(buf.toJSON().data, [0xed, 0xcb, 0xa9, 0x87, 0x70]); strictEqual(buf.readIntBE(0, 5), -0x1234567890); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntLE(-0x0012000000, 0, 5); deepStrictEqual(buf.toJSON().data, [0x00, 0x00, 0x00, 0xee, 0xff]); strictEqual(buf.readIntLE(0, 5), -0x0012000000); - buf.fill(0xFF); + buf.fill(0xff); buf.writeIntBE(-0x0012000000, 0, 5); deepStrictEqual(buf.toJSON().data, [0xff, 0xee, 0x00, 0x00, 0x00]); strictEqual(buf.readIntBE(0, 5), -0x0012000000); } - } + }, }; export const misc = { @@ -1027,7 +1211,7 @@ export const misc = { const outOfRangeError = { code: 'ERR_OUT_OF_RANGE', - name: 'RangeError' + name: 'RangeError', }; // issue GH-5587 @@ -1035,8 +1219,14 @@ export const misc = { throws(() => Buffer.alloc(16).writeDoubleLE(0, 9), outOfRangeError); // Attempt to overflow buffers, similar to previous bug in array buffers - throws(() => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff), outOfRangeError); - throws(() => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff), outOfRangeError); + throws( + () => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff), + outOfRangeError + ); + throws( + () => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff), + outOfRangeError + ); // Ensure negative values can't get past offset throws(() => Buffer.allocUnsafe(8).writeFloatLE(0.0, -1), outOfRangeError); @@ -1044,14 +1234,11 @@ export const misc = { // Regression test for https://github.com/nodejs/node-v0.x-archive/issues/5482: // should throw but not assert in C++ land. - throws( - () => Buffer.from('', 'buffer'), - { - code: 'ERR_UNKNOWN_ENCODING', - name: 'TypeError', - message: 'Unknown encoding: buffer' - } - ); + throws(() => Buffer.from('', 'buffer'), { + code: 'ERR_UNKNOWN_ENCODING', + name: 'TypeError', + message: 'Unknown encoding: buffer', + }); // Regression test for https://github.com/nodejs/node-v0.x-archive/issues/6111. // Constructing a buffer from another buffer should a) work, and b) not corrupt @@ -1069,14 +1256,13 @@ export const misc = { } } - throws( - () => Buffer.allocUnsafe(10).copy(), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "target" argument must be an instance of Buffer or ' + - 'Uint8Array. Received undefined' - }); + throws(() => Buffer.allocUnsafe(10).copy(), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "target" argument must be an instance of Buffer or ' + + 'Uint8Array. Received undefined', + }); throws(() => Buffer.from(), { name: 'TypeError', @@ -1107,7 +1293,7 @@ export const misc = { throws(() => Buffer.from(new ArrayBuffer(0), -1 >>> 0), { code: 'ERR_BUFFER_OUT_OF_BOUNDS', name: 'RangeError', - message: '"offset" is outside of buffer bounds' + message: '"offset" is outside of buffer bounds', }); } @@ -1129,8 +1315,14 @@ export const misc = { // Regression test to verify that an empty ArrayBuffer does not throw. Buffer.from(new ArrayBuffer()); - throws(() => Buffer.alloc({ valueOf: () => 1 }), /"size" argument must be of type number/); - throws(() => Buffer.alloc({ valueOf: () => -1 }), /"size" argument must be of type number/); + throws( + () => Buffer.alloc({ valueOf: () => 1 }), + /"size" argument must be of type number/ + ); + throws( + () => Buffer.alloc({ valueOf: () => -1 }), + /"size" argument must be of type number/ + ); strictEqual(Buffer.prototype.toLocaleString, Buffer.prototype.toString); { @@ -1138,33 +1330,44 @@ export const misc = { strictEqual(buf.toLocaleString(), buf.toString()); } - throws(() => { - Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex'); - }, { - name: 'TypeError' - }); - - throws(() => { - Buffer.alloc(0x1000, 'c', 'hex'); - }, { - name: 'TypeError' - }); + throws( + () => { + Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex'); + }, + { + name: 'TypeError', + } + ); - throws(() => { - Buffer.alloc(1, Buffer.alloc(0)); - }, { - code: 'ERR_INVALID_ARG_VALUE', - name: 'TypeError' - }); + throws( + () => { + Buffer.alloc(0x1000, 'c', 'hex'); + }, + { + name: 'TypeError', + } + ); - throws(() => { - Buffer.alloc(40, 'x', 20); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' - }); + throws( + () => { + Buffer.alloc(1, Buffer.alloc(0)); + }, + { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + } + ); - } + throws( + () => { + Buffer.alloc(40, 'x', 20); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } + ); + }, }; export const arrayBuffers = { @@ -1181,32 +1384,34 @@ export const arrayBuffers = { strictEqual(buf.buffer, ab); strictEqual(buf.length, ab.byteLength); - buf.fill(0xC); + buf.fill(0xc); for (let i = 0; i < LENGTH; i++) { - strictEqual(ui[i], 0xC); - ui[i] = 0xF; - strictEqual(buf[i], 0xF); + strictEqual(ui[i], 0xc); + ui[i] = 0xf; + strictEqual(buf[i], 0xf); } - buf.writeUInt32LE(0xF00, 0); - buf.writeUInt32BE(0xB47, 4); + buf.writeUInt32LE(0xf00, 0); + buf.writeUInt32BE(0xb47, 4); buf.writeDoubleLE(3.1415, 8); - strictEqual(dv.getUint32(0, true), 0xF00); - strictEqual(dv.getUint32(4), 0xB47); + strictEqual(dv.getUint32(0, true), 0xf00); + strictEqual(dv.getUint32(4), 0xb47); strictEqual(dv.getFloat64(8, true), 3.1415); - // Now test protecting users from doing stupid things - throws(function() { - function AB() { } - Object.setPrototypeOf(AB, ArrayBuffer); - Object.setPrototypeOf(AB.prototype, ArrayBuffer.prototype); - Buffer.from(new AB()); - }, { - name: 'TypeError', - }); + throws( + function () { + function AB() {} + Object.setPrototypeOf(AB, ArrayBuffer); + Object.setPrototypeOf(AB.prototype, ArrayBuffer.prototype); + Buffer.from(new AB()); + }, + { + name: 'TypeError', + } + ); // Test the byteOffset and length arguments { @@ -1227,12 +1432,12 @@ export const arrayBuffers = { throws(() => Buffer.from(ab.buffer, 6), { code: 'ERR_BUFFER_OUT_OF_BOUNDS', name: 'RangeError', - message: '"offset" is outside of buffer bounds' + message: '"offset" is outside of buffer bounds', }); throws(() => Buffer.from(ab.buffer, 3, 6), { code: 'ERR_BUFFER_OUT_OF_BOUNDS', name: 'RangeError', - message: '"length" is outside of buffer bounds' + message: '"length" is outside of buffer bounds', }); } @@ -1255,12 +1460,12 @@ export const arrayBuffers = { throws(() => Buffer(ab.buffer, 6), { code: 'ERR_BUFFER_OUT_OF_BOUNDS', name: 'RangeError', - message: '"offset" is outside of buffer bounds' + message: '"offset" is outside of buffer bounds', }); throws(() => Buffer(ab.buffer, 3, 6), { code: 'ERR_BUFFER_OUT_OF_BOUNDS', name: 'RangeError', - message: '"length" is outside of buffer bounds' + message: '"length" is outside of buffer bounds', }); } @@ -1277,13 +1482,16 @@ export const arrayBuffers = { deepStrictEqual(Buffer.from(ab, [1]), Buffer.from(ab, 1)); // If byteOffset is Infinity, throw. - throws(() => { - Buffer.from(ab, Infinity); - }, { - code: 'ERR_BUFFER_OUT_OF_BOUNDS', - name: 'RangeError', - message: '"offset" is outside of buffer bounds' - }); + throws( + () => { + Buffer.from(ab, Infinity); + }, + { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: '"offset" is outside of buffer bounds', + } + ); } { @@ -1299,18 +1507,21 @@ export const arrayBuffers = { deepStrictEqual(Buffer.from(ab, 0, [1]), Buffer.from(ab, 0, 1)); // If length is Infinity, throw. - throws(() => { - Buffer.from(ab, 0, Infinity); - }, { - code: 'ERR_BUFFER_OUT_OF_BOUNDS', - name: 'RangeError', - message: '"length" is outside of buffer bounds' - }); + throws( + () => { + Buffer.from(ab, 0, Infinity); + }, + { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: '"length" is outside of buffer bounds', + } + ); } // Test an array like entry with the length set to NaN. deepStrictEqual(Buffer.from({ length: NaN }), Buffer.alloc(0)); - } + }, }; export const ascii = { @@ -1319,12 +1530,14 @@ export const ascii = { // it doesn't do transliteration. strictEqual(Buffer.from('hérité').toString('ascii'), 'hC)ritC)'); // 71 characters, 78 bytes. The ’ character is a triple-byte sequence. - const input = 'C’est, graphiquement, la réunion d’un accent aigu ' + - 'et d’un accent grave.'; + const input = + 'C’est, graphiquement, la réunion d’un accent aigu ' + + 'et d’un accent grave.'; - const expected = 'Cb\u0000\u0019est, graphiquement, la rC)union ' + - 'db\u0000\u0019un accent aigu et db\u0000\u0019un ' + - 'accent grave.'; + const expected = + 'Cb\u0000\u0019est, graphiquement, la rC)union ' + + 'db\u0000\u0019un accent aigu et db\u0000\u0019un ' + + 'accent grave.'; const buf = Buffer.from(input); @@ -1335,7 +1548,7 @@ export const ascii = { if (input.charCodeAt(i) > 65535) ++i; if (input.charCodeAt(i) > 127) ++i; } - } + }, }; export const badHex = { @@ -1375,8 +1588,7 @@ export const badHex = { { const buf = Buffer.alloc(256); - for (let i = 0; i < 256; i++) - buf[i] = i; + for (let i = 0; i < 256; i++) buf[i] = i; const hex = buf.toString('hex'); deepStrictEqual(Buffer.from(hex, 'hex'), buf); @@ -1384,14 +1596,14 @@ export const badHex = { const badHex = `${hex.slice(0, 256)}xx${hex.slice(256, 510)}`; deepStrictEqual(Buffer.from(badHex, 'hex'), buf.slice(0, 128)); } - } + }, }; export const bigint64 = { test(ctrl, env, ctx) { const buf = Buffer.allocUnsafe(8); - ['LE', 'BE'].forEach(function(endianness) { + ['LE', 'BE'].forEach(function (endianness) { // Should allow simple BigInts to be written and read let val = 123456789n; buf[`writeBigInt64${endianness}`](val, 0); @@ -1415,49 +1627,45 @@ export const bigint64 = { strictEqual(val, buf[`readBigUInt64${endianness}`](0)); // Should throw a RangeError upon INT64_MAX+1 being written - throws(function() { + throws(function () { const val = 0x8000000000000000n; buf[`writeBigInt64${endianness}`](val, 0); }, RangeError); // Should throw a RangeError upon UINT64_MAX+1 being written - throws(function() { - const val = 0x10000000000000000n; - buf[`writeBigUInt64${endianness}`](val, 0); - }, { - code: 'ERR_OUT_OF_RANGE', - message: 'The value of "value" is out of range. It must be ' + - '>= 0n and < 2n ** 64n. Received 18_446_744_073_709_551_616n' - }); + throws( + function () { + const val = 0x10000000000000000n; + buf[`writeBigUInt64${endianness}`](val, 0); + }, + { + code: 'ERR_OUT_OF_RANGE', + message: + 'The value of "value" is out of range. It must be ' + + '>= 0n and < 2n ** 64n. Received 18_446_744_073_709_551_616n', + } + ); // Should throw a TypeError upon invalid input - throws(function() { + throws(function () { buf[`writeBigInt64${endianness}`]('bad', 0); }, TypeError); // Should throw a TypeError upon invalid input - throws(function() { + throws(function () { buf[`writeBigUInt64${endianness}`]('bad', 0); }, TypeError); }); - } + }, }; export const byteLength = { test(ctrl, env, ctx) { - [ - [32, 'latin1'], - [NaN, 'utf8'], - [{}, 'latin1'], - [], - ].forEach((args) => { - throws( - () => Buffer.byteLength(...args), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + [[32, 'latin1'], [NaN, 'utf8'], [{}, 'latin1'], []].forEach((args) => { + throws(() => Buffer.byteLength(...args), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); }); ok(ArrayBuffer.isView(new Buffer(10))); @@ -1524,13 +1732,19 @@ export const byteLength = { strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ=', 'BASE64'), 11); strictEqual(Buffer.byteLength('bm9kZS5qcyByb2NrcyE=', 'base64'), 14); strictEqual(Buffer.byteLength('aGkk', 'base64'), 3); - strictEqual(Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==', 'base64'), 25); + strictEqual( + Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==', 'base64'), + 25 + ); // base64url strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'base64url'), 11); strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'BASE64URL'), 11); strictEqual(Buffer.byteLength('bm9kZS5qcyByb2NrcyE', 'base64url'), 14); strictEqual(Buffer.byteLength('aGkk', 'base64url'), 3); - strictEqual(Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw', 'base64url'), 25); + strictEqual( + Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw', 'base64url'), + 25 + ); // special padding strictEqual(Buffer.byteLength('aaa=', 'base64'), 2); strictEqual(Buffer.byteLength('aaaa==', 'base64'), 3); @@ -1557,11 +1771,12 @@ export const byteLength = { const encoding = String(i).repeat(i); ok(!Buffer.isEncoding(encoding)); - strictEqual(Buffer.byteLength('foo', encoding), - Buffer.byteLength('foo', 'utf8')); + strictEqual( + Buffer.byteLength('foo', encoding), + Buffer.byteLength('foo', 'utf8') + ); } - - } + }, }; export const compareOffset = { @@ -1581,10 +1796,7 @@ export const compareOffset = { // Zero-length target, return 1 strictEqual(a.compare(b, 0, 0, 0), 1); - throws( - () => a.compare(b, 0, '0', '0'), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => a.compare(b, 0, '0', '0'), { code: 'ERR_INVALID_ARG_TYPE' }); // Equivalent to Buffer.compare(a, b.slice(6, 10)) strictEqual(a.compare(b, 6, 10), 1); @@ -1612,34 +1824,23 @@ export const compareOffset = { strictEqual(a.compare(b, 0, 7, 4, 6), -1); // Null is ambiguous. - throws( - () => a.compare(b, 0, null), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => a.compare(b, 0, null), { code: 'ERR_INVALID_ARG_TYPE' }); // Values do not get coerced. - throws( - () => a.compare(b, 0, { valueOf: () => 5 }), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => a.compare(b, 0, { valueOf: () => 5 }), { + code: 'ERR_INVALID_ARG_TYPE', + }); // Infinity should not be coerced. - throws( - () => a.compare(b, Infinity, -Infinity), - { code: 'ERR_OUT_OF_RANGE' } - ); + throws(() => a.compare(b, Infinity, -Infinity), { + code: 'ERR_OUT_OF_RANGE', + }); // Zero length target because default for targetEnd <= targetSource strictEqual(a.compare(b, 0xff), 1); - throws( - () => a.compare(b, '0xff'), - { code: 'ERR_INVALID_ARG_TYPE' } - ); - throws( - () => a.compare(b, 0, '0xff'), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => a.compare(b, '0xff'), { code: 'ERR_INVALID_ARG_TYPE' }); + throws(() => a.compare(b, 0, '0xff'), { code: 'ERR_INVALID_ARG_TYPE' }); const oor = { code: 'ERR_OUT_OF_RANGE' }; @@ -1652,10 +1853,11 @@ export const compareOffset = { throws(() => a.compare(), { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "target" argument must be an instance of ' + - 'Buffer or Uint8Array. Received undefined' + message: + 'The "target" argument must be an instance of ' + + 'Buffer or Uint8Array. Received undefined', }); - } + }, }; export const compare = { @@ -1663,7 +1865,7 @@ export const compare = { const b = Buffer.alloc(1, 'a'); const c = Buffer.alloc(1, 'c'); const d = Buffer.alloc(2, 'aa'); - const e = new Uint8Array([ 0x61, 0x61 ]); // ASCII 'aa', same as d + const e = new Uint8Array([0x61, 0x61]); // ASCII 'aa', same as d strictEqual(b.compare(c), -1); strictEqual(c.compare(d), 1); @@ -1696,13 +1898,13 @@ export const compare = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', }); - } + }, }; export const concat = { test(ctrl, env, ctx) { const zero = []; - const one = [ Buffer.from('asdf') ]; + const one = [Buffer.from('asdf')]; const long = []; for (let i = 0; i < 10; i++) long.push(Buffer.from('asdf')); @@ -1723,29 +1925,38 @@ export const concat = { strictEqual(flatLongLen.toString(), check); [undefined, null, Buffer.from('hello')].forEach((value) => { - throws(() => { - Buffer.concat(value); - }, { - name: 'TypeError', - }); + throws( + () => { + Buffer.concat(value); + }, + { + name: 'TypeError', + } + ); }); [[42], ['hello', Buffer.from('world')]].forEach((value) => { - throws(() => { - Buffer.concat(value); - }, { - name: 'TypeError', - //code: 'ERR_INVALID_ARG_TYPE', - }); - }); - - throws(() => { - Buffer.concat([Buffer.from('hello'), 3]); - }, { - name: 'TypeError', - //code: 'ERR_INVALID_ARG_TYPE', + throws( + () => { + Buffer.concat(value); + }, + { + name: 'TypeError', + //code: 'ERR_INVALID_ARG_TYPE', + } + ); }); + throws( + () => { + Buffer.concat([Buffer.from('hello'), 3]); + }, + { + name: 'TypeError', + //code: 'ERR_INVALID_ARG_TYPE', + } + ); + // eslint-disable-next-line node-core/crypto-check const random10 = Buffer.alloc(10); crypto.getRandomValues(random10); @@ -1764,11 +1975,19 @@ export const concat = { // The tail should be zero-filled deepStrictEqual(Buffer.concat([empty], 100), Buffer.alloc(100)); deepStrictEqual(Buffer.concat([empty], 4096), Buffer.alloc(4096)); - deepStrictEqual(Buffer.concat([random10], 40), Buffer.concat([random10, Buffer.alloc(30)])); + deepStrictEqual( + Buffer.concat([random10], 40), + Buffer.concat([random10, Buffer.alloc(30)]) + ); - deepStrictEqual(Buffer.concat([new Uint8Array([0x41, 0x42]), new Uint8Array([0x43, 0x44])]), - Buffer.from('ABCD')); - } + deepStrictEqual( + Buffer.concat([ + new Uint8Array([0x41, 0x42]), + new Uint8Array([0x43, 0x44]), + ]), + Buffer.from('ABCD') + ); + }, }; export const konstants = { @@ -1776,12 +1995,15 @@ export const konstants = { strictEqual(typeof MAX_LENGTH, 'number'); strictEqual(typeof MAX_STRING_LENGTH, 'number'); ok(MAX_STRING_LENGTH <= MAX_LENGTH); - throws(() => ' '.repeat(MAX_STRING_LENGTH + 1), /^RangeError: Invalid string length$/); + throws( + () => ' '.repeat(MAX_STRING_LENGTH + 1), + /^RangeError: Invalid string length$/ + ); ' '.repeat(MAX_STRING_LENGTH); // Should not throw. // Legacy values match: strictEqual(kMaxLength, MAX_LENGTH); strictEqual(kStringMaxLength, MAX_STRING_LENGTH); - } + }, }; export const copy = { @@ -1908,40 +2130,32 @@ export const copy = { const bb = Buffer.allocUnsafe(10); bb.fill('hello crazy world'); - // Try to copy from before the beginning of b. Should not throw. b.copy(c, 0, 100, 10); // Throw with invalid source type - throws( - () => Buffer.prototype.copy.call(0), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + throws(() => Buffer.prototype.copy.call(0), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); // Copy throws at negative targetStart - throws( - () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), -1, 0), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "targetStart" is out of range. ' + - 'It must be >= 0. Received -1' - } - ); + throws(() => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), -1, 0), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: + 'The value of "targetStart" is out of range. ' + + 'It must be >= 0. Received -1', + }); // Copy throws at negative sourceStart - throws( - () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "sourceStart" is out of range. ' + - 'It must be >= 0. Received -1' - } - ); + throws(() => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: + 'The value of "sourceStart" is out of range. ' + + 'It must be >= 0. Received -1', + }); { // Check sourceEnd resets to targetEnd if former is greater than the latter @@ -1954,15 +2168,13 @@ export const copy = { } // Throw with negative sourceEnd - throws( - () => b.copy(c, 0, 0, -1), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "sourceEnd" is out of range. ' + - 'It must be >= 0. Received -1' - } - ); + throws(() => b.copy(c, 0, 0, -1), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: + 'The value of "sourceEnd" is out of range. ' + + 'It must be >= 0. Received -1', + }); // When sourceStart is greater than sourceEnd, zero copied strictEqual(b.copy(c, 0, 100, 10), 0); @@ -2005,13 +2217,16 @@ export const copy = { { c.fill('C'); throws(() => { - b.copy(c, { [Symbol.toPrimitive]() { throw new Error('foo'); } }); + b.copy(c, { + [Symbol.toPrimitive]() { + throw new Error('foo'); + }, + }); }, /foo/); // No copying took place: deepStrictEqual(c.toString(), 'C'.repeat(c.length)); } - - } + }, }; export const equals = { @@ -2027,14 +2242,11 @@ export const equals = { ok(d.equals(d)); ok(d.equals(new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]))); - throws( - () => Buffer.alloc(1).equals('abc'), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); - } + throws(() => Buffer.alloc(1).equals('abc'), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); + }, }; export const failedAllocTypedArrays = { @@ -2066,62 +2278,61 @@ export const failedAllocTypedArrays = { } } } - } + }, }; export const fakes = { test(ctrl, env, ctx) { - function FakeBuffer() { } + function FakeBuffer() {} Object.setPrototypeOf(FakeBuffer, Buffer); Object.setPrototypeOf(FakeBuffer.prototype, Buffer.prototype); const fb = new FakeBuffer(); - throws(function() { + throws(function () { Buffer.from(fb); }, TypeError); - throws(function() { + throws(function () { +Buffer.prototype; // eslint-disable-line no-unused-expressions }, TypeError); - throws(function() { + throws(function () { Buffer.compare(fb, Buffer.alloc(0)); }, TypeError); - throws(function() { + throws(function () { fb.write('foo'); }, TypeError); - throws(function() { + throws(function () { Buffer.concat([fb, fb]); }, TypeError); - throws(function() { + throws(function () { fb.toString(); }, TypeError); - throws(function() { + throws(function () { fb.equals(Buffer.alloc(0)); }, TypeError); - throws(function() { + throws(function () { fb.indexOf(5); }, TypeError); - throws(function() { + throws(function () { fb.readFloatLE(0); }, TypeError); - throws(function() { + throws(function () { fb.writeFloatLE(0); }, TypeError); - throws(function() { + throws(function () { fb.fill(0); }, TypeError); - - } + }, }; export const fill = { @@ -2233,21 +2444,27 @@ export const fill = { testBufs('61c8b462c8b563c8b6', 4, 1, 'hex'); testBufs('61c8b462c8b563c8b6', 12, 1, 'hex'); - throws(() => { - const buf = Buffer.allocUnsafe(SIZE); + throws( + () => { + const buf = Buffer.allocUnsafe(SIZE); - buf.fill('yKJh', 'hex'); - }, { - name: 'TypeError' - }); + buf.fill('yKJh', 'hex'); + }, + { + name: 'TypeError', + } + ); - throws(() => { - const buf = Buffer.allocUnsafe(SIZE); + throws( + () => { + const buf = Buffer.allocUnsafe(SIZE); - buf.fill('\u0222', 'hex'); - }, { - name: 'TypeError' - }); + buf.fill('\u0222', 'hex'); + }, + { + name: 'TypeError', + } + ); // BASE64 testBufs('YWJj', 'base64'); @@ -2306,41 +2523,29 @@ export const fill = { ['', 0, buf1.length + 1], ['', 1, -1], ].forEach((args) => { - throws( - () => buf1.fill(...args), - { name: 'RangeError' } - ); + throws(() => buf1.fill(...args), { name: 'RangeError' }); }); - throws( - () => buf1.fill('a', 0, buf1.length, 'node rocks!'), - { - code: 'ERR_UNKNOWN_ENCODING', - name: 'TypeError', - message: 'Unknown encoding: node rocks!' - } - ); + throws(() => buf1.fill('a', 0, buf1.length, 'node rocks!'), { + code: 'ERR_UNKNOWN_ENCODING', + name: 'TypeError', + message: 'Unknown encoding: node rocks!', + }); [ ['a', 0, 0, NaN], ['a', 0, 0, false], ].forEach((args) => { - throws( - () => buf1.fill(...args), - { - name: 'TypeError', - } - ); + throws(() => buf1.fill(...args), { + name: 'TypeError', + }); }); - throws( - () => buf1.fill('a', 0, 0, 'foo'), - { - code: 'ERR_UNKNOWN_ENCODING', - name: 'TypeError', - message: 'Unknown encoding: foo' - } - ); + throws(() => buf1.fill('a', 0, 0, 'foo'), { + code: 'ERR_UNKNOWN_ENCODING', + name: 'TypeError', + message: 'Unknown encoding: foo', + }); function genBuffer(size, args) { const b = Buffer.allocUnsafe(size); @@ -2369,11 +2574,9 @@ export const fill = { } // Should never be reached. - if (offset < 0 || end > buf2.length) - throw new ERR_OUT_OF_RANGE(); + if (offset < 0 || end > buf2.length) throw new ERR_OUT_OF_RANGE(); - if (end <= offset) - return buf2; + if (end <= offset) return buf2; offset >>>= 0; end >>>= 0; @@ -2388,10 +2591,8 @@ export const fill = { offset += written; // Safety check in case write falls into infinite loop. if (written === 0) { - if (wasZero) - throw new Error('Could not write all data to Buffer'); - else - wasZero = true; + if (wasZero) throw new Error('Could not write all data to Buffer'); + else wasZero = true; } } while (offset < buf2.length); @@ -2402,17 +2603,19 @@ export const fill = { bufReset(); buf1.fill.apply(buf1, arguments); // Swap bytes on BE archs for ucs2 encoding. - deepStrictEqual(buf1.fill.apply(buf1, arguments), - writeToFill.apply(null, arguments)); + deepStrictEqual( + buf1.fill.apply(buf1, arguments), + writeToFill.apply(null, arguments) + ); } // Make sure these throw. - throws( - () => Buffer.allocUnsafe(8).fill('a', -1), - { code: 'ERR_OUT_OF_RANGE' }); - throws( - () => Buffer.allocUnsafe(8).fill('a', 0, 9), - { code: 'ERR_OUT_OF_RANGE' }); + throws(() => Buffer.allocUnsafe(8).fill('a', -1), { + code: 'ERR_OUT_OF_RANGE', + }); + throws(() => Buffer.allocUnsafe(8).fill('a', 0, 9), { + code: 'ERR_OUT_OF_RANGE', + }); // // Make sure this doesn't hang indefinitely. Buffer.allocUnsafe(8).fill(''); @@ -2420,12 +2623,10 @@ export const fill = { { const buf = Buffer.alloc(64, 10); - for (let i = 0; i < buf.length; i++) - strictEqual(buf[i], 10); + for (let i = 0; i < buf.length; i++) strictEqual(buf[i], 10); buf.fill(11, 0, buf.length >> 1); - for (let i = 0; i < buf.length >> 1; i++) - strictEqual(buf[i], 11); + for (let i = 0; i < buf.length >> 1; i++) strictEqual(buf[i], 11); for (let i = (buf.length >> 1) + 1; i < buf.length; i++) strictEqual(buf[i], 10); @@ -2434,20 +2635,15 @@ export const fill = { strictEqual(buf[i], 'h'.charCodeAt(0)); buf.fill(0); - for (let i = 0; i < buf.length; i++) - strictEqual(buf[i], 0); + for (let i = 0; i < buf.length; i++) strictEqual(buf[i], 0); buf.fill(null); - for (let i = 0; i < buf.length; i++) - strictEqual(buf[i], 0); + for (let i = 0; i < buf.length; i++) strictEqual(buf[i], 0); buf.fill(1, 16, 32); - for (let i = 0; i < 16; i++) - strictEqual(buf[i], 0); - for (let i = 16; i < 32; i++) - strictEqual(buf[i], 1); - for (let i = 32; i < buf.length; i++) - strictEqual(buf[i], 0); + for (let i = 0; i < 16; i++) strictEqual(buf[i], 0); + for (let i = 16; i < 32; i++) strictEqual(buf[i], 1); + for (let i = 32; i < buf.length; i++) strictEqual(buf[i], 0); } { @@ -2460,18 +2656,22 @@ export const fill = { // Make sure "end" is properly checked, even if it's magically mangled using // Symbol.toPrimitive. { - throws(() => { - const end = { - [Symbol.toPrimitive]() { - return 1; - } - }; - Buffer.alloc(1).fill(Buffer.alloc(1), 0, end); - }, { - code: 'ERR_INVALID_ARG_TYPE', - message: 'The "end" argument must be of type number. Received an ' + - 'instance of Object' - }); + throws( + () => { + const end = { + [Symbol.toPrimitive]() { + return 1; + }, + }; + Buffer.alloc(1).fill(Buffer.alloc(1), 0, end); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + message: + 'The "end" argument must be of type number. Received an ' + + 'instance of Object', + } + ); } // Test that bypassing 'length' won't cause an abort. @@ -2484,54 +2684,66 @@ export const fill = { const buf = Buffer.from('w00t'); Object.defineProperty(buf, 'length', { value: 1337, - enumerable: true + enumerable: true, }); buf.fill(''); } deepStrictEqual( Buffer.allocUnsafeSlow(16).fill('ab', 'utf16le'), - Buffer.from('61006200610062006100620061006200', 'hex')); + Buffer.from('61006200610062006100620061006200', 'hex') + ); deepStrictEqual( Buffer.allocUnsafeSlow(15).fill('ab', 'utf16le'), - Buffer.from('610062006100620061006200610062', 'hex')); + Buffer.from('610062006100620061006200610062', 'hex') + ); deepStrictEqual( Buffer.allocUnsafeSlow(16).fill('ab', 'utf16le'), - Buffer.from('61006200610062006100620061006200', 'hex')); + Buffer.from('61006200610062006100620061006200', 'hex') + ); deepStrictEqual( Buffer.allocUnsafeSlow(16).fill('a', 'utf16le'), - Buffer.from('61006100610061006100610061006100', 'hex')); + Buffer.from('61006100610061006100610061006100', 'hex') + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('a', 'utf16le').toString('utf16le'), - 'a'.repeat(8)); + 'a'.repeat(8) + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('a', 'latin1').toString('latin1'), - 'a'.repeat(16)); + 'a'.repeat(16) + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('a', 'utf8').toString('utf8'), - 'a'.repeat(16)); + 'a'.repeat(16) + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('Љ', 'utf16le').toString('utf16le'), - 'Љ'.repeat(8)); + 'Љ'.repeat(8) + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('Љ', 'latin1').toString('latin1'), - '\t'.repeat(16)); + '\t'.repeat(16) + ); strictEqual( Buffer.allocUnsafeSlow(16).fill('Љ', 'utf8').toString('utf8'), - 'Љ'.repeat(8)); - - throws(() => { - const buf = Buffer.from('a'.repeat(1000)); + 'Љ'.repeat(8) + ); - buf.fill('This is not correctly encoded', 'hex'); - }, { - name: 'TypeError' - }); + throws( + () => { + const buf = Buffer.from('a'.repeat(1000)); + buf.fill('This is not correctly encoded', 'hex'); + }, + { + name: 'TypeError', + } + ); { const bufEmptyString = Buffer.alloc(5, ''); @@ -2546,7 +2758,7 @@ export const fill = { const bufZero = Buffer.alloc(5, 0); strictEqual(bufZero.toString(), '\x00\x00\x00\x00\x00'); } - } + }, }; export const includes = { @@ -2627,61 +2839,71 @@ export const includes = { // test hex encoding strictEqual( - Buffer.from(b.toString('hex'), 'hex') - .includes('64', 0, 'hex'), + Buffer.from(b.toString('hex'), 'hex').includes('64', 0, 'hex'), true ); strictEqual( - Buffer.from(b.toString('hex'), 'hex') - .includes(Buffer.from('64', 'hex'), 0, 'hex'), + Buffer.from(b.toString('hex'), 'hex').includes( + Buffer.from('64', 'hex'), + 0, + 'hex' + ), true ); // Test base64 encoding strictEqual( - Buffer.from(b.toString('base64'), 'base64') - .includes('ZA==', 0, 'base64'), + Buffer.from(b.toString('base64'), 'base64').includes('ZA==', 0, 'base64'), true ); strictEqual( - Buffer.from(b.toString('base64'), 'base64') - .includes(Buffer.from('ZA==', 'base64'), 0, 'base64'), + Buffer.from(b.toString('base64'), 'base64').includes( + Buffer.from('ZA==', 'base64'), + 0, + 'base64' + ), true ); // test ascii encoding strictEqual( - Buffer.from(b.toString('ascii'), 'ascii') - .includes('d', 0, 'ascii'), + Buffer.from(b.toString('ascii'), 'ascii').includes('d', 0, 'ascii'), true ); strictEqual( - Buffer.from(b.toString('ascii'), 'ascii') - .includes(Buffer.from('d', 'ascii'), 0, 'ascii'), + Buffer.from(b.toString('ascii'), 'ascii').includes( + Buffer.from('d', 'ascii'), + 0, + 'ascii' + ), true ); // Test latin1 encoding strictEqual( - Buffer.from(b.toString('latin1'), 'latin1') - .includes('d', 0, 'latin1'), + Buffer.from(b.toString('latin1'), 'latin1').includes('d', 0, 'latin1'), true ); strictEqual( - Buffer.from(b.toString('latin1'), 'latin1') - .includes(Buffer.from('d', 'latin1'), 0, 'latin1'), + Buffer.from(b.toString('latin1'), 'latin1').includes( + Buffer.from('d', 'latin1'), + 0, + 'latin1' + ), true ); // Test binary encoding strictEqual( - Buffer.from(b.toString('binary'), 'binary') - .includes('d', 0, 'binary'), + Buffer.from(b.toString('binary'), 'binary').includes('d', 0, 'binary'), true ); strictEqual( - Buffer.from(b.toString('binary'), 'binary') - .includes(Buffer.from('d', 'binary'), 0, 'binary'), + Buffer.from(b.toString('binary'), 'binary').includes( + Buffer.from('d', 'binary'), + 0, + 'binary' + ), true ); @@ -2691,22 +2913,20 @@ export const includes = { ok(twoByteString.includes('\u0395', 4, 'ucs2')); ok(twoByteString.includes('\u03a3', -4, 'ucs2')); ok(twoByteString.includes('\u03a3', -6, 'ucs2')); - ok(twoByteString.includes( - Buffer.from('\u03a3', 'ucs2'), -6, 'ucs2')); + ok(twoByteString.includes(Buffer.from('\u03a3', 'ucs2'), -6, 'ucs2')); ok(!twoByteString.includes('\u03a3', -2, 'ucs2')); - const mixedByteStringUcs2 = - Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395', 'ucs2'); + const mixedByteStringUcs2 = Buffer.from( + '\u039a\u0391abc\u03a3\u03a3\u0395', + 'ucs2' + ); ok(mixedByteStringUcs2.includes('bc', 0, 'ucs2')); ok(mixedByteStringUcs2.includes('\u03a3', 0, 'ucs2')); ok(!mixedByteStringUcs2.includes('\u0396', 0, 'ucs2')); - ok( - mixedByteStringUcs2.includes(Buffer.from('bc', 'ucs2'), 0, 'ucs2')); - ok( - mixedByteStringUcs2.includes(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2')); - ok( - !mixedByteStringUcs2.includes(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2')); + ok(mixedByteStringUcs2.includes(Buffer.from('bc', 'ucs2'), 0, 'ucs2')); + ok(mixedByteStringUcs2.includes(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2')); + ok(!mixedByteStringUcs2.includes(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2')); twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2'); @@ -2724,7 +2944,9 @@ export const includes = { ok(twoByteString.includes('\u03a3\u03a3', 0, 'ucs2'), 'Sigma Sigma'); ok(twoByteString.includes('\u03a3\u0395', 0, 'ucs2'), 'Sigma Epsilon'); - const mixedByteStringUtf8 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395'); + const mixedByteStringUtf8 = Buffer.from( + '\u039a\u0391abc\u03a3\u03a3\u0395' + ); ok(mixedByteStringUtf8.includes('bc')); ok(mixedByteStringUtf8.includes('bc', 5)); ok(mixedByteStringUtf8.includes('bc', -8)); @@ -2734,7 +2956,8 @@ export const includes = { // Test complex string includes algorithms. Only trigger for long strings. // Long string that isn't a simple repeat of a shorter string. let longString = 'A'; - for (let i = 66; i < 76; i++) { // from 'B' to 'K' + for (let i = 66; i < 76; i++) { + // from 'B' to 'K' longString = longString + String.fromCharCode(i) + longString; } @@ -2755,15 +2978,17 @@ export const includes = { // Search for a non-ASCII string in a pure ASCII string. const asciiString = Buffer.from( - 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf'); + 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf' + ); ok(!asciiString.includes('\x2061')); ok(asciiString.includes('leb', 0)); // Search in string containing many non-ASCII chars. const allCodePoints = []; for (let i = 0; i < 65534; i++) allCodePoints[i] = i; - const allCharsString = String.fromCharCode.apply(String, allCodePoints) + - String.fromCharCode(65534, 65535); + const allCharsString = + String.fromCharCode.apply(String, allCodePoints) + + String.fromCharCode(65534, 65535); const allCharsBufferUtf8 = Buffer.from(allCharsString); const allCharsBufferUcs2 = Buffer.from(allCharsString, 'ucs2'); @@ -2773,26 +2998,29 @@ export const includes = { ok(!allCharsBufferUcs2.includes('notfound')); // Find substrings in Utf8. - let lengths = [1, 3, 15]; // Single char, simple and complex. - let indices = [0x5, 0x60, 0x400, 0x680, 0x7ee, 0xFF02, 0x16610, 0x2f77b]; + let lengths = [1, 3, 15]; // Single char, simple and complex. + let indices = [0x5, 0x60, 0x400, 0x680, 0x7ee, 0xff02, 0x16610, 0x2f77b]; for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) { for (let i = 0; i < indices.length; i++) { const index = indices[i]; let length = lengths[lengthIndex]; - if (index + length > 0x7F) { + if (index + length > 0x7f) { length = 2 * length; } - if (index + length > 0x7FF) { + if (index + length > 0x7ff) { length = 3 * length; } - if (index + length > 0xFFFF) { + if (index + length > 0xffff) { length = 4 * length; } - const patternBufferUtf8 = allCharsBufferUtf8.slice(index, index + length); + const patternBufferUtf8 = allCharsBufferUtf8.slice( + index, + index + length + ); ok(index, allCharsBufferUtf8.includes(patternBufferUtf8)); const patternStringUtf8 = patternBufferUtf8.toString(); @@ -2801,35 +3029,28 @@ export const includes = { } // Find substrings in Usc2. - lengths = [2, 4, 16]; // Single char, simple and complex. + lengths = [2, 4, 16]; // Single char, simple and complex. indices = [0x5, 0x65, 0x105, 0x205, 0x285, 0x2005, 0x2085, 0xfff0]; for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) { for (let i = 0; i < indices.length; i++) { const index = indices[i] * 2; const length = lengths[lengthIndex]; - const patternBufferUcs2 = - allCharsBufferUcs2.slice(index, index + length); - ok( - allCharsBufferUcs2.includes(patternBufferUcs2, 0, 'ucs2')); + const patternBufferUcs2 = allCharsBufferUcs2.slice( + index, + index + length + ); + ok(allCharsBufferUcs2.includes(patternBufferUcs2, 0, 'ucs2')); const patternStringUcs2 = patternBufferUcs2.toString('ucs2'); - ok( - allCharsBufferUcs2.includes(patternStringUcs2, 0, 'ucs2')); + ok(allCharsBufferUcs2.includes(patternStringUcs2, 0, 'ucs2')); } } - [ - () => { }, - {}, - [], - ].forEach((val) => { - throws( - () => b.includes(val), - { - name: 'TypeError', - } - ); + [() => {}, {}, []].forEach((val) => { + throws(() => b.includes(val), { + name: 'TypeError', + }); }); // Test truncation of Number arguments to uint8 @@ -2847,7 +3068,7 @@ export const includes = { ok(!buf.includes(0xff)); ok(!buf.includes(0xffff)); } - } + }, }; export const indexof = { @@ -2937,98 +3158,105 @@ export const indexof = { // test hex encoding strictEqual( - Buffer.from(b.toString('hex'), 'hex') - .indexOf('64', 0, 'hex'), + Buffer.from(b.toString('hex'), 'hex').indexOf('64', 0, 'hex'), 3 ); strictEqual( - Buffer.from(b.toString('hex'), 'hex') - .indexOf(Buffer.from('64', 'hex'), 0, 'hex'), + Buffer.from(b.toString('hex'), 'hex').indexOf( + Buffer.from('64', 'hex'), + 0, + 'hex' + ), 3 ); // Test base64 encoding strictEqual( - Buffer.from(b.toString('base64'), 'base64') - .indexOf('ZA==', 0, 'base64'), + Buffer.from(b.toString('base64'), 'base64').indexOf('ZA==', 0, 'base64'), 3 ); strictEqual( - Buffer.from(b.toString('base64'), 'base64') - .indexOf(Buffer.from('ZA==', 'base64'), 0, 'base64'), + Buffer.from(b.toString('base64'), 'base64').indexOf( + Buffer.from('ZA==', 'base64'), + 0, + 'base64' + ), 3 ); // Test base64url encoding strictEqual( - Buffer.from(b.toString('base64url'), 'base64url') - .indexOf('ZA==', 0, 'base64url'), + Buffer.from(b.toString('base64url'), 'base64url').indexOf( + 'ZA==', + 0, + 'base64url' + ), 3 ); // test ascii encoding strictEqual( - Buffer.from(b.toString('ascii'), 'ascii') - .indexOf('d', 0, 'ascii'), + Buffer.from(b.toString('ascii'), 'ascii').indexOf('d', 0, 'ascii'), 3 ); strictEqual( - Buffer.from(b.toString('ascii'), 'ascii') - .indexOf(Buffer.from('d', 'ascii'), 0, 'ascii'), + Buffer.from(b.toString('ascii'), 'ascii').indexOf( + Buffer.from('d', 'ascii'), + 0, + 'ascii' + ), 3 ); // Test latin1 encoding strictEqual( - Buffer.from(b.toString('latin1'), 'latin1') - .indexOf('d', 0, 'latin1'), + Buffer.from(b.toString('latin1'), 'latin1').indexOf('d', 0, 'latin1'), 3 ); strictEqual( - Buffer.from(b.toString('latin1'), 'latin1') - .indexOf(Buffer.from('d', 'latin1'), 0, 'latin1'), + Buffer.from(b.toString('latin1'), 'latin1').indexOf( + Buffer.from('d', 'latin1'), + 0, + 'latin1' + ), 3 ); strictEqual( - Buffer.from('aa\u00e8aa', 'latin1') - .indexOf('\u00e8', 'latin1'), + Buffer.from('aa\u00e8aa', 'latin1').indexOf('\u00e8', 'latin1'), 2 ); + strictEqual(Buffer.from('\u00e8', 'latin1').indexOf('\u00e8', 'latin1'), 0); strictEqual( - Buffer.from('\u00e8', 'latin1') - .indexOf('\u00e8', 'latin1'), - 0 - ); - strictEqual( - Buffer.from('\u00e8', 'latin1') - .indexOf(Buffer.from('\u00e8', 'latin1'), 'latin1'), + Buffer.from('\u00e8', 'latin1').indexOf( + Buffer.from('\u00e8', 'latin1'), + 'latin1' + ), 0 ); // Test binary encoding strictEqual( - Buffer.from(b.toString('binary'), 'binary') - .indexOf('d', 0, 'binary'), + Buffer.from(b.toString('binary'), 'binary').indexOf('d', 0, 'binary'), 3 ); strictEqual( - Buffer.from(b.toString('binary'), 'binary') - .indexOf(Buffer.from('d', 'binary'), 0, 'binary'), + Buffer.from(b.toString('binary'), 'binary').indexOf( + Buffer.from('d', 'binary'), + 0, + 'binary' + ), 3 ); strictEqual( - Buffer.from('aa\u00e8aa', 'binary') - .indexOf('\u00e8', 'binary'), + Buffer.from('aa\u00e8aa', 'binary').indexOf('\u00e8', 'binary'), 2 ); + strictEqual(Buffer.from('\u00e8', 'binary').indexOf('\u00e8', 'binary'), 0); strictEqual( - Buffer.from('\u00e8', 'binary') - .indexOf('\u00e8', 'binary'), - 0 - ); - strictEqual( - Buffer.from('\u00e8', 'binary') - .indexOf(Buffer.from('\u00e8', 'binary'), 'binary'), + Buffer.from('\u00e8', 'binary').indexOf( + Buffer.from('\u00e8', 'binary'), + 'binary' + ), 0 ); @@ -3040,32 +3268,47 @@ export const indexof = { // Test usc2 and utf16le encoding ['ucs2', 'utf16le'].forEach((encoding) => { const twoByteString = Buffer.from( - '\u039a\u0391\u03a3\u03a3\u0395', encoding); + '\u039a\u0391\u03a3\u03a3\u0395', + encoding + ); strictEqual(twoByteString.indexOf('\u0395', 4, encoding), 8); strictEqual(twoByteString.indexOf('\u03a3', -4, encoding), 6); strictEqual(twoByteString.indexOf('\u03a3', -6, encoding), 4); - strictEqual(twoByteString.indexOf( - Buffer.from('\u03a3', encoding), -6, encoding), 4); + strictEqual( + twoByteString.indexOf(Buffer.from('\u03a3', encoding), -6, encoding), + 4 + ); strictEqual(-1, twoByteString.indexOf('\u03a3', -2, encoding)); }); } - const mixedByteStringUcs2 = - Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395', 'ucs2'); + const mixedByteStringUcs2 = Buffer.from( + '\u039a\u0391abc\u03a3\u03a3\u0395', + 'ucs2' + ); strictEqual(mixedByteStringUcs2.indexOf('bc', 0, 'ucs2'), 6); strictEqual(mixedByteStringUcs2.indexOf('\u03a3', 0, 'ucs2'), 10); strictEqual(-1, mixedByteStringUcs2.indexOf('\u0396', 0, 'ucs2')); strictEqual( - mixedByteStringUcs2.indexOf(Buffer.from('bc', 'ucs2'), 0, 'ucs2'), 6); + mixedByteStringUcs2.indexOf(Buffer.from('bc', 'ucs2'), 0, 'ucs2'), + 6 + ); strictEqual( - mixedByteStringUcs2.indexOf(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2'), 10); + mixedByteStringUcs2.indexOf(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2'), + 10 + ); strictEqual( - -1, mixedByteStringUcs2.indexOf(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2')); + -1, + mixedByteStringUcs2.indexOf(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2') + ); { - const twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2'); + const twoByteString = Buffer.from( + '\u039a\u0391\u03a3\u03a3\u0395', + 'ucs2' + ); // Test single char pattern strictEqual(twoByteString.indexOf('\u039a', 0, 'ucs2'), 0); @@ -3091,7 +3334,9 @@ export const indexof = { strictEqual(index, 6, `Sigma Epsilon - at index ${index}`); } - const mixedByteStringUtf8 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395'); + const mixedByteStringUtf8 = Buffer.from( + '\u039a\u0391abc\u03a3\u03a3\u0395' + ); strictEqual(mixedByteStringUtf8.indexOf('bc'), 5); strictEqual(mixedByteStringUtf8.indexOf('bc', 5), 5); strictEqual(mixedByteStringUtf8.indexOf('bc', -8), 5); @@ -3101,7 +3346,8 @@ export const indexof = { // Test complex string indexOf algorithms. Only trigger for long strings. // Long string that isn't a simple repeat of a shorter string. let longString = 'A'; - for (let i = 66; i < 76; i++) { // from 'B' to 'K' + for (let i = 66; i < 76; i++) { + // from 'B' to 'K' longString = longString + String.fromCharCode(i) + longString; } @@ -3111,8 +3357,11 @@ export const indexof = { let pattern = 'ABACABADABACABA'; for (let i = 0; i < longBufferString.length - pattern.length; i += 7) { const index = longBufferString.indexOf(pattern, i); - strictEqual((i + 15) & ~0xf, index, - `Long ABACABA...-string at index ${i}`); + strictEqual( + (i + 15) & ~0xf, + index, + `Long ABACABA...-string at index ${i}` + ); } let index = longBufferString.indexOf('AJABACA'); @@ -3124,20 +3373,21 @@ export const indexof = { index = longBufferString.indexOf(pattern); strictEqual(index, 511, `Long JABACABA..., First J - at index ${index}`); index = longBufferString.indexOf(pattern, 512); - strictEqual( - index, 1535, `Long JABACABA..., Second J - at index ${index}`); + strictEqual(index, 1535, `Long JABACABA..., Second J - at index ${index}`); // Search for a non-ASCII string in a pure ASCII string. const asciiString = Buffer.from( - 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf'); + 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf' + ); strictEqual(-1, asciiString.indexOf('\x2061')); strictEqual(asciiString.indexOf('leb', 0), 3); // Search in string containing many non-ASCII chars. const allCodePoints = []; for (let i = 0; i < 65534; i++) allCodePoints[i] = i; - const allCharsString = String.fromCharCode.apply(String, allCodePoints) + - String.fromCharCode(65534, 65535); + const allCharsString = + String.fromCharCode.apply(String, allCodePoints) + + String.fromCharCode(65534, 65535); const allCharsBufferUtf8 = Buffer.from(allCharsString); const allCharsBufferUcs2 = Buffer.from(allCharsString, 'ucs2'); @@ -3157,26 +3407,31 @@ export const indexof = { { // Find substrings in Utf8. - const lengths = [1, 3, 15]; // Single char, simple and complex. - const indices = [0x5, 0x60, 0x400, 0x680, 0x7ee, 0xFF02, 0x16610, 0x2f77b]; + const lengths = [1, 3, 15]; // Single char, simple and complex. + const indices = [ + 0x5, 0x60, 0x400, 0x680, 0x7ee, 0xff02, 0x16610, 0x2f77b, + ]; for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) { for (let i = 0; i < indices.length; i++) { const index = indices[i]; let length = lengths[lengthIndex]; - if (index + length > 0x7F) { + if (index + length > 0x7f) { length = 2 * length; } - if (index + length > 0x7FF) { + if (index + length > 0x7ff) { length = 3 * length; } - if (index + length > 0xFFFF) { + if (index + length > 0xffff) { length = 4 * length; } - const patternBufferUtf8 = allCharsBufferUtf8.slice(index, index + length); + const patternBufferUtf8 = allCharsBufferUtf8.slice( + index, + index + length + ); strictEqual(index, allCharsBufferUtf8.indexOf(patternBufferUtf8)); const patternStringUtf8 = patternBufferUtf8.toString(); @@ -3187,36 +3442,35 @@ export const indexof = { { // Find substrings in Usc2. - const lengths = [2, 4, 16]; // Single char, simple and complex. + const lengths = [2, 4, 16]; // Single char, simple and complex. const indices = [0x5, 0x65, 0x105, 0x205, 0x285, 0x2005, 0x2085, 0xfff0]; for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) { for (let i = 0; i < indices.length; i++) { const index = indices[i] * 2; const length = lengths[lengthIndex]; - const patternBufferUcs2 = - allCharsBufferUcs2.slice(index, index + length); + const patternBufferUcs2 = allCharsBufferUcs2.slice( + index, + index + length + ); strictEqual( - index, allCharsBufferUcs2.indexOf(patternBufferUcs2, 0, 'ucs2')); + index, + allCharsBufferUcs2.indexOf(patternBufferUcs2, 0, 'ucs2') + ); const patternStringUcs2 = patternBufferUcs2.toString('ucs2'); strictEqual( - index, allCharsBufferUcs2.indexOf(patternStringUcs2, 0, 'ucs2')); + index, + allCharsBufferUcs2.indexOf(patternStringUcs2, 0, 'ucs2') + ); } } } - [ - () => {}, - {}, - [], - ].forEach((val) => { - throws( - () => b.indexOf(val), - { - name: 'TypeError', - } - ); + [() => {}, {}, []].forEach((val) => { + throws(() => b.indexOf(val), { + name: 'TypeError', + }); }); // Test weird offset arguments. @@ -3231,24 +3485,12 @@ export const indexof = { strictEqual(b.indexOf('b', [2]), -1); // Behavior should match String.indexOf() - strictEqual( - b.indexOf('b', undefined), - s.indexOf('b', undefined)); - strictEqual( - b.indexOf('b', {}), - s.indexOf('b', {})); - strictEqual( - b.indexOf('b', 0), - s.indexOf('b', 0)); - strictEqual( - b.indexOf('b', null), - s.indexOf('b', null)); - strictEqual( - b.indexOf('b', []), - s.indexOf('b', [])); - strictEqual( - b.indexOf('b', [2]), - s.indexOf('b', [2])); + strictEqual(b.indexOf('b', undefined), s.indexOf('b', undefined)); + strictEqual(b.indexOf('b', {}), s.indexOf('b', {})); + strictEqual(b.indexOf('b', 0), s.indexOf('b', 0)); + strictEqual(b.indexOf('b', null), s.indexOf('b', null)); + strictEqual(b.indexOf('b', []), s.indexOf('b', [])); + strictEqual(b.indexOf('b', [2]), s.indexOf('b', [2])); // All code for handling encodings is shared between Buffer.indexOf and // Buffer.lastIndexOf, so only testing the separate lastIndexOf semantics. @@ -3317,24 +3559,12 @@ export const indexof = { strictEqual(b.lastIndexOf('b', [2]), 1); // Behavior should match String.lastIndexOf() - strictEqual( - b.lastIndexOf('b', undefined), - s.lastIndexOf('b', undefined)); - strictEqual( - b.lastIndexOf('b', {}), - s.lastIndexOf('b', {})); - strictEqual( - b.lastIndexOf('b', 0), - s.lastIndexOf('b', 0)); - strictEqual( - b.lastIndexOf('b', null), - s.lastIndexOf('b', null)); - strictEqual( - b.lastIndexOf('b', []), - s.lastIndexOf('b', [])); - strictEqual( - b.lastIndexOf('b', [2]), - s.lastIndexOf('b', [2])); + strictEqual(b.lastIndexOf('b', undefined), s.lastIndexOf('b', undefined)); + strictEqual(b.lastIndexOf('b', {}), s.lastIndexOf('b', {})); + strictEqual(b.lastIndexOf('b', 0), s.lastIndexOf('b', 0)); + strictEqual(b.lastIndexOf('b', null), s.lastIndexOf('b', null)); + strictEqual(b.lastIndexOf('b', []), s.lastIndexOf('b', [])); + strictEqual(b.lastIndexOf('b', [2]), s.lastIndexOf('b', [2])); // Test needles longer than the haystack. strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 'ucs2'), -1); @@ -3366,8 +3596,10 @@ export const indexof = { strictEqual(bufferString.lastIndexOf('panama'), 21); strictEqual(bufferString.lastIndexOf('a man a plan a canal panama'), 0); strictEqual(-1, bufferString.lastIndexOf('a man a plan a canal mexico')); - strictEqual(-1, bufferString - .lastIndexOf('a man a plan a canal mexico city')); + strictEqual( + -1, + bufferString.lastIndexOf('a man a plan a canal mexico city') + ); strictEqual(-1, bufferString.lastIndexOf(Buffer.from('a'.repeat(1000)))); strictEqual(bufferString.lastIndexOf('a man a plan', 4), 0); strictEqual(bufferString.lastIndexOf('a '), 13); @@ -3418,21 +3650,21 @@ export const indexof = { } const parts = []; for (let i = 0; i < 1000000; i++) { - parts.push((countBits(i) % 2 === 0) ? 'yolo' : 'swag'); + parts.push(countBits(i) % 2 === 0 ? 'yolo' : 'swag'); } const reallyLong = Buffer.from(parts.join(' ')); strictEqual(reallyLong.slice(0, 19).toString(), 'yolo swag swag yolo'); // Expensive reverse searches. Stress test lastIndexOf: - pattern = reallyLong.slice(0, 100000); // First 1/50th of the pattern. + pattern = reallyLong.slice(0, 100000); // First 1/50th of the pattern. strictEqual(reallyLong.lastIndexOf(pattern), 4751360); strictEqual(reallyLong.lastIndexOf(pattern, 4000000), 3932160); strictEqual(reallyLong.lastIndexOf(pattern, 3000000), 2949120); - pattern = reallyLong.slice(100000, 200000); // Second 1/50th. + pattern = reallyLong.slice(100000, 200000); // Second 1/50th. strictEqual(reallyLong.lastIndexOf(pattern), 4728480); - pattern = reallyLong.slice(0, 1000000); // First 1/5th. + pattern = reallyLong.slice(0, 1000000); // First 1/5th. strictEqual(reallyLong.lastIndexOf(pattern), 3932160); - pattern = reallyLong.slice(0, 2000000); // first 2/5ths. + pattern = reallyLong.slice(0, 2000000); // first 2/5ths. strictEqual(reallyLong.lastIndexOf(pattern), 0); // Test truncation of Number arguments to uint8 @@ -3453,12 +3685,12 @@ export const indexof = { // Test that Uint8Array arguments are okay. { - const needle = new Uint8Array([ 0x66, 0x6f, 0x6f ]); + const needle = new Uint8Array([0x66, 0x6f, 0x6f]); const haystack = Buffer.from('a foo b foo'); strictEqual(haystack.indexOf(needle), 2); strictEqual(haystack.lastIndexOf(needle), haystack.length - 3); } - } + }, }; export const inheritance = { @@ -3473,30 +3705,29 @@ export const inheritance = { T.prototype.sum = function sum() { let cntr = 0; - for (let i = 0; i < this.length; i++) - cntr += this[i]; + for (let i = 0; i < this.length; i++) cntr += this[i]; return cntr; }; - const vals = [new T(4), T(4)]; - vals.forEach(function(t) { + vals.forEach(function (t) { strictEqual(t.constructor, T); strictEqual(Object.getPrototypeOf(t), T.prototype); - strictEqual(Object.getPrototypeOf(Object.getPrototypeOf(t)), - Buffer.prototype); + strictEqual( + Object.getPrototypeOf(Object.getPrototypeOf(t)), + Buffer.prototype + ); t.fill(5); let cntr = 0; - for (let i = 0; i < t.length; i++) - cntr += t[i]; + for (let i = 0; i < t.length; i++) cntr += t[i]; strictEqual(cntr, t.length * 5); // Check this does not throw t.toString(); }); - } + }, }; export const iterator = { @@ -3509,48 +3740,39 @@ export const iterator = { arr = []; - for (b of buffer) - arr.push(b); + for (b of buffer) arr.push(b); deepStrictEqual(arr, [1, 2, 3, 4, 5]); - // Buffer iterators should be iterable arr = []; - for (b of buffer[Symbol.iterator]()) - arr.push(b); + for (b of buffer[Symbol.iterator]()) arr.push(b); deepStrictEqual(arr, [1, 2, 3, 4, 5]); - // buffer#values() should return iterator for values arr = []; - for (b of buffer.values()) - arr.push(b); + for (b of buffer.values()) arr.push(b); deepStrictEqual(arr, [1, 2, 3, 4, 5]); - // buffer#keys() should return iterator for keys arr = []; - for (b of buffer.keys()) - arr.push(b); + for (b of buffer.keys()) arr.push(b); deepStrictEqual(arr, [0, 1, 2, 3, 4]); - // buffer#entries() should return iterator for entries arr = []; - for (b of buffer.entries()) - arr.push(b); + for (b of buffer.entries()) arr.push(b); deepStrictEqual(arr, [ [0, 1], @@ -3559,7 +3781,7 @@ export const iterator = { [3, 4], [4, 5], ]); - } + }, }; export const negativeAlloc = { @@ -3589,7 +3811,7 @@ export const negativeAlloc = { throws(() => SlowBuffer(-100), msg); throws(() => SlowBuffer(-1), msg); throws(() => SlowBuffer(NaN), msg); - } + }, }; export const overMaxLength = { @@ -3612,29 +3834,28 @@ export const overMaxLength = { // issue GH-4331 throws(() => Buffer.allocUnsafe(0x100000001), bufferMaxSizeMsg); - throws(() => Buffer.allocUnsafe(0xFFFFFFFFF), bufferMaxSizeMsg); - } + throws(() => Buffer.allocUnsafe(0xfffffffff), bufferMaxSizeMsg); + }, }; export const read = { test(ctrl, env, ctx) { // Testing basic buffer read functions - const buf = Buffer.from([0xa4, 0xfd, 0x48, 0xea, 0xcf, 0xff, 0xd9, 0x01, 0xde]); + const buf = Buffer.from([ + 0xa4, 0xfd, 0x48, 0xea, 0xcf, 0xff, 0xd9, 0x01, 0xde, + ]); function read(buff, funx, args, expected) { strictEqual(buff[funx](...args), expected); - throws( - () => buff[funx](-1, args[1]), - { code: 'ERR_OUT_OF_RANGE' } - ); + throws(() => buff[funx](-1, args[1]), { code: 'ERR_OUT_OF_RANGE' }); } // Testing basic functionality of readDoubleBE() and readDoubleLE() - read(buf, 'readDoubleBE', [1], -3.1827727774563287e+295); - read(buf, 'readDoubleLE', [1], -6.966010051009108e+144); + read(buf, 'readDoubleBE', [1], -3.1827727774563287e295); + read(buf, 'readDoubleLE', [1], -6.966010051009108e144); // Testing basic functionality of readFloatBE() and readFloatLE() - read(buf, 'readFloatBE', [1], -1.6691549692541768e+37); + read(buf, 'readFloatBE', [1], -1.6691549692541768e37); read(buf, 'readFloatLE', [1], -7861303808); // Testing basic functionality of readInt8() @@ -3668,59 +3889,56 @@ export const read = { read(buf, 'readUIntLE', [2, 2], 0xea48); // Error name and message - const OOR_ERROR = - { - name: 'RangeError' + const OOR_ERROR = { + name: 'RangeError', }; - const OOB_ERROR = - { + const OOB_ERROR = { name: 'RangeError', - message: 'Attempt to access memory outside buffer bounds' + message: 'Attempt to access memory outside buffer bounds', }; // Attempt to overflow buffers, similar to previous bug in array buffers - throws( - () => Buffer.allocUnsafe(8).readFloatBE(0xffffffff), OOR_ERROR); + throws(() => Buffer.allocUnsafe(8).readFloatBE(0xffffffff), OOR_ERROR); - throws( - () => Buffer.allocUnsafe(8).readFloatLE(0xffffffff), OOR_ERROR); + throws(() => Buffer.allocUnsafe(8).readFloatLE(0xffffffff), OOR_ERROR); // Ensure negative values can't get past offset - throws( - () => Buffer.allocUnsafe(8).readFloatBE(-1), OOR_ERROR); - throws( - () => Buffer.allocUnsafe(8).readFloatLE(-1), OOR_ERROR); + throws(() => Buffer.allocUnsafe(8).readFloatBE(-1), OOR_ERROR); + throws(() => Buffer.allocUnsafe(8).readFloatLE(-1), OOR_ERROR); // Offset checks { const buf = Buffer.allocUnsafe(0); - throws( - () => buf.readUInt8(0), OOB_ERROR); - throws( - () => buf.readInt8(0), OOB_ERROR); + throws(() => buf.readUInt8(0), OOB_ERROR); + throws(() => buf.readInt8(0), OOB_ERROR); } [16, 32].forEach((bit) => { const buf = Buffer.allocUnsafe(bit / 8 - 1); - [`Int${bit}B`, `Int${bit}L`, `UInt${bit}B`, `UInt${bit}L`].forEach((fn) => { - throws( - () => buf[`read${fn}E`](0), OOB_ERROR); - }); + [`Int${bit}B`, `Int${bit}L`, `UInt${bit}B`, `UInt${bit}L`].forEach( + (fn) => { + throws(() => buf[`read${fn}E`](0), OOB_ERROR); + } + ); }); [16, 32].forEach((bits) => { - const buf = Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]); + const buf = Buffer.from([0xff, 0xff, 0xff, 0xff]); ['LE', 'BE'].forEach((endian) => { - strictEqual(buf[`readUInt${bits}${endian}`](0), - (0xFFFFFFFF >>> (32 - bits))); + strictEqual( + buf[`readUInt${bits}${endian}`](0), + 0xffffffff >>> (32 - bits) + ); - strictEqual(buf[`readInt${bits}${endian}`](0), - (0xFFFFFFFF >> (32 - bits))); + strictEqual( + buf[`readInt${bits}${endian}`](0), + 0xffffffff >> (32 - bits) + ); }); }); - } + }, }; export const readDouble = { @@ -3736,7 +3954,7 @@ export const readDouble = { buffer[5] = 0x55; buffer[6] = 0xd5; buffer[7] = 0x3f; - strictEqual(buffer.readDoubleBE(0), 1.1945305291680097e+103); + strictEqual(buffer.readDoubleBE(0), 1.1945305291680097e103); strictEqual(buffer.readDoubleLE(0), 0.3333333333333333); buffer[0] = 1; @@ -3775,7 +3993,7 @@ export const readDouble = { buffer[6] = 0xef; buffer[7] = 0x7f; ok(Number.isNaN(buffer.readDoubleBE(0))); - strictEqual(buffer.readDoubleLE(0), 1.7976931348623157e+308); + strictEqual(buffer.readDoubleLE(0), 1.7976931348623157e308); buffer[0] = 0; buffer[1] = 0; @@ -3822,48 +4040,38 @@ export const readDouble = { strictEqual(buffer.readDoubleLE(0), -Infinity); ['readDoubleLE', 'readDoubleBE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](undefined); buffer[fn](); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => buffer[fn](off), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => buffer[fn](off), { code: 'ERR_INVALID_ARG_TYPE' }); }); [Infinity, -1, 1].forEach((offset) => { - throws( - () => buffer[fn](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - }); - }); - - throws( - () => Buffer.alloc(1)[fn](1), - { - code: 'ERR_BUFFER_OUT_OF_BOUNDS', + throws(() => buffer[fn](offset), { + code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'Attempt to access memory outside buffer bounds' }); + }); - [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - `It must be an integer. Received ${offset}` - }); + throws(() => Buffer.alloc(1)[fn](1), { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: 'Attempt to access memory outside buffer bounds', }); - }); - } + [NaN, 1.01].forEach((offset) => { + throws(() => buffer[fn](offset), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: + 'The value of "offset" is out of range. ' + + `It must be an integer. Received ${offset}`, + }); + }); + }); + }, }; export const readFloat = { @@ -3890,7 +4098,7 @@ export const readFloat = { buffer[2] = 0x7f; buffer[3] = 0x7f; ok(Number.isNaN(buffer.readFloatBE(0))); - strictEqual(buffer.readFloatLE(0), 3.4028234663852886e+38); + strictEqual(buffer.readFloatLE(0), 3.4028234663852886e38); buffer[0] = 0xab; buffer[1] = 0xaa; @@ -3927,48 +4135,38 @@ export const readFloat = { strictEqual(buffer.readFloatLE(0), -Infinity); ['readFloatLE', 'readFloatBE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](undefined); buffer[fn](); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => buffer[fn](off), - { code: 'ERR_INVALID_ARG_TYPE' } - ); + throws(() => buffer[fn](off), { code: 'ERR_INVALID_ARG_TYPE' }); }); [Infinity, -1, 1].forEach((offset) => { - throws( - () => buffer[fn](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - }); - }); - - throws( - () => Buffer.alloc(1)[fn](1), - { - code: 'ERR_BUFFER_OUT_OF_BOUNDS', + throws(() => buffer[fn](offset), { + code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'Attempt to access memory outside buffer bounds' }); + }); + + throws(() => Buffer.alloc(1)[fn](1), { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: 'Attempt to access memory outside buffer bounds', + }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - `It must be an integer. Received ${offset}` - }); + throws(() => buffer[fn](offset), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: + 'The value of "offset" is out of range. ' + + `It must be an integer. Received ${offset}`, + }); }); }); - - } + }, }; export const readInt = { @@ -3978,36 +4176,29 @@ export const readInt = { const buffer = Buffer.alloc(4); ['Int8', 'Int16BE', 'Int16LE', 'Int32BE', 'Int32LE'].forEach((fn) => { - // Verify that default offset works fine. buffer[`read${fn}`](undefined); buffer[`read${fn}`](); ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { - throws( - () => buffer[`read${fn}`](o), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' - }); + throws(() => buffer[`read${fn}`](o), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); }); [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => buffer[`read${fn}`](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError' - }); + throws(() => buffer[`read${fn}`](offset), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[`read${fn}`](offset), - { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - }); + throws(() => buffer[`read${fn}`](offset), { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + }); }); }); } @@ -4082,7 +4273,9 @@ export const readInt = { // Test Int { - const buffer = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); + const buffer = Buffer.from([ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + ]); strictEqual(buffer.readIntLE(0, 1), 0x01); strictEqual(buffer.readIntBE(0, 1), 0x01); @@ -4099,59 +4292,51 @@ export const readInt = { // Check byteLength. ['readIntBE', 'readIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((len) => { - throws( - () => buffer[fn](0, len), - { name: 'RangeError' }); - }); + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (len) => { + throws(() => buffer[fn](0, len), { name: 'RangeError' }); + } + ); [Infinity, -1].forEach((byteLength) => { - throws( - () => buffer[fn](0, byteLength), - { - name: 'RangeError', - }); + throws(() => buffer[fn](0, byteLength), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((byteLength) => { - throws( - () => buffer[fn](0, byteLength), - { - name: 'RangeError', - }); + throws(() => buffer[fn](0, byteLength), { + name: 'RangeError', + }); }); }); // Test 1 to 6 bytes. for (let i = 1; i <= 6; i++) { ['readIntBE', 'readIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => { - throws( - () => buffer[fn](o, i), - { - name: 'TypeError' + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (o) => { + throws(() => buffer[fn](o, i), { + name: 'TypeError', }); - }); + } + ); [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => buffer[fn](offset, i), - { - name: 'RangeError', - }); + throws(() => buffer[fn](offset, i), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](offset, i), - { - name: 'RangeError', - }); + throws(() => buffer[fn](offset, i), { + name: 'RangeError', + }); }); }); } } - } + }, }; export const readUint = { @@ -4160,39 +4345,34 @@ export const readUint = { { const buffer = Buffer.alloc(4); - ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach((fn) => { - - // Verify that default offset works fine. - buffer[`read${fn}`](undefined); - buffer[`read${fn}`](); + ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach( + (fn) => { + // Verify that default offset works fine. + buffer[`read${fn}`](undefined); + buffer[`read${fn}`](); - ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { - throws( - () => buffer[`read${fn}`](o), - { + ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { + throws(() => buffer[`read${fn}`](o), { code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' + name: 'TypeError', }); - }); + }); - [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => buffer[`read${fn}`](offset), - { + [Infinity, -1, -4294967295].forEach((offset) => { + throws(() => buffer[`read${fn}`](offset), { code: 'ERR_OUT_OF_RANGE', - name: 'RangeError' + name: 'RangeError', }); - }); + }); - [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[`read${fn}`](offset), - { + [NaN, 1.01].forEach((offset) => { + throws(() => buffer[`read${fn}`](offset), { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', }); - }); - }); + }); + } + ); } // Test 8 bit unsigned integers @@ -4233,7 +4413,9 @@ export const readUint = { // Test UInt { - const buffer = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); + const buffer = Buffer.from([ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + ]); strictEqual(buffer.readUIntLE(0, 1), 0x01); strictEqual(buffer.readUIntBE(0, 1), 0x01); @@ -4250,60 +4432,51 @@ export const readUint = { // Check byteLength. ['readUIntBE', 'readUIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((len) => { - throws( - () => buffer[fn](0, len), - { name: 'RangeError' }); - }); + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (len) => { + throws(() => buffer[fn](0, len), { name: 'RangeError' }); + } + ); [Infinity, -1].forEach((byteLength) => { - throws( - () => buffer[fn](0, byteLength), - { - name: 'RangeError', - }); + throws(() => buffer[fn](0, byteLength), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((byteLength) => { - throws( - () => buffer[fn](0, byteLength), - { - name: 'RangeError', - }); + throws(() => buffer[fn](0, byteLength), { + name: 'RangeError', + }); }); }); // Test 1 to 6 bytes. for (let i = 1; i <= 6; i++) { ['readUIntBE', 'readUIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => { - throws( - () => buffer[fn](o, i), - { - name: 'TypeError' + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (o) => { + throws(() => buffer[fn](o, i), { + name: 'TypeError', }); - }); + } + ); [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => buffer[fn](offset, i), - { - name: 'RangeError', - }); + throws(() => buffer[fn](offset, i), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](offset, i), - { - name: 'RangeError', - }); + throws(() => buffer[fn](offset, i), { + name: 'RangeError', + }); }); }); } } - - } + }, }; export const sharedArrayBuffer = { @@ -4330,7 +4503,7 @@ export const sharedArrayBuffer = { strictEqual(Buffer.byteLength(sab), sab.byteLength); Buffer.from({ buffer: sab }); // Should not throw. - } + }, }; export const slice = { @@ -4394,8 +4567,10 @@ export const slice = { { // Single argument slice - strictEqual(Buffer.from('abcde', 'utf8').slice(1).toString('utf8'), - 'bcde'); + strictEqual( + Buffer.from('abcde', 'utf8').slice(1).toString('utf8'), + 'bcde' + ); } // slice(0,0).length === 0 @@ -4405,16 +4580,15 @@ export const slice = { // Regression tests for https://github.com/nodejs/node/issues/9096 const buf = Buffer.from('abcd', 'utf8'); strictEqual(buf.slice(buf.length / 3).toString('utf8'), 'bcd'); - strictEqual( - buf.slice(buf.length / 3, buf.length).toString(), - 'bcd' - ); + strictEqual(buf.slice(buf.length / 3, buf.length).toString(), 'bcd'); } { const buf = Buffer.from('abcdefg', 'utf8'); - strictEqual(buf.slice(-(-1 >>> 0) - 1).toString('utf8'), - buf.toString('utf8')); + strictEqual( + buf.slice(-(-1 >>> 0) - 1).toString('utf8'), + buf.toString('utf8') + ); } { @@ -4424,8 +4598,8 @@ export const slice = { { const buf = Buffer.from([ - 1, 29, 0, 0, 1, 143, 216, 162, 92, 254, 248, 63, 0, - 0, 0, 18, 184, 6, 0, 175, 29, 0, 8, 11, 1, 0, 0, + 1, 29, 0, 0, 1, 143, 216, 162, 92, 254, 248, 63, 0, 0, 0, 18, 184, 6, 0, + 175, 29, 0, 8, 11, 1, 0, 0, ]); const chunk1 = Buffer.from([ 1, 29, 0, 0, 1, 143, 216, 162, 92, 254, 248, 63, 0, @@ -4438,32 +4612,46 @@ export const slice = { deepStrictEqual(buf.slice(0, middle), chunk1); deepStrictEqual(buf.slice(middle), chunk2); } - } + }, }; export const swap = { test(ctrl, env, ctx) { // Test buffers small enough to use the JS implementation { - const buf = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); + const buf = Buffer.from([ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, + ]); strictEqual(buf, buf.swap16()); - deepStrictEqual(buf, Buffer.from([0x02, 0x01, 0x04, 0x03, 0x06, 0x05, - 0x08, 0x07, 0x0a, 0x09, 0x0c, 0x0b, - 0x0e, 0x0d, 0x10, 0x0f])); + deepStrictEqual( + buf, + Buffer.from([ + 0x02, 0x01, 0x04, 0x03, 0x06, 0x05, 0x08, 0x07, 0x0a, 0x09, 0x0c, + 0x0b, 0x0e, 0x0d, 0x10, 0x0f, + ]) + ); buf.swap16(); // restore strictEqual(buf, buf.swap32()); - deepStrictEqual(buf, Buffer.from([0x04, 0x03, 0x02, 0x01, 0x08, 0x07, - 0x06, 0x05, 0x0c, 0x0b, 0x0a, 0x09, - 0x10, 0x0f, 0x0e, 0x0d])); + deepStrictEqual( + buf, + Buffer.from([ + 0x04, 0x03, 0x02, 0x01, 0x08, 0x07, 0x06, 0x05, 0x0c, 0x0b, 0x0a, + 0x09, 0x10, 0x0f, 0x0e, 0x0d, + ]) + ); buf.swap32(); // restore strictEqual(buf, buf.swap64()); - deepStrictEqual(buf, Buffer.from([0x08, 0x07, 0x06, 0x05, 0x04, 0x03, - 0x02, 0x01, 0x10, 0x0f, 0x0e, 0x0d, - 0x0c, 0x0b, 0x0a, 0x09])); + deepStrictEqual( + buf, + Buffer.from([ + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, + ]) + ); } // Operates in-place @@ -4489,19 +4677,22 @@ export const swap = { } { - const buf = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); + const buf = Buffer.from([ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + ]); buf.slice(2, 18).swap64(); - deepStrictEqual(buf, Buffer.from([0x01, 0x02, 0x0a, 0x09, 0x08, 0x07, - 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, - 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10])); + deepStrictEqual( + buf, + Buffer.from([ + 0x01, 0x02, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, + 0x01, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + ]) + ); } // Force use of native code (Buffer size above threshold limit for js impl) @@ -4509,7 +4700,10 @@ export const swap = { const bufData = new Uint32Array(256).fill(0x04030201); const buf = Buffer.from(bufData.buffer, bufData.byteOffset); const otherBufData = new Uint32Array(256).fill(0x03040102); - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); buf.swap16(); deepStrictEqual(buf, otherBuf); } @@ -4518,7 +4712,10 @@ export const swap = { const bufData = new Uint32Array(256).fill(0x04030201); const buf = Buffer.from(bufData.buffer); const otherBufData = new Uint32Array(256).fill(0x01020304); - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); buf.swap32(); deepStrictEqual(buf, otherBuf); } @@ -4531,7 +4728,10 @@ export const swap = { otherBufData[otherBufData.length - i - 1] = i % 8; } const buf = Buffer.from(bufData.buffer, bufData.byteOffset); - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); buf.swap64(); deepStrictEqual(buf, otherBuf); } @@ -4548,7 +4748,10 @@ export const swap = { } const buf = Buffer.from(bufData.buffer, bufData.byteOffset); // 0|1 0|1 0|1... - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); // 0|0 1|0 1|0... buf.slice(1, buf.length - 1).swap16(); @@ -4566,7 +4769,10 @@ export const swap = { } const buf = Buffer.from(bufData.buffer, bufData.byteOffset); // 0|1 2 3 0|1 2 3... - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); // 0|0 3 2 1|0 3 2... buf.slice(1, buf.length - 3).swap32(); @@ -4584,22 +4790,29 @@ export const swap = { } const buf = Buffer.from(bufData.buffer, bufData.byteOffset); // 0|1 2 3 4 5 6 7 0|1 2 3 4... - const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset); + const otherBuf = Buffer.from( + otherBufData.buffer, + otherBufData.byteOffset + ); // 0|0 7 6 5 4 3 2 1|0 7 6 5... buf.slice(1, buf.length - 7).swap64(); deepStrictEqual(buf.slice(0, otherBuf.length), otherBuf); } - } + }, }; export const json = { test(ctrl, env, ctx) { { - strictEqual(JSON.stringify(Buffer.alloc(0)), - '{"type":"Buffer","data":[]}'); - strictEqual(JSON.stringify(Buffer.from([1, 2, 3, 4])), - '{"type":"Buffer","data":[1,2,3,4]}'); + strictEqual( + JSON.stringify(Buffer.alloc(0)), + '{"type":"Buffer","data":[]}' + ); + strictEqual( + JSON.stringify(Buffer.from([1, 2, 3, 4])), + '{"type":"Buffer","data":[1,2,3,4]}' + ); } // issue GH-7849 @@ -4620,39 +4833,40 @@ export const json = { strictEqual(string, '{"type":"Buffer","data":[116,101,115,116]}'); function receiver(key, value) { - return value && value.type === 'Buffer' ? Buffer.from(value.data) : value; + return value && value.type === 'Buffer' + ? Buffer.from(value.data) + : value; } deepStrictEqual(buffer, JSON.parse(string, receiver)); } - } + }, }; export const writeUint8 = { test(ctrl, env, ctx) { - { // OOB + { + // OOB const data = Buffer.alloc(8); - ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach((fn) => { - - // Verify that default offset works fine. - data[`write${fn}`](23, undefined); - data[`write${fn}`](23); + ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach( + (fn) => { + // Verify that default offset works fine. + data[`write${fn}`](23, undefined); + data[`write${fn}`](23); - ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { - throws( - () => data[`write${fn}`](23, o), - { name: 'TypeError' }); - }); + ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { + throws(() => data[`write${fn}`](23, o), { name: 'TypeError' }); + }); - [NaN, Infinity, -1, 1.01].forEach((o) => { - throws( - () => data[`write${fn}`](23, o), - { name: 'RangeError' }); - }); - }); + [NaN, Infinity, -1, 1.01].forEach((o) => { + throws(() => data[`write${fn}`](23, o), { name: 'RangeError' }); + }); + } + ); } - { // Test 8 bit + { + // Test 8 bit const data = Buffer.alloc(4); data.writeUInt8(23, 0); @@ -4706,12 +4920,9 @@ export const writeUint8 = { value = 0xfffff; ['writeUInt16BE', 'writeUInt16LE'].forEach((fn) => { - throws( - () => data[fn](value, 0), - { - name: 'RangeError', - } - ); + throws(() => data[fn](value, 0), { + name: 'RangeError', + }); }); } @@ -4757,65 +4968,56 @@ export const writeUint8 = { // Check byteLength. ['writeUIntBE', 'writeUIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((bl) => { - throws( - () => data[fn](23, 0, bl), - { name: 'RangeError' }); - }); + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (bl) => { + throws(() => data[fn](23, 0, bl), { name: 'RangeError' }); + } + ); [Infinity, -1].forEach((byteLength) => { - throws( - () => data[fn](23, 0, byteLength), - { - name: 'RangeError', - } - ); + throws(() => data[fn](23, 0, byteLength), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((byteLength) => { - throws( - () => data[fn](42, 0, byteLength), - { - name: 'RangeError', - }); + throws(() => data[fn](42, 0, byteLength), { + name: 'RangeError', + }); }); }); // Test 1 to 6 bytes. for (let i = 1; i <= 6; i++) { const range = i < 5 ? `= ${val - 1}` : ` 2 ** ${i * 8}`; - const received = i > 4 ? - String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') : - val; + const received = + i > 4 ? String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') : val; ['writeUIntBE', 'writeUIntLE'].forEach((fn) => { - throws(() => { - data[fn](val, 0, i); - }, { - name: 'RangeError', - }); + throws( + () => { + data[fn](val, 0, i); + }, + { + name: 'RangeError', + } + ); ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { - throws( - () => data[fn](23, o, i), - { - name: 'TypeError' - }); + throws(() => data[fn](23, o, i), { + name: 'TypeError', + }); }); [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => data[fn](val - 1, offset, i), - { - name: 'RangeError', - }); + throws(() => data[fn](val - 1, offset, i), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => data[fn](val - 1, offset, i), - { - name: 'RangeError', - }); + throws(() => data[fn](val - 1, offset, i), { + name: 'RangeError', + }); }); }); @@ -4824,15 +5026,22 @@ export const writeUint8 = { } for (const fn of [ - 'UInt8', 'UInt16LE', 'UInt16BE', 'UInt32LE', 'UInt32BE', 'UIntLE', 'UIntBE', - 'BigUInt64LE', 'BigUInt64BE', + 'UInt8', + 'UInt16LE', + 'UInt16BE', + 'UInt32LE', + 'UInt32BE', + 'UIntLE', + 'UIntBE', + 'BigUInt64LE', + 'BigUInt64BE', ]) { const p = Buffer.prototype; const lowerFn = fn.replace(/UInt/, 'Uint'); strictEqual(p[`write${fn}`], p[`write${lowerFn}`]); strictEqual(p[`read${fn}`], p[`read${lowerFn}`]); } - } + }, }; export const writeInt = { @@ -4847,12 +5056,12 @@ export const writeInt = { buffer.writeInt8(0x23, 0); buffer.writeInt8(-5, 1); - ok(buffer.equals(new Uint8Array([ 0x23, 0xfb ]))); + ok(buffer.equals(new Uint8Array([0x23, 0xfb]))); /* Make sure we handle min/max correctly */ buffer.writeInt8(0x7f, 0); buffer.writeInt8(-0x80, 1); - ok(buffer.equals(new Uint8Array([ 0x7f, 0x80 ]))); + ok(buffer.equals(new Uint8Array([0x7f, 0x80]))); throws(() => { buffer.writeInt8(0x7f + 1, 0); @@ -4866,15 +5075,11 @@ export const writeInt = { buffer.writeInt8(23); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => buffer.writeInt8(23, off), - { name: 'TypeError' }); + throws(() => buffer.writeInt8(23, off), { name: 'TypeError' }); }); [NaN, Infinity, -1, 1.01].forEach((off) => { - throws( - () => buffer.writeInt8(23, off), - { name: 'RangeError' }); + throws(() => buffer.writeInt8(23, off), { name: 'RangeError' }); }); } @@ -4884,27 +5089,26 @@ export const writeInt = { buffer.writeInt16BE(0x0023, 0); buffer.writeInt16LE(0x0023, 2); - ok(buffer.equals(new Uint8Array([ 0x00, 0x23, 0x23, 0x00 ]))); + ok(buffer.equals(new Uint8Array([0x00, 0x23, 0x23, 0x00]))); buffer.writeInt16BE(-5, 0); buffer.writeInt16LE(-5, 2); - ok(buffer.equals(new Uint8Array([ 0xff, 0xfb, 0xfb, 0xff ]))); + ok(buffer.equals(new Uint8Array([0xff, 0xfb, 0xfb, 0xff]))); buffer.writeInt16BE(-1679, 0); buffer.writeInt16LE(-1679, 2); - ok(buffer.equals(new Uint8Array([ 0xf9, 0x71, 0x71, 0xf9 ]))); + ok(buffer.equals(new Uint8Array([0xf9, 0x71, 0x71, 0xf9]))); /* Make sure we handle min/max correctly */ buffer.writeInt16BE(0x7fff, 0); buffer.writeInt16BE(-0x8000, 2); - ok(buffer.equals(new Uint8Array([ 0x7f, 0xff, 0x80, 0x00 ]))); + ok(buffer.equals(new Uint8Array([0x7f, 0xff, 0x80, 0x00]))); buffer.writeInt16LE(0x7fff, 0); buffer.writeInt16LE(-0x8000, 2); - ok(buffer.equals(new Uint8Array([ 0xff, 0x7f, 0x00, 0x80 ]))); + ok(buffer.equals(new Uint8Array([0xff, 0x7f, 0x00, 0x80]))); ['writeInt16BE', 'writeInt16LE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](23, undefined); buffer[fn](23); @@ -4917,15 +5121,11 @@ export const writeInt = { }, errorOutOfBounds); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => buffer[fn](23, off), - { code: 'ERR_INVALID_ARG_TYPE' }); + throws(() => buffer[fn](23, off), { code: 'ERR_INVALID_ARG_TYPE' }); }); [NaN, Infinity, -1, 1.01].forEach((off) => { - throws( - () => buffer[fn](23, off), - { code: 'ERR_OUT_OF_RANGE' }); + throws(() => buffer[fn](23, off), { code: 'ERR_OUT_OF_RANGE' }); }); }); } @@ -4936,37 +5136,46 @@ export const writeInt = { buffer.writeInt32BE(0x23, 0); buffer.writeInt32LE(0x23, 4); - ok(buffer.equals(new Uint8Array([ - 0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00, - ]))); + ok( + buffer.equals( + new Uint8Array([0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00]) + ) + ); buffer.writeInt32BE(-5, 0); buffer.writeInt32LE(-5, 4); - ok(buffer.equals(new Uint8Array([ - 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xff, 0xff, 0xff, - ]))); + ok( + buffer.equals( + new Uint8Array([0xff, 0xff, 0xff, 0xfb, 0xfb, 0xff, 0xff, 0xff]) + ) + ); buffer.writeInt32BE(-805306713, 0); buffer.writeInt32LE(-805306713, 4); - ok(buffer.equals(new Uint8Array([ - 0xcf, 0xff, 0xfe, 0xa7, 0xa7, 0xfe, 0xff, 0xcf, - ]))); + ok( + buffer.equals( + new Uint8Array([0xcf, 0xff, 0xfe, 0xa7, 0xa7, 0xfe, 0xff, 0xcf]) + ) + ); /* Make sure we handle min/max correctly */ buffer.writeInt32BE(0x7fffffff, 0); buffer.writeInt32BE(-0x80000000, 4); - ok(buffer.equals(new Uint8Array([ - 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, - ]))); + ok( + buffer.equals( + new Uint8Array([0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00]) + ) + ); buffer.writeInt32LE(0x7fffffff, 0); buffer.writeInt32LE(-0x80000000, 4); - ok(buffer.equals(new Uint8Array([ - 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x80, - ]))); + ok( + buffer.equals( + new Uint8Array([0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x80]) + ) + ); ['writeInt32BE', 'writeInt32LE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](23, undefined); buffer[fn](23); @@ -4979,15 +5188,11 @@ export const writeInt = { }, errorOutOfBounds); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => buffer[fn](23, off), - { code: 'ERR_INVALID_ARG_TYPE' }); + throws(() => buffer[fn](23, off), { code: 'ERR_INVALID_ARG_TYPE' }); }); [NaN, Infinity, -1, 1.01].forEach((off) => { - throws( - () => buffer[fn](23, off), - { code: 'ERR_OUT_OF_RANGE' }); + throws(() => buffer[fn](23, off), { code: 'ERR_OUT_OF_RANGE' }); }); }); } @@ -4997,14 +5202,10 @@ export const writeInt = { const value = 0x1234567890ab; const buffer = Buffer.allocUnsafe(6); buffer.writeIntBE(value, 0, 6); - ok(buffer.equals(new Uint8Array([ - 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, - ]))); + ok(buffer.equals(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]))); buffer.writeIntLE(value, 0, 6); - ok(buffer.equals(new Uint8Array([ - 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, - ]))); + ok(buffer.equals(new Uint8Array([0xab, 0x90, 0x78, 0x56, 0x34, 0x12]))); } // Test Int @@ -5013,27 +5214,22 @@ export const writeInt = { // Check byteLength. ['writeIntBE', 'writeIntLE'].forEach((fn) => { - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((bl) => { - throws( - () => data[fn](23, 0, bl), - { name: 'RangeError' }); - }); + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (bl) => { + throws(() => data[fn](23, 0, bl), { name: 'RangeError' }); + } + ); [Infinity, -1].forEach((byteLength) => { - throws( - () => data[fn](23, 0, byteLength), - { - name: 'RangeError', - } - ); + throws(() => data[fn](23, 0, byteLength), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((byteLength) => { - throws( - () => data[fn](42, 0, byteLength), - { - name: 'RangeError', - }); + throws(() => data[fn](42, 0, byteLength), { + name: 'RangeError', + }); }); }); @@ -5047,43 +5243,43 @@ export const writeInt = { range = `>= -(2 ** ${i * 8 - 1}) and < 2 ** ${i * 8 - 1}`; } [min - 1, max + 1].forEach((val) => { - const received = i > 4 ? - String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') : - val; - throws(() => { - data[fn](val, 0, i); - }, { - name: 'RangeError', - }); - }); - - ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => { + const received = + i > 4 + ? String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') + : val; throws( - () => data[fn](min, o, i), + () => { + data[fn](val, 0, i); + }, { - name: 'TypeError' - }); + name: 'RangeError', + } + ); }); - [Infinity, -1, -4294967295].forEach((offset) => { - throws( - () => data[fn](min, offset, i), - { - name: 'RangeError', + ['', '0', null, {}, [], () => {}, true, false, undefined].forEach( + (o) => { + throws(() => data[fn](min, o, i), { + name: 'TypeError', }); + } + ); + + [Infinity, -1, -4294967295].forEach((offset) => { + throws(() => data[fn](min, offset, i), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => data[fn](max, offset, i), - { - name: 'RangeError', - }); + throws(() => data[fn](max, offset, i), { + name: 'RangeError', + }); }); }); } } - } + }, }; export const writeFloat = { @@ -5092,41 +5288,62 @@ export const writeFloat = { buffer.writeFloatBE(1, 0); buffer.writeFloatLE(1, 4); - ok(buffer.equals( - new Uint8Array([ 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f ]))); + ok( + buffer.equals( + new Uint8Array([0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f]) + ) + ); buffer.writeFloatBE(1 / 3, 0); buffer.writeFloatLE(1 / 3, 4); - ok(buffer.equals( - new Uint8Array([ 0x3e, 0xaa, 0xaa, 0xab, 0xab, 0xaa, 0xaa, 0x3e ]))); + ok( + buffer.equals( + new Uint8Array([0x3e, 0xaa, 0xaa, 0xab, 0xab, 0xaa, 0xaa, 0x3e]) + ) + ); - buffer.writeFloatBE(3.4028234663852886e+38, 0); - buffer.writeFloatLE(3.4028234663852886e+38, 4); - ok(buffer.equals( - new Uint8Array([ 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f ]))); + buffer.writeFloatBE(3.4028234663852886e38, 0); + buffer.writeFloatLE(3.4028234663852886e38, 4); + ok( + buffer.equals( + new Uint8Array([0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f]) + ) + ); buffer.writeFloatLE(1.1754943508222875e-38, 0); buffer.writeFloatBE(1.1754943508222875e-38, 4); - ok(buffer.equals( - new Uint8Array([ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00 ]))); + ok( + buffer.equals( + new Uint8Array([0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00]) + ) + ); buffer.writeFloatBE(0 * -1, 0); buffer.writeFloatLE(0 * -1, 4); - ok(buffer.equals( - new Uint8Array([ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 ]))); + ok( + buffer.equals( + new Uint8Array([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]) + ) + ); buffer.writeFloatBE(Infinity, 0); buffer.writeFloatLE(Infinity, 4); - ok(buffer.equals( - new Uint8Array([ 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F ]))); + ok( + buffer.equals( + new Uint8Array([0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f]) + ) + ); strictEqual(buffer.readFloatBE(0), Infinity); strictEqual(buffer.readFloatLE(4), Infinity); buffer.writeFloatBE(-Infinity, 0); buffer.writeFloatLE(-Infinity, 4); - ok(buffer.equals( - new Uint8Array([ 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF ]))); + ok( + buffer.equals( + new Uint8Array([0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff]) + ) + ); strictEqual(buffer.readFloatBE(0), -Infinity); strictEqual(buffer.readFloatLE(4), -Infinity); @@ -5136,14 +5353,18 @@ export const writeFloat = { // JS only knows a single NaN but there exist two platform specific // implementations. Therefore, allow both quiet and signalling NaNs. - if (buffer[1] === 0xBF) { + if (buffer[1] === 0xbf) { ok( - buffer.equals(new Uint8Array( - [ 0x7F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F ]))); + buffer.equals( + new Uint8Array([0x7f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x7f]) + ) + ); } else { ok( - buffer.equals(new Uint8Array( - [ 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F ]))); + buffer.equals( + new Uint8Array([0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f]) + ) + ); } ok(Number.isNaN(buffer.readFloatBE(0))); @@ -5154,44 +5375,32 @@ export const writeFloat = { const small = Buffer.allocUnsafe(1); ['writeFloatLE', 'writeFloatBE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](23, undefined); buffer[fn](23); - throws( - () => small[fn](11.11, 0), - { - name: 'RangeError', - }); + throws(() => small[fn](11.11, 0), { + name: 'RangeError', + }); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => small[fn](23, off), - { name: 'TypeError' } - ); + throws(() => small[fn](23, off), { name: 'TypeError' }); }); [Infinity, -1, 5].forEach((offset) => { - throws( - () => buffer[fn](23, offset), - { - name: 'RangeError', - } - ); + throws(() => buffer[fn](23, offset), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](42, offset), - { - name: 'RangeError', - }); + throws(() => buffer[fn](42, offset), { + name: 'RangeError', + }); }); }); } - - } + }, }; export const writeDouble = { @@ -5200,46 +5409,70 @@ export const writeDouble = { buffer.writeDoubleBE(2.225073858507201e-308, 0); buffer.writeDoubleLE(2.225073858507201e-308, 8); - ok(buffer.equals(new Uint8Array([ - 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x00, + ]) + ) + ); buffer.writeDoubleBE(1.0000000000000004, 0); buffer.writeDoubleLE(1.0000000000000004, 8); - ok(buffer.equals(new Uint8Array([ - 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x3f, + ]) + ) + ); buffer.writeDoubleBE(-2, 0); buffer.writeDoubleLE(-2, 8); - ok(buffer.equals(new Uint8Array([ - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, - ]))); - - buffer.writeDoubleBE(1.7976931348623157e+308, 0); - buffer.writeDoubleLE(1.7976931348623157e+308, 8); - ok(buffer.equals(new Uint8Array([ - 0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x7f, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, + ]) + ) + ); + + buffer.writeDoubleBE(1.7976931348623157e308, 0); + buffer.writeDoubleLE(1.7976931348623157e308, 8); + ok( + buffer.equals( + new Uint8Array([ + 0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xef, 0x7f, + ]) + ) + ); buffer.writeDoubleBE(0 * -1, 0); buffer.writeDoubleLE(0 * -1, 8); - ok(buffer.equals(new Uint8Array([ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, + ]) + ) + ); buffer.writeDoubleBE(Infinity, 0); buffer.writeDoubleLE(Infinity, 8); - ok(buffer.equals(new Uint8Array([ - 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7F, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x7f, + ]) + ) + ); strictEqual(buffer.readDoubleBE(0), Infinity); strictEqual(buffer.readDoubleLE(8), Infinity); @@ -5247,10 +5480,14 @@ export const writeDouble = { buffer.writeDoubleBE(-Infinity, 0); buffer.writeDoubleLE(-Infinity, 8); - ok(buffer.equals(new Uint8Array([ - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, + ]) + ) + ); strictEqual(buffer.readDoubleBE(0), -Infinity); strictEqual(buffer.readDoubleLE(8), -Infinity); @@ -5260,16 +5497,24 @@ export const writeDouble = { // JS only knows a single NaN but there exist two platform specific // implementations. Therefore, allow both quiet and signalling NaNs. - if (buffer[1] === 0xF7) { - ok(buffer.equals(new Uint8Array([ - 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7F, - ]))); + if (buffer[1] === 0xf7) { + ok( + buffer.equals( + new Uint8Array([ + 0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf7, 0x7f, + ]) + ) + ); } else { - ok(buffer.equals(new Uint8Array([ - 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, - ]))); + ok( + buffer.equals( + new Uint8Array([ + 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x7f, + ]) + ) + ); } ok(Number.isNaN(buffer.readDoubleBE(0))); @@ -5280,55 +5525,42 @@ export const writeDouble = { const small = Buffer.allocUnsafe(1); ['writeDoubleLE', 'writeDoubleBE'].forEach((fn) => { - // Verify that default offset works fine. buffer[fn](23, undefined); buffer[fn](23); - throws( - () => small[fn](11.11, 0), - { - code: 'ERR_BUFFER_OUT_OF_BOUNDS', - name: 'RangeError', - message: 'Attempt to access memory outside buffer bounds' - }); + throws(() => small[fn](11.11, 0), { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: 'Attempt to access memory outside buffer bounds', + }); ['', '0', null, {}, [], () => {}, true, false].forEach((off) => { - throws( - () => small[fn](23, off), - { name: 'TypeError' }); + throws(() => small[fn](23, off), { name: 'TypeError' }); }); [Infinity, -1, 9].forEach((offset) => { - throws( - () => buffer[fn](23, offset), - { - name: 'RangeError', - }); + throws(() => buffer[fn](23, offset), { + name: 'RangeError', + }); }); [NaN, 1.01].forEach((offset) => { - throws( - () => buffer[fn](42, offset), - { - name: 'RangeError', - }); + throws(() => buffer[fn](42, offset), { + name: 'RangeError', + }); }); }); } - - } + }, }; export const write = { test(ctrl, env, ctx) { [-1, 10].forEach((offset) => { - throws( - () => Buffer.alloc(9).write('foo', offset), - { - name: 'RangeError', - } - ); + throws(() => Buffer.alloc(9).write('foo', offset), { + name: 'RangeError', + }); }); const resultMap = new Map([ @@ -5344,8 +5576,17 @@ export const write = { ]); // utf8, ucs2, ascii, latin1, utf16le - const encodings = ['utf8', 'utf-8', 'ascii', 'latin1', - 'binary', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le']; + const encodings = [ + 'utf8', + 'utf-8', + 'ascii', + 'latin1', + 'binary', + 'ucs2', + 'ucs-2', + 'utf16le', + 'utf-16le', + ]; encodings .reduce((es, e) => es.concat(e, e.toUpperCase()), []) @@ -5354,8 +5595,7 @@ export const write = { const len = Buffer.byteLength('foo', encoding); strictEqual(buf.write('foo', 0, len, encoding), len); - if (encoding.includes('-')) - encoding = encoding.replace('-', ''); + if (encoding.includes('-')) encoding = encoding.replace('-', ''); deepStrictEqual(buf, resultMap.get(encoding.toLowerCase())); }); @@ -5410,8 +5650,7 @@ export const write = { deepStrictEqual([...z], [0, 0, 0x61, 0x62]); // Large overrun could corrupt the process - strictEqual(Buffer.alloc(4) - .write('ыыыыыы'.repeat(100), 3, 'utf16le'), 0); + strictEqual(Buffer.alloc(4).write('ыыыыыы'.repeat(100), 3, 'utf16le'), 0); { // .write() does not affect the byte after the written-to slice of the Buffer. @@ -5420,15 +5659,23 @@ export const write = { strictEqual(buf.write('ыы', 1, 'utf16le'), 4); deepStrictEqual([...buf], [0, 0x4b, 0x04, 0x4b, 0x04, 0, 0, 0]); } - - } + }, }; export const toString = { test(ctrl, env, ctx) { // utf8, ucs2, ascii, latin1, utf16le - const encodings = ['utf8', 'utf-8', 'ucs2', 'ucs-2', 'ascii', 'latin1', - 'binary', 'utf16le', 'utf-16le']; + const encodings = [ + 'utf8', + 'utf-8', + 'ucs2', + 'ucs-2', + 'ascii', + 'latin1', + 'binary', + 'utf16le', + 'utf-16le', + ]; encodings .reduce((es, e) => es.concat(e, e.toUpperCase()), []) @@ -5443,8 +5690,7 @@ export const toString = { // hex ['hex', 'HEX'].forEach((encoding) => { - strictEqual(Buffer.from('666f6f', encoding).toString(encoding), - '666f6f'); + strictEqual(Buffer.from('666f6f', encoding).toString(encoding), '666f6f'); }); // Invalid encodings @@ -5453,14 +5699,13 @@ export const toString = { const error = { code: 'ERR_UNKNOWN_ENCODING', name: 'TypeError', - message: `Unknown encoding: ${encoding}` + message: `Unknown encoding: ${encoding}`, }; ok(!Buffer.isEncoding(encoding)); throws(() => Buffer.from('foo').toString(encoding), error); } - - } -} + }, +}; export const toStringRangeError = { test(ctrl, env, ctx) { @@ -5474,7 +5719,7 @@ export const toStringRangeError = { throws(() => Buffer.alloc(len).toString('utf8'), message); throws(() => Buffer.allocUnsafe(len).toString('utf8'), message); throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message); - } + }, }; export const toStringRange = { @@ -5554,23 +5799,34 @@ export const toStringRange = { strictEqual(rangeBuffer.toString('ascii', 0, true), 'a'); // Try toString() with an object as an encoding - strictEqual(rangeBuffer.toString({ toString: function() { - return 'ascii'; - } }), 'abc'); + strictEqual( + rangeBuffer.toString({ + toString: function () { + return 'ascii'; + }, + }), + 'abc' + ); // Try toString() with 0 and null as the encoding - throws(() => { - rangeBuffer.toString(0, 1, 2); - }, { - name: 'TypeError', - }); + throws( + () => { + rangeBuffer.toString(0, 1, 2); + }, + { + name: 'TypeError', + } + ); - throws(() => { - rangeBuffer.toString(null, 1, 2); - }, { - name: 'TypeError', - }); - } + throws( + () => { + rangeBuffer.toString(null, 1, 2); + }, + { + name: 'TypeError', + } + ); + }, }; export const inspect = { @@ -5582,7 +5838,8 @@ export const inspect = { let s = buffer.SlowBuffer(60); s.fill('0123456789'.repeat(6)); - let expected = ''; + let expected = + ''; strictEqual(util.inspect(b), expected); strictEqual(util.inspect(s), expected); @@ -5608,11 +5865,8 @@ export const inspect = { b = Buffer.alloc(0); b.prop = 123; - strictEqual( - util.inspect(b), - '' - ); - } + strictEqual(util.inspect(b), ''); + }, }; export const isAsciiTest = { @@ -5624,19 +5878,23 @@ export const isAsciiTest = { [ undefined, - '', 'hello', - false, true, - 0, 1, - 0n, 1n, + '', + 'hello', + false, + true, + 0, + 1, + 0n, + 1n, Symbol(), () => {}, - {}, [], null, + {}, + [], + null, ].forEach((input) => { - throws( - () => isAscii(input), - ); + throws(() => isAscii(input)); }); - } + }, }; export const isUtf8Test = { @@ -5649,63 +5907,55 @@ export const isUtf8Test = { // Taken from test/fixtures/wpt/encoding/textdecoder-fatal.any.js [ - [0xFF], // 'invalid code' - [0xC0], // 'ends early' - [0xE0], // 'ends early 2' - [0xC0, 0x00], // 'invalid trail' - [0xC0, 0xC0], // 'invalid trail 2' - [0xE0, 0x00], // 'invalid trail 3' - [0xE0, 0xC0], // 'invalid trail 4' - [0xE0, 0x80, 0x00], // 'invalid trail 5' - [0xE0, 0x80, 0xC0], // 'invalid trail 6' - [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], // '> 0x10FFFF' - [0xFE, 0x80, 0x80, 0x80, 0x80, 0x80], // 'obsolete lead byte' + [0xff], // 'invalid code' + [0xc0], // 'ends early' + [0xe0], // 'ends early 2' + [0xc0, 0x00], // 'invalid trail' + [0xc0, 0xc0], // 'invalid trail 2' + [0xe0, 0x00], // 'invalid trail 3' + [0xe0, 0xc0], // 'invalid trail 4' + [0xe0, 0x80, 0x00], // 'invalid trail 5' + [0xe0, 0x80, 0xc0], // 'invalid trail 6' + [0xfc, 0x80, 0x80, 0x80, 0x80, 0x80], // '> 0x10FFFF' + [0xfe, 0x80, 0x80, 0x80, 0x80, 0x80], // 'obsolete lead byte' // Overlong encodings - [0xC0, 0x80], // 'overlong U+0000 - 2 bytes' - [0xE0, 0x80, 0x80], // 'overlong U+0000 - 3 bytes' - [0xF0, 0x80, 0x80, 0x80], // 'overlong U+0000 - 4 bytes' - [0xF8, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 5 bytes' - [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 6 bytes' - - [0xC1, 0xBF], // 'overlong U+007F - 2 bytes' - [0xE0, 0x81, 0xBF], // 'overlong U+007F - 3 bytes' - [0xF0, 0x80, 0x81, 0xBF], // 'overlong U+007F - 4 bytes' - [0xF8, 0x80, 0x80, 0x81, 0xBF], // 'overlong U+007F - 5 bytes' - [0xFC, 0x80, 0x80, 0x80, 0x81, 0xBF], // 'overlong U+007F - 6 bytes' - - [0xE0, 0x9F, 0xBF], // 'overlong U+07FF - 3 bytes' - [0xF0, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 4 bytes' - [0xF8, 0x80, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 5 bytes' - [0xFC, 0x80, 0x80, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 6 bytes' - - [0xF0, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 4 bytes' - [0xF8, 0x80, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 5 bytes' - [0xFC, 0x80, 0x80, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 6 bytes' - - [0xF8, 0x84, 0x8F, 0xBF, 0xBF], // 'overlong U+10FFFF - 5 bytes' - [0xFC, 0x80, 0x84, 0x8F, 0xBF, 0xBF], // 'overlong U+10FFFF - 6 bytes' + [0xc0, 0x80], // 'overlong U+0000 - 2 bytes' + [0xe0, 0x80, 0x80], // 'overlong U+0000 - 3 bytes' + [0xf0, 0x80, 0x80, 0x80], // 'overlong U+0000 - 4 bytes' + [0xf8, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 5 bytes' + [0xfc, 0x80, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 6 bytes' + + [0xc1, 0xbf], // 'overlong U+007F - 2 bytes' + [0xe0, 0x81, 0xbf], // 'overlong U+007F - 3 bytes' + [0xf0, 0x80, 0x81, 0xbf], // 'overlong U+007F - 4 bytes' + [0xf8, 0x80, 0x80, 0x81, 0xbf], // 'overlong U+007F - 5 bytes' + [0xfc, 0x80, 0x80, 0x80, 0x81, 0xbf], // 'overlong U+007F - 6 bytes' + + [0xe0, 0x9f, 0xbf], // 'overlong U+07FF - 3 bytes' + [0xf0, 0x80, 0x9f, 0xbf], // 'overlong U+07FF - 4 bytes' + [0xf8, 0x80, 0x80, 0x9f, 0xbf], // 'overlong U+07FF - 5 bytes' + [0xfc, 0x80, 0x80, 0x80, 0x9f, 0xbf], // 'overlong U+07FF - 6 bytes' + + [0xf0, 0x8f, 0xbf, 0xbf], // 'overlong U+FFFF - 4 bytes' + [0xf8, 0x80, 0x8f, 0xbf, 0xbf], // 'overlong U+FFFF - 5 bytes' + [0xfc, 0x80, 0x80, 0x8f, 0xbf, 0xbf], // 'overlong U+FFFF - 6 bytes' + + [0xf8, 0x84, 0x8f, 0xbf, 0xbf], // 'overlong U+10FFFF - 5 bytes' + [0xfc, 0x80, 0x84, 0x8f, 0xbf, 0xbf], // 'overlong U+10FFFF - 6 bytes' // UTF-16 surrogates encoded as code points in UTF-8 - [0xED, 0xA0, 0x80], // 'lead surrogate' - [0xED, 0xB0, 0x80], // 'trail surrogate' - [0xED, 0xA0, 0x80, 0xED, 0xB0, 0x80], // 'surrogate pair' + [0xed, 0xa0, 0x80], // 'lead surrogate' + [0xed, 0xb0, 0x80], // 'trail surrogate' + [0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80], // 'surrogate pair' ].forEach((input) => { strictEqual(isUtf8(Buffer.from(input)), false); }); - [ - null, - undefined, - 'hello', - true, - false, - ].forEach((input) => { - throws( - () => isUtf8(input), - ); + [null, undefined, 'hello', true, false].forEach((input) => { + throws(() => isUtf8(input)); }); - } + }, }; // Adapted from test/parallel/test-icu-transcode.js @@ -5713,11 +5963,11 @@ export const transcodeTest = { test(ctrl, env, ctx) { const orig = Buffer.from('těst ☕', 'utf8'); const tests = { - 'latin1': [0x74, 0x3f, 0x73, 0x74, 0x20, 0x3f], - 'ascii': [0x74, 0x3f, 0x73, 0x74, 0x20, 0x3f], - 'ucs2': [0x74, 0x00, 0x1b, 0x01, 0x73, - 0x00, 0x74, 0x00, 0x20, 0x00, - 0x15, 0x26] + latin1: [0x74, 0x3f, 0x73, 0x74, 0x20, 0x3f], + ascii: [0x74, 0x3f, 0x73, 0x74, 0x20, 0x3f], + ucs2: [ + 0x74, 0x00, 0x1b, 0x01, 0x73, 0x00, 0x74, 0x00, 0x20, 0x00, 0x15, 0x26, + ], }; for (const test in tests) { @@ -5746,13 +5996,16 @@ export const transcodeTest = { { deepStrictEqual( transcode(Buffer.from('hi', 'ascii'), 'ascii', 'utf16le'), - Buffer.from('hi', 'utf16le')); + Buffer.from('hi', 'utf16le') + ); deepStrictEqual( transcode(Buffer.from('hi', 'latin1'), 'latin1', 'utf16le'), - Buffer.from('hi', 'utf16le')); + Buffer.from('hi', 'utf16le') + ); deepStrictEqual( transcode(Buffer.from('hä', 'latin1'), 'latin1', 'utf16le'), - Buffer.from('hä', 'utf16le')); + Buffer.from('hä', 'utf16le') + ); } { @@ -5765,7 +6018,8 @@ export const transcodeTest = { const uint8array = new Uint8Array([...Buffer.from('hä', 'latin1')]); deepStrictEqual( transcode(uint8array, 'latin1', 'utf16le'), - Buffer.from('hä', 'utf16le')); + Buffer.from('hä', 'utf16le') + ); } // Invalid arguments should fail @@ -5791,7 +6045,7 @@ export const transcodeTest = { ok(copied_value.buffer.detached); ok(!original.buffer.detached); } - } + }, }; // Tests are taken from Node.js @@ -5820,15 +6074,10 @@ export const fileTest = { const toPrimitive = { [Symbol.toPrimitive]() { return 'NaN'; - } + }, }; - const invalidLastModified = [ - null, - 'string', - false, - toPrimitive, - ]; + const invalidLastModified = [null, 'string', false, toPrimitive]; for (const lastModified of invalidLastModified) { const file = new File([], '', { lastModified }); @@ -5845,13 +6094,10 @@ export const fileTest = { const toPrimitive = { [Symbol.toPrimitive]() { throw new TypeError('boom'); - } + }, }; - const throwValues = [ - BigInt(3n), - toPrimitive, - ]; + const throwValues = [BigInt(3n), toPrimitive]; for (const lastModified of throwValues) { throws(() => new File([], '', { lastModified }), TypeError); @@ -5863,7 +6109,7 @@ export const fileTest = { { [Symbol.toPrimitive]() { return 10; - } + }, }, new Number(10), 10, @@ -5888,12 +6134,12 @@ export const fileTest = { get lastModified() { counter++; return 10; - } + }, }); strictEqual(counter, 1); } - } -} + }, +}; // Ref: https://github.com/cloudflare/workerd/issues/2538 export const sliceOffsetLimits = { @@ -5902,5 +6148,5 @@ export const sliceOffsetLimits = { strictEqual(Buffer.from('abcd').utf8Slice(2, 3).toString(), 'c'); // Make sure to handle (end < start) edge case. strictEqual(Buffer.from('abcd').utf8Slice(1, 0).toString(), ''); - } -} + }, +}; diff --git a/src/workerd/api/node/tests/crypto_dh-test.js b/src/workerd/api/node/tests/crypto_dh-test.js index efce7a83f5c..328d3fbf136 100644 --- a/src/workerd/api/node/tests/crypto_dh-test.js +++ b/src/workerd/api/node/tests/crypto_dh-test.js @@ -25,9 +25,7 @@ 'use strict'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; import * as assert from 'node:assert'; import * as crypto from 'node:crypto'; @@ -40,15 +38,17 @@ export const dh_test = { assert.throws(() => crypto.createDiffieHellman(13.37), { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'The value of "sizeOrKey" is out of range. ' + - 'It must be an integer. Received 13.37', + message: + 'The value of "sizeOrKey" is out of range. ' + + 'It must be an integer. Received 13.37', }); assert.throws(() => crypto.createDiffieHellman('abcdef', 13.37), { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'The value of "generator" is out of range. ' + - 'It must be an integer. Received 13.37', + message: + 'The value of "generator" is out of range. ' + + 'It must be an integer. Received 13.37', }); for (const bits of [-1, 0, 1]) { @@ -72,11 +72,9 @@ export const dh_test = { assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex); } - crypto.createDiffieHellman('abcdef', Buffer.from([2])); // OK + crypto.createDiffieHellman('abcdef', Buffer.from([2])); // OK - for (const g of [Buffer.from([]), - Buffer.from([0]), - Buffer.from([1])]) { + for (const g of [Buffer.from([]), Buffer.from([0]), Buffer.from([1])]) { const ex = { name: 'Error', }; @@ -84,64 +82,55 @@ export const dh_test = { assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex); } - [ - [0x1, 0x2], - () => { }, - /abc/, - {}, - ].forEach((input) => { - assert.throws( - () => crypto.createDiffieHellman(input), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + [[0x1, 0x2], () => {}, /abc/, {}].forEach((input) => { + assert.throws(() => crypto.createDiffieHellman(input), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); }); assert.throws( - function() { + function () { crypto.getDiffieHellman('unknown-group'); }, { name: 'Error', }, - 'crypto.getDiffieHellman(\'unknown-group\') ' + - 'failed to throw the expected error.' + "crypto.getDiffieHellman('unknown-group') " + + 'failed to throw the expected error.' ); - assert.throws( - () => crypto.createDiffieHellman('', true), - { - code: 'ERR_INVALID_ARG_TYPE' - } - ); + assert.throws(() => crypto.createDiffieHellman('', true), { + code: 'ERR_INVALID_ARG_TYPE', + }); - [true, Symbol(), {}, () => {}, []].forEach((generator) => assert.throws( - () => crypto.createDiffieHellman('', 'base64', generator), - { name: 'TypeError' } - )); - } -} + [true, Symbol(), {}, () => {}, []].forEach((generator) => + assert.throws(() => crypto.createDiffieHellman('', 'base64', generator), { + name: 'TypeError', + }) + ); + }, +}; /////////////// export const dh_verify_error_test = { test(ctrl, env, ctx) { -// Second OAKLEY group, see -// https://github.com/nodejs/node-v0.x-archive/issues/2338 and -// https://xml2rfc.tools.ietf.org/public/rfc/html/rfc2412.html#anchor49 -const p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' + - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' + - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; -crypto.createDiffieHellman(p, 'hex'); - -// Confirm DH_check() results are exposed for optional examination. -const bad_dh = crypto.createDiffieHellman('02', 'hex'); -assert.notStrictEqual(bad_dh.verifyError, 0); - } -} + // Second OAKLEY group, see + // https://github.com/nodejs/node-v0.x-archive/issues/2338 and + // https://xml2rfc.tools.ietf.org/public/rfc/html/rfc2412.html#anchor49 + const p = + 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' + + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' + + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; + crypto.createDiffieHellman(p, 'hex'); + + // Confirm DH_check() results are exposed for optional examination. + const bad_dh = crypto.createDiffieHellman('02', 'hex'); + assert.notStrictEqual(bad_dh.verifyError, 0); + }, +}; ///////////////////// @@ -149,17 +138,23 @@ export const dh_constructor_test = { test(ctrl, env, ctx) { const DiffieHellmanGroup = crypto.DiffieHellmanGroup; const dhg = DiffieHellmanGroup('modp14'); - assert.ok(dhg instanceof DiffieHellmanGroup, 'DiffieHellmanGroup is expected ' + - 'to return a new instance when ' + - 'called without `new`'); + assert.ok( + dhg instanceof DiffieHellmanGroup, + 'DiffieHellmanGroup is expected ' + + 'to return a new instance when ' + + 'called without `new`' + ); const p1 = dhg.getPrime('buffer'); const DiffieHellman = crypto.DiffieHellman; const dh = DiffieHellman(p1, 'buffer'); - assert.ok(dh instanceof DiffieHellman, 'DiffieHellman is expected to return a ' + - 'new instance when called without `new`'); - } -} + assert.ok( + dh instanceof DiffieHellman, + 'DiffieHellman is expected to return a ' + + 'new instance when called without `new`' + ); + }, +}; //////////////////// // This test will fail if boringssl runs in FIPS mode and succeed otherwise; disable it for now. @@ -186,25 +181,29 @@ if (!common.hasFipsCrypto) { export const dh_group_test = { test(ctrl, env, ctx) { assert.throws( - function() { + function () { crypto.getDiffieHellman('modp14').setPrivateKey(''); }, - new RegExp('^TypeError: crypto\\.getDiffieHellman\\(\\.\\.\\.\\)\\.' + - 'setPrivateKey is not a function$'), - 'crypto.getDiffieHellman(\'modp14\').setPrivateKey(\'\') ' + - 'failed to throw the expected error.' + new RegExp( + '^TypeError: crypto\\.getDiffieHellman\\(\\.\\.\\.\\)\\.' + + 'setPrivateKey is not a function$' + ), + "crypto.getDiffieHellman('modp14').setPrivateKey('') " + + 'failed to throw the expected error.' ); assert.throws( - function() { + function () { crypto.getDiffieHellman('modp14').setPublicKey(''); }, - new RegExp('^TypeError: crypto\\.getDiffieHellman\\(\\.\\.\\.\\)\\.' + - 'setPublicKey is not a function$'), - 'crypto.getDiffieHellman(\'modp14\').setPublicKey(\'\') ' + - 'failed to throw the expected error.' + new RegExp( + '^TypeError: crypto\\.getDiffieHellman\\(\\.\\.\\.\\)\\.' + + 'setPublicKey is not a function$' + ), + "crypto.getDiffieHellman('modp14').setPublicKey('') " + + 'failed to throw the expected error.' ); - } -} + }, +}; //////////////// @@ -217,8 +216,8 @@ export const dh_exchange_test = { const aSecret = alice.computeSecret(bob.getPublicKey()).toString('hex'); const bSecret = bob.computeSecret(alice.getPublicKey()).toString('hex'); assert.strictEqual(aSecret, bSecret); - } -} + }, +}; //////////////// @@ -258,7 +257,7 @@ export const dh_exchange_test = { // } const apub = -'5484455905d3eff34c70980e871f27f05448e66f5a6efbb97cbcba4e927196c2bd9ea272cded91\ + '5484455905d3eff34c70980e871f27f05448e66f5a6efbb97cbcba4e927196c2bd9ea272cded91\ 10a4977afa8d9b16c9139a444ed2d954a794650e5d7cb525204f385e1af81530518563822ecd0f9\ 524a958d02b3c269e79d6d69850f0968ad567a4404fbb0b19efc8bc73e267b6136b88cafb33299f\ f7c7cace3ffab1a88c2c9ee841f88b4c3679b4efc465f5c93cca11d487be57373e4c5926f634c4e\ @@ -266,7 +265,7 @@ efee6721d01db91cd66321615b2522f96368dbc818875d422140d0edf30bdb97d9721feddcb9ff6\ 453741a4f687ee46fc54bf1198801f1210ac789879a5ee123f79e2d2ce1209df2445d32166bc9e4\ 8f89e944ec9c3b2e16c8066cd8eebd4e33eb941'; const bpub = -'3fca64510e36bc7da8a3a901c7b74c2eabfa25deaf7cbe1d0c50235866136ad677317279e1fb0\ + '3fca64510e36bc7da8a3a901c7b74c2eabfa25deaf7cbe1d0c50235866136ad677317279e1fb0\ 06e9c0a07f63e14a3363c8e016fbbde2b2c7e79fed1cc3e08e95f7459f547a8cd0523ee9dc744d\ e5a956d92b937db4448917e1f6829437f05e408ee7aea70c0362b37370c7c75d14449d8b2d2133\ 04ac972302d349975e2265ca7103cfebd019d9e91234d638611abd049014f7abf706c1c5da6c88\ @@ -274,7 +273,7 @@ e5a956d92b937db4448917e1f6829437f05e408ee7aea70c0362b37370c7c75d14449d8b2d2133\ 6e8ac97f5be1a5b68f20382f2a7dac189cf169325c4cf845b26a0cd616c31fec905c5d9035e5f7\ 8e9880c812374ac0f3ca3d365f06e4be526b5affd4b79'; const apriv = -'62411e34704637d99c6c958a7db32ac22fcafafbe1c33d2cfdb76e12ded41f38fc16b792b9041\ + '62411e34704637d99c6c958a7db32ac22fcafafbe1c33d2cfdb76e12ded41f38fc16b792b9041\ 2e4c82755a3815ba52f780f0ee296ad46e348fc4d1dcd6b64f4eea1b231b2b7d95c5b1c2e26d34\ 83520558b9860a6eb668f01422a54e6604aa7702b4e67511397ef3ecb912bff1a83899c5a5bfb2\ 0ee29249a91b8a698e62486f7009a0e9eaebda69d77ecfa2ca6ba2db6c8aa81759c8c90c675979\ @@ -282,7 +281,7 @@ const apriv = 7012f68255207722355634290acc7fddeefbba75650a85ece95b6a12de67eac016ba78960108dd\ 5dbadfaa43cc9fed515a1f307b7d90ae0623bc7b8cefb'; const secret = -'00c37b1e06a436d6717816a40e6d72907a6f255638b93032267dcb9a5f0b4a9aa0236f3dce63b\ + '00c37b1e06a436d6717816a40e6d72907a6f255638b93032267dcb9a5f0b4a9aa0236f3dce63b\ 1c418c60978a00acd1617dfeecf1661d8a3fafb4d0d8824386750f4853313400e7e4afd22847e4\ fa56bc9713872021265111906673b38db83d10cbfa1dea3b6b4c97c8655f4ae82125281af7f234\ 8916a15c6f95649367d169d587697480df4d10b381479e86d5518b520d9d8fb764084eab518224\ @@ -294,7 +293,8 @@ export const dh_padding_test = { test(ctrl, env, ctx) { /* FIPS-friendly 2048 bit prime */ const p = crypto.createDiffieHellman( - crypto.getDiffieHellman('modp14').getPrime()); + crypto.getDiffieHellman('modp14').getPrime() + ); p.setPublicKey(apub, 'hex'); p.setPrivateKey(apriv, 'hex'); @@ -303,8 +303,8 @@ export const dh_padding_test = { p.computeSecret(bpub, 'hex', 'hex').toString('hex'), secret ); - } -} + }, +}; export const dhKeygenTest = { test() { @@ -356,8 +356,11 @@ export const dhKeygenTest = { assert.strictEqual(secret1, secret4); - assert.throws(() => { - dh3.computeSecret(''); - }, { name: 'Error' }); - } + assert.throws( + () => { + dh3.computeSecret(''); + }, + { name: 'Error' } + ); + }, }; diff --git a/src/workerd/api/node/tests/crypto_hash-test.js b/src/workerd/api/node/tests/crypto_hash-test.js index 8fac702135f..efc47fc80c3 100644 --- a/src/workerd/api/node/tests/crypto_hash-test.js +++ b/src/workerd/api/node/tests/crypto_hash-test.js @@ -25,9 +25,7 @@ 'use strict'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; import * as assert from 'node:assert'; import * as crypto from 'node:crypto'; import * as stream from 'node:stream'; @@ -77,26 +75,30 @@ export const hash_correctness_tests = { assert.strictEqual( a1, '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', - `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); + `${cryptoType} with ${digest} digest failed to evaluate to expected hash` + ); cryptoType = 'sha256'; digest = 'base64'; assert.strictEqual( a2, '2bX1jws4GYKTlxhloUB09Z66PoJZW+y+hq5R8dnx9l4=', - `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); + `${cryptoType} with ${digest} digest failed to evaluate to expected hash` + ); cryptoType = 'sha512'; digest = 'latin1'; assert.deepStrictEqual( a3, Buffer.from( - '\u00c1(4\u00f1\u0003\u001fd\u0097!O\'\u00d4C/&Qz\u00d4' + - '\u0094\u0015l\u00b8\u008dQ+\u00db\u001d\u00c4\u00b5}\u00b2' + - '\u00d6\u0092\u00a3\u00df\u00a2i\u00a1\u009b\n\n*\u000f' + - '\u00d7\u00d6\u00a2\u00a8\u0085\u00e3<\u0083\u009c\u0093' + - '\u00c2\u0006\u00da0\u00a1\u00879(G\u00ed\'', - 'latin1'), - `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); + "\u00c1(4\u00f1\u0003\u001fd\u0097!O'\u00d4C/&Qz\u00d4" + + '\u0094\u0015l\u00b8\u008dQ+\u00db\u001d\u00c4\u00b5}\u00b2' + + '\u00d6\u0092\u00a3\u00df\u00a2i\u00a1\u009b\n\n*\u000f' + + '\u00d7\u00d6\u00a2\u00a8\u0085\u00e3<\u0083\u009c\u0093' + + "\u00c2\u0006\u00da0\u00a1\u00879(G\u00ed'", + 'latin1' + ), + `${cryptoType} with ${digest} digest failed to evaluate to expected hash` + ); cryptoType = 'sha1'; digest = 'hex'; @@ -122,115 +124,129 @@ export const hash_correctness_tests = { // Test multiple updates to same hash const h1 = crypto.createHash('sha1').update('Test123').digest('hex'); - const h2 = crypto.createHash('sha1').update('Test').update('123').digest('hex'); + const h2 = crypto + .createHash('sha1') + .update('Test') + .update('123') + .digest('hex'); assert.strictEqual(h1, h2); - } -} + }, +}; export const hash_error_test = { async test(ctrl, env, ctx) { // Issue https://github.com/nodejs/node-v0.x-archive/issues/2227: unknown digest // method should throw an error. - assert.throws(function() { + assert.throws(function () { crypto.createHash('xyzzy'); }, /Digest method not supported/); // Issue https://github.com/nodejs/node/issues/9819: throwing encoding used to // segfault. assert.throws( - () => crypto.createHash('sha256').digest({ - toString: () => { throw new Error('boom'); }, - }), + () => + crypto.createHash('sha256').digest({ + toString: () => { + throw new Error('boom'); + }, + }), { name: 'Error', - message: 'boom' - }); + message: 'boom', + } + ); // Issue https://github.com/nodejs/node/issues/25487: error message for invalid // arg type to update method should include all possible types - assert.throws( - () => crypto.createHash('sha256').update(), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); + assert.throws(() => crypto.createHash('sha256').update(), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); // Default UTF-8 encoding - const hutf8 = crypto.createHash('sha512').update('УТФ-8 text').digest('hex'); + const hutf8 = crypto + .createHash('sha512') + .update('УТФ-8 text') + .digest('hex'); assert.strictEqual( hutf8, '4b21bbd1a68e690a730ddcb5a8bc94ead9879ffe82580767ad7ec6fa8ba2dea6' + - '43a821af66afa9a45b6a78c712fecf0e56dc7f43aef4bcfc8eb5b4d8dca6ea5b'); + '43a821af66afa9a45b6a78c712fecf0e56dc7f43aef4bcfc8eb5b4d8dca6ea5b' + ); assert.notStrictEqual( hutf8, - crypto.createHash('sha512').update('УТФ-8 text', 'latin1').digest('hex')); + crypto.createHash('sha512').update('УТФ-8 text', 'latin1').digest('hex') + ); const h3 = crypto.createHash('sha256'); h3.digest(); - assert.throws( - () => h3.digest(), - { - code: 'ERR_CRYPTO_HASH_FINALIZED', - name: 'Error' - }); + assert.throws(() => h3.digest(), { + code: 'ERR_CRYPTO_HASH_FINALIZED', + name: 'Error', + }); - assert.throws( - () => h3.update('foo'), - { - code: 'ERR_CRYPTO_HASH_FINALIZED', - name: 'Error' - }); + assert.throws(() => h3.update('foo'), { + code: 'ERR_CRYPTO_HASH_FINALIZED', + name: 'Error', + }); assert.strictEqual( crypto.createHash('sha256').update('test').digest('ucs2'), - crypto.createHash('sha256').update('test').digest().toString('ucs2')); - - assert.throws( - () => crypto.createHash(), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "algorithm" argument must be of type string. ' + - 'Received undefined' - } + crypto.createHash('sha256').update('test').digest().toString('ucs2') ); + assert.throws(() => crypto.createHash(), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "algorithm" argument must be of type string. ' + + 'Received undefined', + }); + { const Hash = crypto.Hash; const instance = crypto.Hash('sha256'); - assert.ok(instance instanceof Hash, 'Hash is expected to return a new instance' + - ' when called without `new`'); + assert.ok( + instance instanceof Hash, + 'Hash is expected to return a new instance' + + ' when called without `new`' + ); } // shake*-based tests for XOF hash function are not supported in FIPS and have been removed. { // Non-XOF hash functions should accept valid outputLength options as well. - assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 }) - .digest('hex'), - 'd14a028c2a3a2bc9476102bb288234c4' + - '15a2b01f828ea62ac5b3e42f'); + assert.strictEqual( + crypto.createHash('sha224', { outputLength: 28 }).digest('hex'), + 'd14a028c2a3a2bc9476102bb288234c4' + '15a2b01f828ea62ac5b3e42f' + ); // Passing invalid sizes should throw during creation. - assert.throws(() => { - crypto.createHash('sha256', { outputLength: 28 }); - }, { - name: 'Error' - }); + assert.throws( + () => { + crypto.createHash('sha256', { outputLength: 28 }); + }, + { + name: 'Error', + } + ); for (const outputLength of [null, {}, 'foo', false]) { - assert.throws(() => crypto.createHash('sha256', { outputLength }), - { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => crypto.createHash('sha256', { outputLength }), { + code: 'ERR_INVALID_ARG_TYPE', + }); } - for (const outputLength of [-1, .5, Infinity, 2 ** 90]) { - assert.throws(() => crypto.createHash('sha256', { outputLength }), - { code: 'ERR_OUT_OF_RANGE' }); + for (const outputLength of [-1, 0.5, Infinity, 2 ** 90]) { + assert.throws(() => crypto.createHash('sha256', { outputLength }), { + code: 'ERR_OUT_OF_RANGE', + }); } } - } -} + }, +}; export const hash_copy_test = { async test(ctrl, env, ctx) { @@ -245,8 +261,8 @@ export const hash_copy_test = { const d = crypto.createHash('sha512').update('abcdef'); assert.strictEqual(a.digest('hex'), b.digest('hex')); assert.strictEqual(c.digest('hex'), d.digest('hex')); - } -} + }, +}; function deferredPromise() { let resolve, reject; @@ -258,7 +274,7 @@ function deferredPromise() { promise, resolve, reject, - } + }; } export const hash_pipe_test = { @@ -267,21 +283,24 @@ export const hash_pipe_test = { const s = new stream.PassThrough(); const h = crypto.createHash('sha512'); - const expect = 'fba055c6fd0c5b6645407749ed7a8b41' + - 'b8f629f2163c3ca3701d864adabda1f8' + - '93c37bf82b22fdd151ba8e357f611da4' + - '88a74b6a5525dd9b69554c6ce5138ad7'; - - s.pipe(h).on('data', function(c) { + const expect = + 'fba055c6fd0c5b6645407749ed7a8b41' + + 'b8f629f2163c3ca3701d864adabda1f8' + + '93c37bf82b22fdd151ba8e357f611da4' + + '88a74b6a5525dd9b69554c6ce5138ad7'; + + s.pipe(h) + .on('data', function (c) { // Calling digest() after piping into a stream with SHA3 should not cause // a segmentation fault, see https://github.com/nodejs/node/issues/28245. if (c !== expect || h.digest('hex') !== expect) { - p.reject("Unexpected value for stream-based hash"); + p.reject('Unexpected value for stream-based hash'); } p.resolve(); - }).setEncoding('hex'); + }) + .setEncoding('hex'); s.end('aoeu'); await p.promise; - } -} + }, +}; diff --git a/src/workerd/api/node/tests/crypto_hkdf-test.js b/src/workerd/api/node/tests/crypto_hkdf-test.js index 965ff10638c..f90ceb80b07 100644 --- a/src/workerd/api/node/tests/crypto_hkdf-test.js +++ b/src/workerd/api/node/tests/crypto_hkdf-test.js @@ -25,17 +25,14 @@ 'use strict'; -import { - Buffer, - kMaxLength -} from 'node:buffer'; +import { Buffer, kMaxLength } from 'node:buffer'; import * as assert from 'node:assert'; import { // createSecretKey, hkdf, hkdfSync, - getHashes + getHashes, } from 'node:crypto'; function deferredPromise() { @@ -48,85 +45,89 @@ function deferredPromise() { promise, resolve, reject, - } + }; } export const hkdf_error_tests = { async test(ctrl, env, ctx) { assert.throws(() => hkdf(), { code: 'ERR_INVALID_ARG_TYPE', - message: /The "digest" argument must be of type string/ + message: /The "digest" argument must be of type string/, }); [1, {}, [], false, Infinity].forEach((i) => { assert.throws(() => hkdf(i, 'a'), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "digest" argument must be of type string/ + message: /^The "digest" argument must be of type string/, }); assert.throws(() => hkdfSync(i, 'a'), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "digest" argument must be of type string/ + message: /^The "digest" argument must be of type string/, }); }); [1, {}, [], false, Infinity].forEach((i) => { assert.throws(() => hkdf('sha256', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "ikm" argument must be / + message: /^The "ikm" argument must be /, }); assert.throws(() => hkdfSync('sha256', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "ikm" argument must be / + message: /^The "ikm" argument must be /, }); }); [1, {}, [], false, Infinity].forEach((i) => { assert.throws(() => hkdf('sha256', 'secret', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "salt" argument must be / + message: /^The "salt" argument must be /, }); assert.throws(() => hkdfSync('sha256', 'secret', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "salt" argument must be / + message: /^The "salt" argument must be /, }); }); [1, {}, [], false, Infinity].forEach((i) => { assert.throws(() => hkdf('sha256', 'secret', 'salt', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "info" argument must be / + message: /^The "info" argument must be /, }); assert.throws(() => hkdfSync('sha256', 'secret', 'salt', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "info" argument must be / + message: /^The "info" argument must be /, }); }); ['test', {}, [], false].forEach((i) => { assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "length" argument must be of type number/ + message: /^The "length" argument must be of type number/, }); assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', i), { code: 'ERR_INVALID_ARG_TYPE', - message: /^The "length" argument must be of type number/ + message: /^The "length" argument must be of type number/, }); }); assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', -1), { - code: 'ERR_OUT_OF_RANGE' + code: 'ERR_OUT_OF_RANGE', }); assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', -1), { - code: 'ERR_OUT_OF_RANGE' - }); - assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', - kMaxLength + 1), { - code: 'ERR_OUT_OF_RANGE' - }); - assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', - kMaxLength + 1), { - code: 'ERR_OUT_OF_RANGE' + code: 'ERR_OUT_OF_RANGE', }); + assert.throws( + () => hkdf('sha256', 'secret', 'salt', 'info', kMaxLength + 1), + { + code: 'ERR_OUT_OF_RANGE', + } + ); + assert.throws( + () => hkdfSync('sha256', 'secret', 'salt', 'info', kMaxLength + 1), + { + code: 'ERR_OUT_OF_RANGE', + } + ); { const p = deferredPromise(); @@ -139,14 +140,14 @@ export const hkdf_error_tests = { await assert.rejects(p.promise); } assert.throws(() => hkdfSync('unknown', 'a', '', '', 10), { - name: 'TypeError' + name: 'TypeError', }); assert.throws(() => hkdf('unknown', 'a', '', Buffer.alloc(1025), 10), { - code: 'ERR_OUT_OF_RANGE' + code: 'ERR_OUT_OF_RANGE', }); assert.throws(() => hkdfSync('unknown', 'a', '', Buffer.alloc(1025), 10), { - code: 'ERR_OUT_OF_RANGE' + code: 'ERR_OUT_OF_RANGE', }); { @@ -159,14 +160,13 @@ export const hkdf_error_tests = { }); await assert.rejects(p.promise); } - assert.throws( - () => hkdfSync('sha512', 'a', '', '', 64 * 255 + 1), { - name: 'RangeError' + assert.throws(() => hkdfSync('sha512', 'a', '', '', 64 * 255 + 1), { + name: 'RangeError', }); - } -} + }, +}; -async function hkdfTestAlg([ hash, secret, salt, info, length ]) { +async function hkdfTestAlg([hash, secret, salt, info, length]) { { const syncResult = hkdfSync(hash, secret, salt, info, length); assert.ok(syncResult instanceof ArrayBuffer); @@ -174,11 +174,11 @@ async function hkdfTestAlg([ hash, secret, salt, info, length ]) { const p = deferredPromise(); hkdf(hash, secret, salt, info, length, (err, asyncResult) => { - if (err) return p.reject(err); - assert.ok(is_async); - assert.ok(asyncResult instanceof ArrayBuffer); - assert.deepStrictEqual(syncResult, asyncResult); - p.resolve(); + if (err) return p.reject(err); + assert.ok(is_async); + assert.ok(asyncResult instanceof ArrayBuffer); + assert.deepStrictEqual(syncResult, asyncResult); + p.resolve(); }); // Keep this after the hkdf call above. This verifies // that the callback is invoked asynchronously. @@ -194,9 +194,9 @@ async function hkdfTestAlg([ hash, secret, salt, info, length ]) { const syncResult = hkdfSync(hash, buf_secret, buf_salt, buf_info, length); hkdf(hash, buf_secret, buf_salt, buf_info, length, (err, asyncResult) => { - if (err) return p.reject(err); - assert.deepStrictEqual(syncResult, asyncResult); - p.resolve(); + if (err) return p.reject(err); + assert.deepStrictEqual(syncResult, asyncResult); + p.resolve(); }); await p.promise; } @@ -225,9 +225,9 @@ async function hkdfTestAlg([ hash, secret, salt, info, length ]) { const syncResult = hkdfSync(hash, ta_secret, ta_salt, ta_info, length); hkdf(hash, ta_secret, ta_salt, ta_info, length, (err, asyncResult) => { - if (err) return p.reject(err); - assert.deepStrictEqual(syncResult, asyncResult); - p.resolve(); + if (err) return p.reject(err); + assert.deepStrictEqual(syncResult, asyncResult); + p.resolve(); }); await p.promise; @@ -236,7 +236,8 @@ async function hkdfTestAlg([ hash, secret, salt, info, length ]) { ta_secret.buffer, ta_salt.buffer, ta_info.buffer, - length); + length + ); assert.deepStrictEqual(syncResult, syncResultBuf); } @@ -246,16 +247,11 @@ async function hkdfTestAlg([ hash, secret, salt, info, length ]) { const a_salt = new ArrayBuffer(0); const a_info = new ArrayBuffer(1); - const syncResult = hkdfSync( - hash, - ta_secret.buffer, - a_salt, - a_info, - length); + const syncResult = hkdfSync(hash, ta_secret.buffer, a_salt, a_info, length); hkdf(hash, ta_secret, a_salt, a_info, length, (err, asyncResult) => { - if (err) return p.reject(err); - assert.deepStrictEqual(syncResult, asyncResult); - p.resolve(); + if (err) return p.reject(err); + assert.deepStrictEqual(syncResult, asyncResult); + p.resolve(); }); await p.promise; } @@ -276,5 +272,5 @@ export const hkdf_correctness_tests = { getHashes().forEach((hash) => { assert.ok(hkdfSync(hash, 'key', 'salt', 'info', 5)); }); - } -} + }, +}; diff --git a/src/workerd/api/node/tests/crypto_hmac-test.js b/src/workerd/api/node/tests/crypto_hmac-test.js index e335671db6f..eea19073f0a 100644 --- a/src/workerd/api/node/tests/crypto_hmac-test.js +++ b/src/workerd/api/node/tests/crypto_hmac-test.js @@ -25,9 +25,7 @@ 'use strict'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; import * as assert from 'node:assert'; import * as crypto from 'node:crypto'; @@ -36,39 +34,41 @@ export const hmac_error_tests = { { const Hmac = crypto.Hmac; const instance = crypto.Hmac('sha256', 'Node'); - assert.ok(instance instanceof Hmac, 'Hmac is expected to return a new instance' + - ' when called without `new`'); + assert.ok( + instance instanceof Hmac, + 'Hmac is expected to return a new instance' + + ' when called without `new`' + ); } - assert.throws( - () => crypto.createHmac(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "hmac" argument must be of type string. Received null' - }); + assert.throws(() => crypto.createHmac(null), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "hmac" argument must be of type string. Received null', + }); assert.throws( - () => crypto.createHmac('sha256', 'key').digest({ - toString: () => { throw new Error('boom'); }, - }), + () => + crypto.createHmac('sha256', 'key').digest({ + toString: () => { + throw new Error('boom'); + }, + }), { name: 'Error', - message: 'boom' - }); + message: 'boom', + } + ); - assert.throws( - () => crypto.createHmac('sha1', null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); - } -} + assert.throws(() => crypto.createHmac('sha1', null), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); + }, +}; function testHmac(algo, key, data, expected) { - if (!Array.isArray(data)) - data = [data]; + if (!Array.isArray(data)) data = [data]; // If the key is a Buffer, test Hmac with a key object as well. const keyWrappers = [ @@ -78,8 +78,7 @@ function testHmac(algo, key, data, expected) { for (const keyWrapper of keyWrappers) { const hmac = crypto.createHmac(algo, keyWrapper(key)); - for (const chunk of data) - hmac.update(chunk); + for (const chunk of data) hmac.update(chunk); const actual = hmac.digest('hex'); assert.strictEqual(actual, expected); } @@ -89,57 +88,68 @@ export const hmac_correctness_tests = { async test(ctrl, env, ctx) { { // Test HMAC with multiple updates. - testHmac('sha1', 'Node', ['some data', 'to hmac'], - '19fd6e1ba73d9ed2224dd5094a71babe85d9a892'); + testHmac( + 'sha1', + 'Node', + ['some data', 'to hmac'], + '19fd6e1ba73d9ed2224dd5094a71babe85d9a892' + ); } // Test HMAC (Wikipedia Test Cases) const wikipedia = [ { - key: 'key', data: 'The quick brown fox jumps over the lazy dog', - hmac: { // HMACs lifted from Wikipedia. + key: 'key', + data: 'The quick brown fox jumps over the lazy dog', + hmac: { + // HMACs lifted from Wikipedia. md5: '80070713463e7749b90c2dc24911e275', sha1: 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', sha256: - 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc' + - '2d1a3cd8' - } + 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc' + + '2d1a3cd8', + }, }, { - key: 'key', data: '', - hmac: { // Intermediate test to help debugging. + key: 'key', + data: '', + hmac: { + // Intermediate test to help debugging. md5: '63530468a04e386459855da0063b6596', sha1: 'f42bb0eeb018ebbd4597ae7213711ec60760843f', sha256: - '5d5d139563c95b5967b9bd9a8c9b233a9dedb45072794cd232dc1b74' + - '832607d0' - } + '5d5d139563c95b5967b9bd9a8c9b233a9dedb45072794cd232dc1b74' + + '832607d0', + }, }, { - key: '', data: 'The quick brown fox jumps over the lazy dog', - hmac: { // Intermediate test to help debugging. + key: '', + data: 'The quick brown fox jumps over the lazy dog', + hmac: { + // Intermediate test to help debugging. md5: 'ad262969c53bc16032f160081c4a07a0', sha1: '2ba7f707ad5f187c412de3106583c3111d668de8', sha256: - 'fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dc' + - 'ed19a416' - } + 'fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dc' + + 'ed19a416', + }, }, { - key: '', data: '', - hmac: { // HMACs lifted from Wikipedia. + key: '', + data: '', + hmac: { + // HMACs lifted from Wikipedia. md5: '74e6f7298a9c2d168935f58c001bad88', sha1: 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', sha256: - 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c71214' + - '4292c5ad' - } + 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c71214' + + '4292c5ad', + }, }, ]; for (const { key, data, hmac } of wikipedia) { - for (const hash in hmac) - testHmac(hash, key, data, hmac[hash]); + for (const hash in hmac) testHmac(hash, key, data, hmac[hash]); } // Test HMAC-SHA-* (rfc 4231 Test Cases) @@ -150,73 +160,81 @@ export const hmac_correctness_tests = { hmac: { sha224: '896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22', sha256: - 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c' + - '2e32cff7', + 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c' + + '2e32cff7', sha384: - 'afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c' + - '7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6', + 'afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c' + + '7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6', sha512: - '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b305' + - '45e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f170' + - '2e696c203a126854' - } + '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b305' + + '45e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f170' + + '2e696c203a126854', + }, }, { key: Buffer.from('4a656665', 'hex'), // 'Jefe' - data: Buffer.from('7768617420646f2079612077616e7420666f72206e6f74686' + - '96e673f', 'hex'), // 'what do ya want for nothing?' + data: Buffer.from( + '7768617420646f2079612077616e7420666f72206e6f74686' + '96e673f', + 'hex' + ), // 'what do ya want for nothing?' hmac: { sha224: 'a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44', sha256: - '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b9' + - '64ec3843', + '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b9' + + '64ec3843', sha384: - 'af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec373' + - '6322445e8e2240ca5e69e2c78b3239ecfab21649', + 'af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec373' + + '6322445e8e2240ca5e69e2c78b3239ecfab21649', sha512: - '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7' + - 'ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b' + - '636e070a38bce737' - } + '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7' + + 'ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b' + + '636e070a38bce737', + }, }, { key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), - data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddddddd' + - 'ddddddddddddddddddddddddddddddddddddddddddddddddddd', - 'hex'), + data: Buffer.from( + 'ddddddddddddddddddddddddddddddddddddddddddddddddd' + + 'ddddddddddddddddddddddddddddddddddddddddddddddddddd', + 'hex' + ), hmac: { sha224: '7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea', sha256: - '773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514' + - 'ced565fe', + '773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514' + + 'ced565fe', sha384: - '88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e5' + - '5966144b2a5ab39dc13814b94e3ab6e101a34f27', + '88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e5' + + '5966144b2a5ab39dc13814b94e3ab6e101a34f27', sha512: - 'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33' + - 'b2279d39bf3e848279a722c806b485a47e67c807b946a337bee89426' + - '74278859e13292fb' - } + 'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33' + + 'b2279d39bf3e848279a722c806b485a47e67c807b946a337bee89426' + + '74278859e13292fb', + }, }, { - key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'hex'), - data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + - 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd', - 'hex'), + key: Buffer.from( + '0102030405060708090a0b0c0d0e0f10111213141516171819', + 'hex' + ), + data: Buffer.from( + 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + + 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd', + 'hex' + ), hmac: { sha224: '6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a', sha256: - '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff4' + - '6729665b', + '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff4' + + '6729665b', sha384: - '3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e' + - '1f573b4e6801dd23c4a7d679ccf8a386c674cffb', + '3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e' + + '1f573b4e6801dd23c4a7d679ccf8a386c674cffb', sha512: - 'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050' + - '361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2d' + - 'e2adebeb10a298dd' - } + 'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050' + + '361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2d' + + 'e2adebeb10a298dd', + }, }, { @@ -227,65 +245,77 @@ export const hmac_correctness_tests = { sha224: '0e2aea68a90c8d37c988bcdb9fca6fa8', sha256: 'a3b6167473100ee06e0c796c2955552b', sha384: '3abf34c3503b2a23a46efc619baef897', - sha512: '415fad6271580a531d4179bc891d87a6' + sha512: '415fad6271580a531d4179bc891d87a6', }, - truncate: true + truncate: true, }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaa', 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaa', + 'hex' + ), // 'Test Using Larger Than Block-Size Key - Hash Key First' - data: Buffer.from('54657374205573696e67204c6172676572205468616e20426' + - 'c6f636b2d53697a65204b6579202d2048617368204b657920' + - '4669727374', 'hex'), + data: Buffer.from( + '54657374205573696e67204c6172676572205468616e20426' + + 'c6f636b2d53697a65204b6579202d2048617368204b657920' + + '4669727374', + 'hex' + ), hmac: { sha224: '95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e', sha256: - '60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f' + - '0ee37f54', + '60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f' + + '0ee37f54', sha384: - '4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05' + - '033ac4c60c2ef6ab4030fe8296248df163f44952', + '4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05' + + '033ac4c60c2ef6ab4030fe8296248df163f44952', sha512: - '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b0137' + - '83f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec' + - '8b915a985d786598' - } + '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b0137' + + '83f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec' + + '8b915a985d786598', + }, }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaa', 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaa', + 'hex' + ), // 'This is a test using a larger than block-size key and a larger ' + // 'than block-size data. The key needs to be hashed before being ' + // 'used by the HMAC algorithm.' - data: Buffer.from('5468697320697320612074657374207573696e672061206c6' + - '172676572207468616e20626c6f636b2d73697a65206b6579' + - '20616e642061206c6172676572207468616e20626c6f636b2' + - 'd73697a6520646174612e20546865206b6579206e65656473' + - '20746f20626520686173686564206265666f7265206265696' + - 'e6720757365642062792074686520484d414320616c676f72' + - '6974686d2e', 'hex'), + data: Buffer.from( + '5468697320697320612074657374207573696e672061206c6' + + '172676572207468616e20626c6f636b2d73697a65206b6579' + + '20616e642061206c6172676572207468616e20626c6f636b2' + + 'd73697a6520646174612e20546865206b6579206e65656473' + + '20746f20626520686173686564206265666f7265206265696' + + 'e6720757365642062792074686520484d414320616c676f72' + + '6974686d2e', + 'hex' + ), hmac: { sha224: '3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1', sha256: - '9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f5153' + - '5c3a35e2', + '9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f5153' + + '5c3a35e2', sha384: - '6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82' + - '461e99c5a678cc31e799176d3860e6110c46523e', + '6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82' + + '461e99c5a678cc31e799176d3860e6110c46523e', sha512: - 'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d' + - '20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de04460' + - '65c97440fa8c6a58' - } + 'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d' + + '20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de04460' + + '65c97440fa8c6a58', + }, }, ]; @@ -294,9 +324,10 @@ export const hmac_correctness_tests = { const str = crypto.createHmac(hash, rfc4231[i].key); str.end(rfc4231[i].data); let strRes = str.read().toString('hex'); - let actual = crypto.createHmac(hash, rfc4231[i].key) - .update(rfc4231[i].data) - .digest('hex'); + let actual = crypto + .createHmac(hash, rfc4231[i].key) + .update(rfc4231[i].data) + .digest('hex'); if (rfc4231[i].truncate) { actual = actual.substr(0, 32); // first 128 bits == 32 hex chars strRes = strRes.substr(0, 32); @@ -311,7 +342,7 @@ export const hmac_correctness_tests = { actual, strRes, `Should get same result from stream (hash: ${hash} and case: ${i + 1})` + - ` => ${actual} must be ${strRes}` + ` => ${actual} must be ${strRes}` ); } } @@ -321,53 +352,63 @@ export const hmac_correctness_tests = { { key: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'), data: 'Hi There', - hmac: '9294727a3638bb1c13f48ef8158bfc9d' + hmac: '9294727a3638bb1c13f48ef8158bfc9d', }, { key: 'Jefe', data: 'what do ya want for nothing?', - hmac: '750c783e6ab0b503eaa86e310a5db738' + hmac: '750c783e6ab0b503eaa86e310a5db738', }, { key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), - data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddddddd' + - 'ddddddddddddddddddddddddddddddddddddddddddddddddddd', - 'hex'), - hmac: '56be34521d144c88dbb8c733f0e8b3f6' + data: Buffer.from( + 'ddddddddddddddddddddddddddddddddddddddddddddddddd' + + 'ddddddddddddddddddddddddddddddddddddddddddddddddddd', + 'hex' + ), + hmac: '56be34521d144c88dbb8c733f0e8b3f6', }, { - key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'hex'), - data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + - 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' + - 'cdcdcdcdcd', - 'hex'), - hmac: '697eaf0aca3a3aea3a75164746ffaa79' + key: Buffer.from( + '0102030405060708090a0b0c0d0e0f10111213141516171819', + 'hex' + ), + data: Buffer.from( + 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + + 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' + + 'cdcdcdcdcd', + 'hex' + ), + hmac: '697eaf0aca3a3aea3a75164746ffaa79', }, { key: Buffer.from('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', 'hex'), data: 'Test With Truncation', - hmac: '56461ef2342edc00f9bab995690efd4c' + hmac: '56461ef2342edc00f9bab995690efd4c', }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaa', - 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaa', + 'hex' + ), data: 'Test Using Larger Than Block-Size Key - Hash Key First', - hmac: '6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd' + hmac: '6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd', }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaa', - 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaa', + 'hex' + ), data: - 'Test Using Larger Than Block-Size Key and Larger Than One ' + - 'Block-Size Data', - hmac: '6f630fad67cda0ee1fb1f562db3aa53e' + 'Test Using Larger Than Block-Size Key and Larger Than One ' + + 'Block-Size Data', + hmac: '6f630fad67cda0ee1fb1f562db3aa53e', }, ]; @@ -378,76 +419,90 @@ export const hmac_correctness_tests = { { key: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'), data: 'Hi There', - hmac: 'b617318655057264e28bc0b6fb378c8ef146be00' + hmac: 'b617318655057264e28bc0b6fb378c8ef146be00', }, { key: 'Jefe', data: 'what do ya want for nothing?', - hmac: 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79' + hmac: 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79', }, { key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), - data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddd' + - 'ddddddddddddddddddddddddddddddddddddddddddddd' + - 'dddddddddd', - 'hex'), - hmac: '125d7342b9ac11cd91a39af48aa17b4f63f175d3' + data: Buffer.from( + 'ddddddddddddddddddddddddddddddddddddddddddddd' + + 'ddddddddddddddddddddddddddddddddddddddddddddd' + + 'dddddddddd', + 'hex' + ), + hmac: '125d7342b9ac11cd91a39af48aa17b4f63f175d3', }, { - key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'hex'), - data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + - 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' + - 'cdcdcdcdcd', - 'hex'), - hmac: '4c9007f4026250c6bc8414f9bf50c86c2d7235da' + key: Buffer.from( + '0102030405060708090a0b0c0d0e0f10111213141516171819', + 'hex' + ), + data: Buffer.from( + 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' + + 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' + + 'cdcdcdcdcd', + 'hex' + ), + hmac: '4c9007f4026250c6bc8414f9bf50c86c2d7235da', }, { key: Buffer.from('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', 'hex'), data: 'Test With Truncation', - hmac: '4c1a03424b55e07fe7f27be1d58bb9324a9a5a04' + hmac: '4c1a03424b55e07fe7f27be1d58bb9324a9a5a04', }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaa', - 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaa', + 'hex' + ), data: 'Test Using Larger Than Block-Size Key - Hash Key First', - hmac: 'aa4ae5e15272d00e95705637ce8a3b55ed402112' + hmac: 'aa4ae5e15272d00e95705637ce8a3b55ed402112', }, { - key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaa', - 'hex'), + key: Buffer.from( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaa', + 'hex' + ), data: - 'Test Using Larger Than Block-Size Key and Larger Than One ' + - 'Block-Size Data', - hmac: 'e8e99d0f45237d786d6bbaa7965c7808bbff1a91' + 'Test Using Larger Than Block-Size Key and Larger Than One ' + + 'Block-Size Data', + hmac: 'e8e99d0f45237d786d6bbaa7965c7808bbff1a91', }, ]; for (const { key, data, hmac } of rfc2202_sha1) testHmac('sha1', key, data, hmac); - } -} + }, +}; export const hmac_misc_tests = { async test(ctrl, env, ctx) { assert.strictEqual( crypto.createHmac('sha256', 'w00t').digest('ucs2'), - crypto.createHmac('sha256', 'w00t').digest().toString('ucs2')); + crypto.createHmac('sha256', 'w00t').digest().toString('ucs2') + ); // Check initialized -> uninitialized state transition after calling digest(). { const expected = - '\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' + - '\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d'; + '\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' + + '\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d'; { const h = crypto.createHmac('sha1', 'key').update('data'); - assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1')); + assert.deepStrictEqual( + h.digest('buffer'), + Buffer.from(expected, 'latin1') + ); assert.deepStrictEqual(h.digest('buffer'), Buffer.from('')); } { @@ -461,11 +516,14 @@ export const hmac_misc_tests = { // Calls to update() omitted intentionally. { const expected = - '\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' + - '\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f'; + '\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' + + '\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f'; { const h = crypto.createHmac('sha1', 'key'); - assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1')); + assert.deepStrictEqual( + h.digest('buffer'), + Buffer.from(expected, 'latin1') + ); assert.deepStrictEqual(h.digest('buffer'), Buffer.from('')); } { @@ -478,7 +536,8 @@ export const hmac_misc_tests = { { assert.throws( () => crypto.createHmac('sha7', 'key'), - /Digest method not supported/); + /Digest method not supported/ + ); } { @@ -486,8 +545,8 @@ export const hmac_misc_tests = { const keyObject = crypto.createSecretKey(Buffer.alloc(0)); assert.deepStrictEqual( crypto.createHmac('sha256', buf).update('foo').digest(), - crypto.createHmac('sha256', keyObject).update('foo').digest(), + crypto.createHmac('sha256', keyObject).update('foo').digest() ); } - } -} \ No newline at end of file + }, +}; diff --git a/src/workerd/api/node/tests/crypto_keys-test.js b/src/workerd/api/node/tests/crypto_keys-test.js index 960af1ad35f..6aa9465d6bc 100644 --- a/src/workerd/api/node/tests/crypto_keys-test.js +++ b/src/workerd/api/node/tests/crypto_keys-test.js @@ -1,47 +1,52 @@ - -import { - strictEqual, - ok, -} from 'node:assert'; -import { - KeyObject, - SecretKeyObject, - createSecretKey, -} from 'node:crypto'; -import { - Buffer, -} from 'node:buffer'; +import { strictEqual, ok } from 'node:assert'; +import { KeyObject, SecretKeyObject, createSecretKey } from 'node:crypto'; +import { Buffer } from 'node:buffer'; export const secret_key_equals_test = { async test(ctrl, env, ctx) { const secretKeyData1 = Buffer.from('abcdefghijklmnop'); const secretKeyData2 = Buffer.from('abcdefghijklmnop'.repeat(2)); - const aes1 = await crypto.subtle.importKey('raw', - secretKeyData1, - { name: 'AES-CBC'}, - true, ['encrypt', 'decrypt']); - const aes2 = await crypto.subtle.importKey('raw', - secretKeyData1, - { name: 'AES-CBC'}, - true, ['encrypt', 'decrypt']); - const aes3 = await crypto.subtle.importKey('raw', - secretKeyData2, - { name: 'AES-CBC'}, - true, ['encrypt', 'decrypt']); - const hmac = await crypto.subtle.importKey('raw', - secretKeyData1, - { - name: 'HMAC', - hash: 'SHA-256', - }, - true, ['sign', 'verify']); - const hmac2 = await crypto.subtle.importKey('raw', - secretKeyData1, - { - name: 'HMAC', - hash: 'SHA-256', - }, - false, ['sign', 'verify']); + const aes1 = await crypto.subtle.importKey( + 'raw', + secretKeyData1, + { name: 'AES-CBC' }, + true, + ['encrypt', 'decrypt'] + ); + const aes2 = await crypto.subtle.importKey( + 'raw', + secretKeyData1, + { name: 'AES-CBC' }, + true, + ['encrypt', 'decrypt'] + ); + const aes3 = await crypto.subtle.importKey( + 'raw', + secretKeyData2, + { name: 'AES-CBC' }, + true, + ['encrypt', 'decrypt'] + ); + const hmac = await crypto.subtle.importKey( + 'raw', + secretKeyData1, + { + name: 'HMAC', + hash: 'SHA-256', + }, + true, + ['sign', 'verify'] + ); + const hmac2 = await crypto.subtle.importKey( + 'raw', + secretKeyData1, + { + name: 'HMAC', + hash: 'SHA-256', + }, + false, + ['sign', 'verify'] + ); const aes1_ko = KeyObject.from(aes1); const aes2_ko = KeyObject.from(aes2); @@ -66,7 +71,7 @@ export const secret_key_equals_test = { // Unable to determine equality if either key is not extractable. ok(!hmac_ko.equals(hmac2_ko)); ok(!hmac2_ko.equals(hmac_ko)); - } + }, }; // In case anyone comes across these tests and wonders why there are @@ -75,17 +80,16 @@ export const secret_key_equals_test = { // pulled directly from MDN examples. const jwkEcKey = { - crv: "P-384", - d: "wouCtU7Nw4E8_7n5C1-xBjB4xqSb_liZhYMsy8MGgxUny6Q8NCoH9xSiviwLFfK_", + crv: 'P-384', + d: 'wouCtU7Nw4E8_7n5C1-xBjB4xqSb_liZhYMsy8MGgxUny6Q8NCoH9xSiviwLFfK_', ext: true, - key_ops: ["sign"], - kty: "EC", - x: "SzrRXmyI8VWFJg1dPUNbFcc9jZvjZEfH7ulKI1UkXAltd7RGWrcfFxqyGPcwu6AQ", - y: "hHUag3OvDzEr0uUQND4PXHQTXP5IDGdYhJhL-WLKjnGjQAw0rNGy5V29-aV-yseW", + key_ops: ['sign'], + kty: 'EC', + x: 'SzrRXmyI8VWFJg1dPUNbFcc9jZvjZEfH7ulKI1UkXAltd7RGWrcfFxqyGPcwu6AQ', + y: 'hHUag3OvDzEr0uUQND4PXHQTXP5IDGdYhJhL-WLKjnGjQAw0rNGy5V29-aV-yseW', }; -const pemEncodedKey = -` +const pemEncodedKey = ` MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy3Xo3U13dc+xojwQYWoJLCbOQ5fOVY8LlnqcJm1W1BFtxIhOAJWohiHuIRMctv7d zx47TLlmARSKvTRjd0dF92jx/xY20Lz+DXp8YL5yUWAFgA3XkO3LSJ gEOex10NB8jfkmgSb7QIudTVvbbUDfd5fwIBmCtaCwWx7NyeWWDb7A @@ -101,8 +105,8 @@ export const asymmetric_key_equals_test = { 'jwk', jwkEcKey, { - name: "ECDSA", - namedCurve: "P-384", + name: 'ECDSA', + namedCurve: 'P-384', }, true, ['sign'] @@ -111,8 +115,8 @@ export const asymmetric_key_equals_test = { 'jwk', jwkEcKey, { - name: "ECDSA", - namedCurve: "P-384", + name: 'ECDSA', + namedCurve: 'P-384', }, true, ['sign'] @@ -126,21 +130,21 @@ export const asymmetric_key_equals_test = { 'spki', pemContent, { - name: "RSA-OAEP", - hash: "SHA-256", + name: 'RSA-OAEP', + hash: 'SHA-256', }, true, - ["encrypt"] + ['encrypt'] ); const rsa2 = await crypto.subtle.importKey( 'spki', pemContent, { - name: "RSA-OAEP", - hash: "SHA-256", + name: 'RSA-OAEP', + hash: 'SHA-256', }, false, - ["encrypt"] + ['encrypt'] ); strictEqual(rsa.type, 'public'); @@ -162,23 +166,22 @@ export const asymmetric_key_equals_test = { ok(!rsa_ko.equals(rsa2_ko)); jwk1_ko.export({ - type: "pkcs8", - format: "der", - cipher: "aes-128-cbc", - passphrase: Buffer.alloc(0) + type: 'pkcs8', + format: 'der', + cipher: 'aes-128-cbc', + passphrase: Buffer.alloc(0), }); jwk1_ko.export({ - type: "pkcs8", - format: "der", - cipher: "aes-128-cbc", - passphrase: '' + type: 'pkcs8', + format: 'der', + cipher: 'aes-128-cbc', + passphrase: '', }); - } + }, }; export const secret_key_test = { test(ctrl, env, ctx) { - const key1 = createSecretKey('hello'); const key2 = createSecretKey('hello'); const key3 = createSecretKey('there'); @@ -192,5 +195,5 @@ export const secret_key_test = { strictEqual(key3.type, 'secret'); ok(key1.equals(key2)); ok(!key1.equals(key3)); - } + }, }; diff --git a/src/workerd/api/node/tests/crypto_pbkdf2-test.js b/src/workerd/api/node/tests/crypto_pbkdf2-test.js index 69ae7d13e76..11147b02810 100644 --- a/src/workerd/api/node/tests/crypto_pbkdf2-test.js +++ b/src/workerd/api/node/tests/crypto_pbkdf2-test.js @@ -38,27 +38,47 @@ function deferredPromise() { promise, resolve, reject, - } + }; } -function mustNotCall(){return () => {};} +function mustNotCall() { + return () => {}; +} async function runPBKDF2(password, salt, iterations, keylen, hash) { - const syncResult = - crypto.pbkdf2Sync(password, salt, iterations, keylen, hash); + const syncResult = crypto.pbkdf2Sync( + password, + salt, + iterations, + keylen, + hash + ); const p = deferredPromise(); - crypto.pbkdf2(password, salt, iterations, keylen, hash, - (err, asyncResult) => { - assert.deepStrictEqual(asyncResult, syncResult); - p.resolve(); - }); + crypto.pbkdf2( + password, + salt, + iterations, + keylen, + hash, + (err, asyncResult) => { + assert.deepStrictEqual(asyncResult, syncResult); + p.resolve(); + } + ); await p.promise; return syncResult; } -async function testPBKDF2(password, salt, iterations, keylen, expected, encoding) { +async function testPBKDF2( + password, + salt, + iterations, + keylen, + expected, + encoding +) { const actual = await runPBKDF2(password, salt, iterations, keylen, 'sha256'); assert.strictEqual(actual.toString(encoding || 'latin1'), expected); } @@ -69,47 +89,70 @@ async function testPBKDF2(password, salt, iterations, keylen, expected, encoding export const pbkdf2_correctness_tests = { async test(ctrl, env, ctx) { - await testPBKDF2('password', 'salt', 1, 20, - '\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52' + - '\x56\xc4\xf8\x37\xa8\x65\x48\xc9'); - - await testPBKDF2('password', 'salt', 2, 20, - '\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9' + - '\x28\xf0\x6d\xd0\x2a\x30\x3f\x8e'); - - await testPBKDF2('password', 'salt', 4096, 20, - '\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6' + - '\x84\x5c\x4c\x8d\x96\x28\x93\xa0'); - - await testPBKDF2('passwordPASSWORDpassword', - 'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, - 25, - '\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11' + - '\x6e\x84\xcf\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c'); - - await testPBKDF2('pass\0word', 'sa\0lt', 4096, 16, - '\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65' + - '\x0a\x86\x87'); - - await testPBKDF2('password', 'salt', 32, 32, - '64c486c55d30d4c5a079b8823b7d7cb37ff0556f537da8410233bcec330ed956', - 'hex'); - } -} + await testPBKDF2( + 'password', + 'salt', + 1, + 20, + '\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52' + + '\x56\xc4\xf8\x37\xa8\x65\x48\xc9' + ); + + await testPBKDF2( + 'password', + 'salt', + 2, + 20, + '\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9' + + '\x28\xf0\x6d\xd0\x2a\x30\x3f\x8e' + ); + + await testPBKDF2( + 'password', + 'salt', + 4096, + 20, + '\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6' + + '\x84\x5c\x4c\x8d\x96\x28\x93\xa0' + ); + + await testPBKDF2( + 'passwordPASSWORDpassword', + 'saltSALTsaltSALTsaltSALTsaltSALTsalt', + 4096, + 25, + '\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11' + + '\x6e\x84\xcf\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c' + ); + + await testPBKDF2( + 'pass\0word', + 'sa\0lt', + 4096, + 16, + '\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65' + '\x0a\x86\x87' + ); + + await testPBKDF2( + 'password', + 'salt', + 32, + 32, + '64c486c55d30d4c5a079b8823b7d7cb37ff0556f537da8410233bcec330ed956', + 'hex' + ); + }, +}; export const pbkdf2_no_callback_test = { test(ctrl, env, ctx) { // Error path should not leak memory (check with valgrind). - assert.throws( - () => crypto.pbkdf2('password', 'salt', 1, 20, 'sha1'), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' - } - ); - } -} + assert.throws(() => crypto.pbkdf2('password', 'salt', 1, 20, 'sha1'), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); + }, +}; export const pbkdf2_out_of_range_tests = { test(ctrl, env, ctx) { @@ -127,37 +170,42 @@ export const pbkdf2_out_of_range_tests = { assert.throws( () => { crypto.pbkdf2Sync('password', 'salt', 1, notNumber, 'sha256'); - }, { + }, + { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - }); + } + ); }); [Infinity, -Infinity, NaN].forEach((input) => { assert.throws( () => { - crypto.pbkdf2('password', 'salt', 1, input, 'sha256', - mustNotCall()); - }, { + crypto.pbkdf2('password', 'salt', 1, input, 'sha256', mustNotCall()); + }, + { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'The value of "keylen" is out of range. It ' + - `must be an integer. Received ${input}` - }); + message: + 'The value of "keylen" is out of range. It ' + + `must be an integer. Received ${input}`, + } + ); }); [-1, 2147483648, 4294967296].forEach((input) => { assert.throws( () => { - crypto.pbkdf2('password', 'salt', 1, input, 'sha256', - mustNotCall()); - }, { + crypto.pbkdf2('password', 'salt', 1, input, 'sha256', mustNotCall()); + }, + { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - }); + } + ); }); - } -} + }, +}; export const empty_pwd_test = { async test(ctrl, env, ctx) { @@ -168,8 +216,8 @@ export const empty_pwd_test = { p.resolve(); }); await p.promise; - } -} + }, +}; export const invalid_arg_tests = { test(ctrl, env, ctx) { @@ -178,27 +226,25 @@ export const invalid_arg_tests = { { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "digest" argument must be of type string. ' + - 'Received undefined' - }); + message: + 'The "digest" argument must be of type string. ' + + 'Received undefined', + } + ); - assert.throws( - () => crypto.pbkdf2Sync('password', 'salt', 8, 8), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "digest" argument must be of type string. ' + - 'Received undefined' - }); + assert.throws(() => crypto.pbkdf2Sync('password', 'salt', 8, 8), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "digest" argument must be of type string. ' + 'Received undefined', + }); - assert.throws( - () => crypto.pbkdf2Sync('password', 'salt', 8, 8, null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "digest" argument must be of type string. ' + - 'Received null' - }); + assert.throws(() => crypto.pbkdf2Sync('password', 'salt', 8, 8, null), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "digest" argument must be of type string. ' + 'Received null', + }); [1, {}, [], true, undefined, null].forEach((input) => { assert.throws( () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', mustNotCall()), @@ -216,21 +262,15 @@ export const invalid_arg_tests = { } ); - assert.throws( - () => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + assert.throws(() => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); - assert.throws( - () => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + assert.throws(() => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); }); ['test', {}, [], true, undefined, null].forEach((i) => { @@ -242,45 +282,44 @@ export const invalid_arg_tests = { } ); - assert.throws( - () => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + assert.throws(() => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); }); - } -} + }, +}; export const TypedArray_tests = { async test(ctrl, env, ctx) { // Any TypedArray should work for password and salt. - for (const SomeArray of [Uint8Array, Uint16Array, Uint32Array, Float32Array, - Float64Array, ArrayBuffer]) { + for (const SomeArray of [ + Uint8Array, + Uint16Array, + Uint32Array, + Float32Array, + Float64Array, + ArrayBuffer, + ]) { await runPBKDF2(new SomeArray(10), 'salt', 8, 8, 'sha256'); await runPBKDF2('pass', new SomeArray(10), 8, 8, 'sha256'); } - } -} + }, +}; export const invalid_digest_tests = { async test(ctrl, env, ctx) { { const p = deferredPromise(); - crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', - (err, prime) => { + crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', (err, prime) => { if (err) return p.reject(err); }); await assert.rejects(p.promise); } - assert.throws( - () => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'), - { - name: 'TypeError', - } - ); + assert.throws(() => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'), { + name: 'TypeError', + }); // TODO(soon): Enable this once crypto.getHashes() is available. Note that shake* is not // supported by boringssl so there's no need to filter it out, but we may want to filter other @@ -294,12 +333,9 @@ export const invalid_digest_tests = { { // This should not crash. - assert.throws( - () => crypto.pbkdf2Sync('1', '2', 1, 1, '%'), - { - name: 'TypeError', - } - ); + assert.throws(() => crypto.pbkdf2Sync('1', '2', 1, 1, '%'), { + name: 'TypeError', + }); } - } -} + }, +}; diff --git a/src/workerd/api/node/tests/crypto_random-test.js b/src/workerd/api/node/tests/crypto_random-test.js index b9be49ffe55..c99b0e61a09 100644 --- a/src/workerd/api/node/tests/crypto_random-test.js +++ b/src/workerd/api/node/tests/crypto_random-test.js @@ -1,9 +1,4 @@ -import { - ok, - rejects, - strictEqual, - throws, -} from 'node:assert'; +import { ok, rejects, strictEqual, throws } from 'node:assert'; import { generatePrime, @@ -13,9 +8,7 @@ import { timingSafeEqual, } from 'node:crypto'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; function deferredPromise() { let resolve, reject; @@ -27,17 +20,18 @@ function deferredPromise() { promise, resolve, reject, - } + }; } export const test = { async test(ctrl, env, ctx) { [1, 'hello', {}, []].forEach((i) => { throws(() => checkPrimeSync(i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); + // prettier-ignore for (const checks of [-(2 ** 31), -1, 2 ** 31, 2 ** 32 - 1, 2 ** 32, 2 ** 50]) { throws(() => checkPrimeSync(2n, { checks }), { code: 'ERR_OUT_OF_RANGE', @@ -46,13 +40,12 @@ export const test = { } ok( - !checkPrimeSync( - Buffer.from([0x1]), - { - fast: true, - trialDivision: true, - checks: 10 - })); + !checkPrimeSync(Buffer.from([0x1]), { + fast: true, + trialDivision: true, + checks: 10, + }) + ); ok(!checkPrimeSync(Buffer.from([0x1]))); ok(checkPrimeSync(Buffer.from([0x2]))); @@ -63,14 +56,14 @@ export const test = { ['hello', false, 123].forEach((i) => { throws(() => generatePrimeSync(80, i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); for (const checks of ['hello', {}, []]) { throws(() => checkPrimeSync(2n, { checks }), { code: 'ERR_INVALID_ARG_TYPE', - message: /checks/ + message: /checks/, }); } @@ -78,65 +71,65 @@ export const test = { ['hello', false, {}, []].forEach((i) => { throws(() => generatePrime(i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrimeSync(i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); ['hello', false, 123].forEach((i) => { throws(() => generatePrime(80, i, {}), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrimeSync(80, i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); ['hello', false, 123].forEach((i) => { throws(() => generatePrime(80, {}), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); [-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => { throws(() => generatePrime(-1), { code: 'ERR_OUT_OF_RANGE', - message: />= 1 && <= 2147483647/ + message: />= 1 && <= 2147483647/, }); throws(() => generatePrimeSync(size), { code: 'ERR_OUT_OF_RANGE', - message: />= 1 && <= 2147483647/ + message: />= 1 && <= 2147483647/, }); }); // TODO: Fix and enable asynchronous tests ['test', -1, {}, []].forEach((i) => { throws(() => generatePrime(8, { safe: i }, () => {}), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrime(8, { rem: i }, () => {}), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrime(8, { add: i }, () => {}), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrimeSync(8, { safe: i }), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrimeSync(8, { rem: i }), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); throws(() => generatePrimeSync(8, { add: i }), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); { // Negative BigInts should not be converted to 0 silently. throws(() => generatePrime(20, { add: -1n }, () => {}), { - code: 'ERR_OUT_OF_RANGE' + code: 'ERR_OUT_OF_RANGE', }); throws(() => generatePrime(20, { rem: -1n }, () => {}), { @@ -186,7 +179,7 @@ export const test = { p.resolve(); }); await p.promise; - } + } { const prime = generatePrimeSync(32, { safe: true }); @@ -205,17 +198,14 @@ export const test = { { const p = deferredPromise(); - generatePrime( - 32, - { add: add_buf, rem: rem_buf }, - (err, prime) => { - if (err) return p.reject(err); - ok(checkPrimeSync(prime)); - const buf = Buffer.from(prime); - const val = buf.readUInt32BE(); - strictEqual(val % add, rem); - p.resolve(); - }); + generatePrime(32, { add: add_buf, rem: rem_buf }, (err, prime) => { + if (err) return p.reject(err); + ok(checkPrimeSync(prime)); + const buf = Buffer.from(prime); + const val = buf.readUInt32BE(); + strictEqual(val % add, rem); + p.resolve(); + }); await p.promise; } @@ -228,7 +218,10 @@ export const test = { } { - const prime = generatePrimeSync(32, { add: BigInt(add), rem: BigInt(rem) }); + const prime = generatePrimeSync(32, { + add: BigInt(add), + rem: BigInt(rem), + }); ok(checkPrimeSync(prime)); const buf = Buffer.from(prime); const val = buf.readUInt32BE(); @@ -237,91 +230,121 @@ export const test = { { const p = deferredPromise(); - generatePrime(128, { - bigint: true, - add: 5n - }, (err, prime) => { - // Fails because the add option is not a supported value - if (err) return p.reject(err); - }); + generatePrime( + 128, + { + bigint: true, + add: 5n, + }, + (err, prime) => { + // Fails because the add option is not a supported value + if (err) return p.reject(err); + } + ); await rejects(p.promise); } { const p = deferredPromise(); - generatePrime(128, { - bigint: true, - safe: true, - add: 5n - }, (err, prime) => { - // Fails because the add option is not a supported value - if (err) return p.reject(err); - }); + generatePrime( + 128, + { + bigint: true, + safe: true, + add: 5n, + }, + (err, prime) => { + // Fails because the add option is not a supported value + if (err) return p.reject(err); + } + ); await rejects(p.promise); } // This is impossible because it implies (prime % 2**64) == 1 and // prime < 2**64, meaning prime = 1, but 1 is not prime. for (const add of [2n ** 64n, 2n ** 65n]) { - throws(() => { - generatePrimeSync(64, { add }); - }, { - name: 'RangeError' - }); + throws( + () => { + generatePrimeSync(64, { add }); + }, + { + name: 'RangeError', + } + ); } // Any parameters with rem >= add lead to an impossible condition. for (const rem of [7n, 8n, 3000n]) { - throws(() => { - generatePrimeSync(64, { add: 7n, rem }); - }, { - name: 'RangeError' - }); + throws( + () => { + generatePrimeSync(64, { add: 7n, rem }); + }, + { + name: 'RangeError', + } + ); } // This is possible, but not allowed. It implies prime == 7, which means that // we did not actually generate a random prime. - throws(() => { - generatePrimeSync(3, { add: 8n, rem: 7n }); - }, { - name: 'RangeError' - }); + throws( + () => { + generatePrimeSync(3, { add: 8n, rem: 7n }); + }, + { + name: 'RangeError', + } + ); // We only allow specific values of add and rem - throws(() => generatePrimeSync(8, { - add: 7n, - rem: 1n, - }), { - name: 'RangeError' - }); - throws(() => generatePrimeSync(8, { - add: 12n, - rem: 10n, - }), { - name: 'RangeError' - }); - throws(() => generatePrimeSync(8, { - add: 12n, - }), { - name: 'RangeError' - }); + throws( + () => + generatePrimeSync(8, { + add: 7n, + rem: 1n, + }), + { + name: 'RangeError', + } + ); + throws( + () => + generatePrimeSync(8, { + add: 12n, + rem: 10n, + }), + { + name: 'RangeError', + } + ); + throws( + () => + generatePrimeSync(8, { + add: 12n, + }), + { + name: 'RangeError', + } + ); [1, 'hello', {}, []].forEach((i) => { throws(() => checkPrime(i), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); for (const checks of ['hello', {}, []]) { throws(() => checkPrime(2n, { checks }, () => {}), { code: 'ERR_INVALID_ARG_TYPE', - message: /checks/ + message: /checks/, }); throws(() => checkPrimeSync(2n, { checks }), { code: 'ERR_INVALID_ARG_TYPE', - message: /checks/ + message: /checks/, }); } + // prettier-ignore for (const checks of [-(2 ** 31), -1, 2 ** 31, 2 ** 32 - 1, 2 ** 32, 2 ** 50]) { throws(() => checkPrime(2n, { checks }, () => {}), { code: 'ERR_OUT_OF_RANGE', @@ -334,21 +357,26 @@ export const test = { } ok( - !checkPrimeSync( - Buffer.from([0x1]), - { - fast: true, - trialDivision: true, - checks: 10 - })); - - throws(() => { - generatePrimeSync(32, { bigint: '' }); - }, { code: 'ERR_INVALID_ARG_TYPE' }); - - throws(() => { - generatePrime(32, { bigint: '' }, () => {}); - }, { code: 'ERR_INVALID_ARG_TYPE' }); + !checkPrimeSync(Buffer.from([0x1]), { + fast: true, + trialDivision: true, + checks: 10, + }) + ); + + throws( + () => { + generatePrimeSync(32, { bigint: '' }); + }, + { code: 'ERR_INVALID_ARG_TYPE' } + ); + + throws( + () => { + generatePrime(32, { bigint: '' }, () => {}); + }, + { code: 'ERR_INVALID_ARG_TYPE' } + ); { const prime = generatePrimeSync(3, { bigint: true }); @@ -360,7 +388,7 @@ export const test = { if (err) return p.reject(err); p.resolve(result); }); - await p.promise + await p.promise; } { @@ -377,11 +405,11 @@ export const test = { }); await p.promise; } - } + }, }; export const timingSafeEqualTest = { test() { timingSafeEqual(new Uint8Array(1), new Uint8Array(1)); - } + }, }; diff --git a/src/workerd/api/node/tests/crypto_scrypt-test.js b/src/workerd/api/node/tests/crypto_scrypt-test.js index f84f337840d..8a3cfbc4f25 100644 --- a/src/workerd/api/node/tests/crypto_scrypt-test.js +++ b/src/workerd/api/node/tests/crypto_scrypt-test.js @@ -25,20 +25,11 @@ 'use strict'; -import { - strictEqual, - throws, - rejects, -} from 'node:assert'; +import { strictEqual, throws, rejects } from 'node:assert'; -import { - scrypt, - scryptSync, -} from 'node:crypto'; +import { scrypt, scryptSync } from 'node:crypto'; -import { - mock, -} from 'node:test'; +import { mock } from 'node:test'; const good = [ // Zero-length key is legal, functions as a parameter validation check. @@ -62,8 +53,8 @@ const good = [ p: 1, r: 1, expected: - '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442' + - 'fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906', + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442' + + 'fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906', }, { pass: 'password', @@ -73,8 +64,8 @@ const good = [ p: 16, r: 8, expected: - 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162' + - '2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640', + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162' + + '2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640', }, { pass: 'pleaseletmein', @@ -84,8 +75,8 @@ const good = [ p: 1, r: 8, expected: - '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2' + - 'd5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887', + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2' + + 'd5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887', }, { pass: '', @@ -95,8 +86,8 @@ const good = [ parallelization: 1, blockSize: 1, expected: - '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442' + - 'fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906', + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442' + + 'fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906', }, { pass: 'password', @@ -106,8 +97,8 @@ const good = [ parallelization: 16, blockSize: 8, expected: - 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162' + - '2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640', + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162' + + '2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640', }, { pass: 'pleaseletmein', @@ -117,21 +108,21 @@ const good = [ parallelization: 1, blockSize: 8, expected: - '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2' + - 'd5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887', + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2' + + 'd5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887', }, ]; // Test vectors that should fail. const bad = [ - { N: 1, p: 1, r: 1 }, // N < 2 - { N: 3, p: 1, r: 1 }, // Not power of 2. + { N: 1, p: 1, r: 1 }, // N < 2 + { N: 3, p: 1, r: 1 }, // Not power of 2. ]; // Test vectors where 128*N*r exceeds maxmem. const toobig = [ - { N: 2 ** 16, p: 1, r: 1 }, // N >= 2**(r*16) - { N: 2, p: 2 ** 30, r: 1 }, // p > (2**30-1)/r + { N: 2 ** 16, p: 1, r: 1 }, // N >= 2**(r*16) + { N: 2, p: 2 ** 30, r: 1 }, // p > (2**30-1)/r { N: 2 ** 20, p: 1, r: 8 }, { N: 2 ** 10, p: 1, r: 8, maxmem: 2 ** 20 }, ]; @@ -162,7 +153,7 @@ const badargs = [ expected: { code: 'ERR_INVALID_ARG_TYPE', message: /"keylen"/ }, }, { - args: ['', '', .42], + args: ['', '', 0.42], expected: { code: 'ERR_OUT_OF_RANGE', message: /"keylen"/ }, }, { @@ -198,8 +189,8 @@ export const goodTests = { await promise; strictEqual(fn.mock.calls.length, 1); } - } -} + }, +}; export const badTests = { async test() { @@ -215,23 +206,23 @@ export const badTests = { throws(() => scryptSync('pass', 'salt', 1, { N: 1, cost: 1 })); throws(() => scryptSync('pass', 'salt', 1, { p: 1, parallelization: 1 })); throws(() => scryptSync('pass', 'salt', 1, { r: 1, blockSize: 1 })); - } + }, }; export const tooBigTests = { async test() { - for (const options of toobig) { - const { promise, reject } = Promise.withResolvers(); - const fn = mock.fn((err, actual) => { - if (err) reject(err); - }); - scrypt('pass', 'salt', 1, options, fn); - await rejects(promise); - strictEqual(fn.mock.calls.length, 1); + for (const options of toobig) { + const { promise, reject } = Promise.withResolvers(); + const fn = mock.fn((err, actual) => { + if (err) reject(err); + }); + scrypt('pass', 'salt', 1, options, fn); + await rejects(promise); + strictEqual(fn.mock.calls.length, 1); - throws(() => scryptSync('pass', 'salt', 1, options)); - } - } + throws(() => scryptSync('pass', 'salt', 1, options)); + } + }, }; export const defaultsTest = { @@ -248,7 +239,7 @@ export const defaultsTest = { scrypt('pass', 'salt', 1, fn); await promise; strictEqual(fn.mock.calls.length, 1); - } + }, }; export const badArgsTest = { @@ -262,5 +253,5 @@ export const badArgsTest = { throws(() => scrypt('', '', 42, {}, null)); throws(() => scrypt('', '', 42, {})); throws(() => scrypt('', '', 42, {}, {})); - } -} + }, +}; diff --git a/src/workerd/api/node/tests/crypto_spkac-test.js b/src/workerd/api/node/tests/crypto_spkac-test.js index 4e1895db95d..5be0aa9a036 100644 --- a/src/workerd/api/node/tests/crypto_spkac-test.js +++ b/src/workerd/api/node/tests/crypto_spkac-test.js @@ -23,16 +23,18 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; import * as assert from 'node:assert'; import { Certificate } from 'node:crypto'; -const valid = Buffer.from("MIICUzCCATswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC33FiIiiexwLe/P8DZx5HsqFlmUO7/lvJ7necJVNwqdZ3ax5jpQB0p6uxfqeOvzcN3k5V7UFb/Am+nkSNZMAZhsWzCU2Z4Pjh50QYz3f0Hour7/yIGStOLyYY3hgLK2K8TbhgjQPhdkw9+QtKlpvbL8fLgONAoGrVOFnRQGcr70iFffsm79mgZhKVMgYiHPJqJgGHvCtkGg9zMgS7p63+Q3ZWedtFS2RhMX3uCBy/mH6EOlRCNBbRmA4xxNzyf5GQaki3T+Iz9tOMjdPP+CwV2LqEdylmBuik8vrfTb3qIHLKKBAI8lXN26wWtA3kN4L7NP+cbKlCRlqctvhmylLH1AgMBAAEWE3RoaXMtaXMtYS1jaGFsbGVuZ2UwDQYJKoZIhvcNAQEEBQADggEBAIozmeW1kfDfAVwRQKileZGLRGCD7AjdHLYEe16xTBPve8Af1bDOyuWsAm4qQLYA4FAFROiKeGqxCtIErEvm87/09tCfF1My/1Uj+INjAk39DK9J9alLlTsrwSgd1lb3YlXY7TyitCmh7iXLo4pVhA2chNA3njiMq3CUpSvGbpzrESL2dv97lv590gUD988wkTDVyYsf0T8+X0Kww3AgPWGji+2f2i5/jTfD/s1lK1nqi7ZxFm0pGZoy1MJ51SCEy7Y82ajroI+5786nC02mo9ak7samca4YDZOoxN4d3tax4B/HDF5dqJSm1/31xYLDTfujCM5FkSjRc4m6hnriEkc="); +const valid = Buffer.from( + 'MIICUzCCATswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC33FiIiiexwLe/P8DZx5HsqFlmUO7/lvJ7necJVNwqdZ3ax5jpQB0p6uxfqeOvzcN3k5V7UFb/Am+nkSNZMAZhsWzCU2Z4Pjh50QYz3f0Hour7/yIGStOLyYY3hgLK2K8TbhgjQPhdkw9+QtKlpvbL8fLgONAoGrVOFnRQGcr70iFffsm79mgZhKVMgYiHPJqJgGHvCtkGg9zMgS7p63+Q3ZWedtFS2RhMX3uCBy/mH6EOlRCNBbRmA4xxNzyf5GQaki3T+Iz9tOMjdPP+CwV2LqEdylmBuik8vrfTb3qIHLKKBAI8lXN26wWtA3kN4L7NP+cbKlCRlqctvhmylLH1AgMBAAEWE3RoaXMtaXMtYS1jaGFsbGVuZ2UwDQYJKoZIhvcNAQEEBQADggEBAIozmeW1kfDfAVwRQKileZGLRGCD7AjdHLYEe16xTBPve8Af1bDOyuWsAm4qQLYA4FAFROiKeGqxCtIErEvm87/09tCfF1My/1Uj+INjAk39DK9J9alLlTsrwSgd1lb3YlXY7TyitCmh7iXLo4pVhA2chNA3njiMq3CUpSvGbpzrESL2dv97lv590gUD988wkTDVyYsf0T8+X0Kww3AgPWGji+2f2i5/jTfD/s1lK1nqi7ZxFm0pGZoy1MJ51SCEy7Y82ajroI+5786nC02mo9ak7samca4YDZOoxN4d3tax4B/HDF5dqJSm1/31xYLDTfujCM5FkSjRc4m6hnriEkc=' +); -const invalid = Buffer.from("UzCCATswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC33FiIiiexwLe/P8DZx5HsqFlmUO7/lvJ7necJVNwqdZ3ax5jpQB0p6uxfqeOvzcN3k5V7UFb/Am+nkSNZMAZhsWzCU2Z4Pjh50QYz3f0Hour7/yIGStOLyYY3hgLK2K8TbhgjQPhdkw9+QtKlpvbL8fLgONAoGrVOFnRQGcr70iFffsm79mgZhKVMgYiHPJqJgGHvCtkGg9zMgS7p63+Q3ZWedtFS2RhMX3uCBy/mH6EOlRCNBbRmA4xxNzyf5GQaki3T+Iz9tOMjdPP+CwV2LqEdylmBuik8vrfTb3qIHLKKBAI8lXN26wWtA3kN4L7NP+cbKlCRlqctvhmylLH1AgMBAAEWE3RoaXMtaXMtYS1jaGFsbGVuZ2UwDQYJKoZIhvcNAQEEBQADggEBAIozmeW1kfDfAVwRQKileZGLRGCD7AjdHLYEe16xTBPve8Af1bDOyuWsAm4qQLYA4FAFROiKeGqxCtIErEvm87/09tCfF1My/1Uj+INjAk39DK9J9alLlTsrwSgd1lb3YlXY7TyitCmh7iXLo4pVhA2chNA3njiMq3CUpSvGbpzrESL2dv97lv590gUD988wkTDVyYsf0T8+X0Kww3AgPWGji+2f2i5/jTfD/s1lK1nqi7ZxFm0pGZoy1MJ51SCEy7Y82ajroI+5786nC02mo9ak7samca4YDZOoxN4d3tax4B/HDF5dqJSm1/31xYLDTfujCM5FkSjRc4m6hnriEkc="); +const invalid = Buffer.from( + 'UzCCATswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC33FiIiiexwLe/P8DZx5HsqFlmUO7/lvJ7necJVNwqdZ3ax5jpQB0p6uxfqeOvzcN3k5V7UFb/Am+nkSNZMAZhsWzCU2Z4Pjh50QYz3f0Hour7/yIGStOLyYY3hgLK2K8TbhgjQPhdkw9+QtKlpvbL8fLgONAoGrVOFnRQGcr70iFffsm79mgZhKVMgYiHPJqJgGHvCtkGg9zMgS7p63+Q3ZWedtFS2RhMX3uCBy/mH6EOlRCNBbRmA4xxNzyf5GQaki3T+Iz9tOMjdPP+CwV2LqEdylmBuik8vrfTb3qIHLKKBAI8lXN26wWtA3kN4L7NP+cbKlCRlqctvhmylLH1AgMBAAEWE3RoaXMtaXMtYS1jaGFsbGVuZ2UwDQYJKoZIhvcNAQEEBQADggEBAIozmeW1kfDfAVwRQKileZGLRGCD7AjdHLYEe16xTBPve8Af1bDOyuWsAm4qQLYA4FAFROiKeGqxCtIErEvm87/09tCfF1My/1Uj+INjAk39DK9J9alLlTsrwSgd1lb3YlXY7TyitCmh7iXLo4pVhA2chNA3njiMq3CUpSvGbpzrESL2dv97lv590gUD988wkTDVyYsf0T8+X0Kww3AgPWGji+2f2i5/jTfD/s1lK1nqi7ZxFm0pGZoy1MJ51SCEy7Y82ajroI+5786nC02mo9ak7samca4YDZOoxN4d3tax4B/HDF5dqJSm1/31xYLDTfujCM5FkSjRc4m6hnriEkc=' +); const key = Buffer.from(`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9xYiIonscC3vz/A2ceR @@ -48,7 +50,6 @@ const challenge = 'this-is-a-challenge'; export const spkac = { test() { - // In workerd, this following check works fine but in the internal // system we prevent anyone from creating a TypedArray with this // size... which means this check passes in workerd but fails internally, @@ -80,13 +81,19 @@ export const spkac = { stripLineEndings(Certificate.exportPublicKey(valid).toString('utf8')), stripLineEndings(key.toString('utf8')) ); - assert.strictEqual(Certificate.exportPublicKey(invalid).toString('utf8'), ''); + assert.strictEqual( + Certificate.exportPublicKey(invalid).toString('utf8'), + '' + ); assert.strictEqual( Certificate.exportChallenge(valid).toString('utf8'), challenge ); - assert.strictEqual(Certificate.exportChallenge(invalid).toString('utf8'), ''); + assert.strictEqual( + Certificate.exportChallenge(invalid).toString('utf8'), + '' + ); const ab = copyArrayBuffer(key); assert.ok(!Certificate.verifySpkac(ab)); @@ -102,7 +109,7 @@ export const spkac = { assert.throws(() => Certificate.exportPublicKey(val), errObj); assert.throws(() => Certificate.exportChallenge(val), errObj); }); - } + }, }; function stripLineEndings(obj) { diff --git a/src/workerd/api/node/tests/crypto_x509-test.js b/src/workerd/api/node/tests/crypto_x509-test.js index 0e63a28c7bf..b82c7d55b01 100644 --- a/src/workerd/api/node/tests/crypto_x509-test.js +++ b/src/workerd/api/node/tests/crypto_x509-test.js @@ -26,19 +26,11 @@ /* todo: the following is adopted code, enabling linting one day */ /* eslint-disable */ -import { - deepStrictEqual, - ok, - strictEqual, - throws, -} from 'node:assert'; +import { deepStrictEqual, ok, strictEqual, throws } from 'node:assert'; import { Buffer } from 'node:buffer'; -import { - X509Certificate, - PublicKeyObject, -} from 'node:crypto'; +import { X509Certificate, PublicKeyObject } from 'node:crypto'; const cert = Buffer.from(`-----BEGIN CERTIFICATE----- MIID6DCCAtCgAwIBAgIUFH02wcL3Qgben6tfIibXitsApCYwDQYJKoZIhvcNAQEL @@ -91,34 +83,35 @@ lz88C25ucKA= const der = Buffer.from( '308203e8308202d0a0030201020214147d36c1c2f74206de9fab5f2226d78adb00a42630' + - '0d06092a864886f70d01010b0500307a310b3009060355040613025553310b3009060355' + - '04080c024341310b300906035504070c025346310f300d060355040a0c064a6f79656e74' + - '3110300e060355040b0c074e6f64652e6a73310c300a06035504030c036361313120301e' + - '06092a864886f70d010901161172794074696e79636c6f7564732e6f72673020170d3232' + - '303930333231343033375a180f32323936303631373231343033375a307d310b30090603' + - '55040613025553310b300906035504080c024341310b300906035504070c025346310f30' + - '0d060355040a0c064a6f79656e743110300e060355040b0c074e6f64652e6a73310f300d' + - '06035504030c066167656e74313120301e06092a864886f70d010901161172794074696e' + - '79636c6f7564732e6f726730820122300d06092a864886f70d01010105000382010f0030' + - '82010a0282010100d456320afb20d3827093dc2c4284ed04dfbabd56e1ddae529e28b790' + - 'cd4256db273349f3735ffd337c7a6363ecca5a27b7f73dc7089a96c6d886db0c62388f1c' + - 'dd6a963afcd599d5800e587a11f908960f84ed50ba25a28303ecda6e684fbe7baedc9ce8' + - '801327b1697af25097cee3f175e400984c0db6a8eb87be03b4cf94774ba56fffc8c63c68' + - 'd6adeb60abbe69a7b14ab6a6b9e7baa89b5adab8eb07897c07f6d4fa3d660dff574107d2' + - '8e8f63467a788624c574197693e959cea1362ffae1bba10c8c0d88840abfef103631b2e8' + - 'f5c39b5548a7ea57e8a39f89291813f45a76c448033a2b7ed8403f4baa147cf35e2d2554' + - 'aa65ce49695797095bf4dc6b0203010001a361305f305d06082b06010505070101045130' + - '4f302306082b060105050730018617687474703a2f2f6f6373702e6e6f64656a732e6f72' + - '672f302806082b06010505073002861c687474703a2f2f63612e6e6f64656a732e6f7267' + - '2f63612e63657274300d06092a864886f70d01010b05000382010100c3349810632ccb7d' + - 'a585de3ed51e34ed154f0f7215608cf2701c00eda444dc2427072c8aca4da6472c1d9e68' + - 'f177f99a90a8b5dbf3884586d61cb1c14ea7016c8d38b70d1b46b42947db30edc1e9961e' + - 'd46c0f0e35da427bfbe52900771817e733b371adf19e12137235141a34347db0dfc05579' + - '8b1f269f3bdf5e30ce35d1339d56bb3c570de9096215433047f87ca42447b44e7e6b5d0e' + - '48f7894ab186f85b6b1a74561b520952fea888617f32f582afce1111581cd63efcc68986' + - '00d248bb684dedb9c3d6710c38de9e9bc21f9c3394b729d5f707d64ea890603e5989f8fa' + - '59c19ad1a00732e7adc851b89487cc00799dde068aa64b3b8fd976e8bc113ef2', - 'hex'); + '0d06092a864886f70d01010b0500307a310b3009060355040613025553310b3009060355' + + '04080c024341310b300906035504070c025346310f300d060355040a0c064a6f79656e74' + + '3110300e060355040b0c074e6f64652e6a73310c300a06035504030c036361313120301e' + + '06092a864886f70d010901161172794074696e79636c6f7564732e6f72673020170d3232' + + '303930333231343033375a180f32323936303631373231343033375a307d310b30090603' + + '55040613025553310b300906035504080c024341310b300906035504070c025346310f30' + + '0d060355040a0c064a6f79656e743110300e060355040b0c074e6f64652e6a73310f300d' + + '06035504030c066167656e74313120301e06092a864886f70d010901161172794074696e' + + '79636c6f7564732e6f726730820122300d06092a864886f70d01010105000382010f0030' + + '82010a0282010100d456320afb20d3827093dc2c4284ed04dfbabd56e1ddae529e28b790' + + 'cd4256db273349f3735ffd337c7a6363ecca5a27b7f73dc7089a96c6d886db0c62388f1c' + + 'dd6a963afcd599d5800e587a11f908960f84ed50ba25a28303ecda6e684fbe7baedc9ce8' + + '801327b1697af25097cee3f175e400984c0db6a8eb87be03b4cf94774ba56fffc8c63c68' + + 'd6adeb60abbe69a7b14ab6a6b9e7baa89b5adab8eb07897c07f6d4fa3d660dff574107d2' + + '8e8f63467a788624c574197693e959cea1362ffae1bba10c8c0d88840abfef103631b2e8' + + 'f5c39b5548a7ea57e8a39f89291813f45a76c448033a2b7ed8403f4baa147cf35e2d2554' + + 'aa65ce49695797095bf4dc6b0203010001a361305f305d06082b06010505070101045130' + + '4f302306082b060105050730018617687474703a2f2f6f6373702e6e6f64656a732e6f72' + + '672f302806082b06010505073002861c687474703a2f2f63612e6e6f64656a732e6f7267' + + '2f63612e63657274300d06092a864886f70d01010b05000382010100c3349810632ccb7d' + + 'a585de3ed51e34ed154f0f7215608cf2701c00eda444dc2427072c8aca4da6472c1d9e68' + + 'f177f99a90a8b5dbf3884586d61cb1c14ea7016c8d38b70d1b46b42947db30edc1e9961e' + + 'd46c0f0e35da427bfbe52900771817e733b371adf19e12137235141a34347db0dfc05579' + + '8b1f269f3bdf5e30ce35d1339d56bb3c570de9096215433047f87ca42447b44e7e6b5d0e' + + '48f7894ab186f85b6b1a74561b520952fea888617f32f582afce1111581cd63efcc68986' + + '00d248bb684dedb9c3d6710c38de9e9bc21f9c3394b729d5f707d64ea890603e5989f8fa' + + '59c19ad1a00732e7adc851b89487cc00799dde068aa64b3b8fd976e8bc113ef2', + 'hex' +); const key = Buffer.from(`-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA1FYyCvsg04Jwk9wsQoTtBN+6vVbh3a5Snii3kM1CVtsnM0nz @@ -189,17 +182,18 @@ const legacyObjectCheck = { }, infoAccess: { 'OCSP - URI': ['http://ocsp.nodejs.org/'], - 'CA Issuers - URI': ['http://ca.nodejs.org/ca.cert'] + 'CA Issuers - URI': ['http://ca.nodejs.org/ca.cert'], }, - modulus: 'D456320AFB20D3827093DC2C4284ED04DFBABD56E1DDAE529E28B790CD42' + - '56DB273349F3735FFD337C7A6363ECCA5A27B7F73DC7089A96C6D886DB0C' + - '62388F1CDD6A963AFCD599D5800E587A11F908960F84ED50BA25A28303EC' + - 'DA6E684FBE7BAEDC9CE8801327B1697AF25097CEE3F175E400984C0DB6A8' + - 'EB87BE03B4CF94774BA56FFFC8C63C68D6ADEB60ABBE69A7B14AB6A6B9E7' + - 'BAA89B5ADAB8EB07897C07F6D4FA3D660DFF574107D28E8F63467A788624' + - 'C574197693E959CEA1362FFAE1BBA10C8C0D88840ABFEF103631B2E8F5C3' + - '9B5548A7EA57E8A39F89291813F45A76C448033A2B7ED8403F4BAA147CF3' + - '5E2D2554AA65CE49695797095BF4DC6B', + modulus: + 'D456320AFB20D3827093DC2C4284ED04DFBABD56E1DDAE529E28B790CD42' + + '56DB273349F3735FFD337C7A6363ECCA5A27B7F73DC7089A96C6D886DB0C' + + '62388F1CDD6A963AFCD599D5800E587A11F908960F84ED50BA25A28303EC' + + 'DA6E684FBE7BAEDC9CE8801327B1697AF25097CEE3F175E400984C0DB6A8' + + 'EB87BE03B4CF94774BA56FFFC8C63C68D6ADEB60ABBE69A7B14AB6A6B9E7' + + 'BAA89B5ADAB8EB07897C07F6D4FA3D660DFF574107D28E8F63467A788624' + + 'C574197693E959CEA1362FFAE1BBA10C8C0D88840ABFEF103631B2E8F5C3' + + '9B5548A7EA57E8A39F89291813F45A76C448033A2B7ED8403F4BAA147CF3' + + '5E2D2554AA65CE49695797095BF4DC6B', bits: 2048, exponent: '0x10001', valid_from: 'Sep 3 21:40:37 2022 GMT', @@ -212,7 +206,7 @@ const legacyObjectCheck = { '51:62:18:39:E2:E2:77:F5:86:11:E8:C0:CA:54:43:7C:76:83:19:05:D0:03:' + '24:21:B8:EB:14:61:FB:24:16:EB:BD:51:1A:17:91:04:30:03:EB:68:5F:DC:' + '86:E1:D1:7C:FB:AF:78:ED:63:5F:29:9C:32:AF:A1:8E:22:96:D1:02', - serialNumber: '147D36C1C2F74206DE9FAB5F2226D78ADB00A426' + serialNumber: '147D36C1C2F74206DE9FAB5F2226D78ADB00A426', }; export const test_ok = { @@ -225,15 +219,21 @@ export const test_ok = { strictEqual(x509.infoAccess, infoAccessCheck); strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT'); strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT'); - strictEqual(x509.fingerprint.length, - '8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53'.length); - strictEqual(x509.fingerprint256, - '2C:62:59:16:91:89:AB:90:6A:3E:98:88:A6:D3:C5:58:58:6C:AE:FF:9C:33:' + - '22:7C:B6:77:D3:34:E7:53:4B:05'); - strictEqual(x509.fingerprint512, - '0B:6F:D0:4D:6B:22:53:99:66:62:51:2D:2C:96:F2:58:3F:95:1C:CC:4C:44:' + - '9D:B5:59:AA:AD:A8:F6:2A:24:8A:BB:06:A5:26:42:52:30:A3:37:61:30:A9:' + - '5A:42:63:E0:21:2F:D6:70:63:07:96:6F:27:A7:78:12:08:02:7A:8B'); + strictEqual( + x509.fingerprint.length, + '8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53'.length + ); + strictEqual( + x509.fingerprint256, + '2C:62:59:16:91:89:AB:90:6A:3E:98:88:A6:D3:C5:58:58:6C:AE:FF:9C:33:' + + '22:7C:B6:77:D3:34:E7:53:4B:05' + ); + strictEqual( + x509.fingerprint512, + '0B:6F:D0:4D:6B:22:53:99:66:62:51:2D:2C:96:F2:58:3F:95:1C:CC:4C:44:' + + '9D:B5:59:AA:AD:A8:F6:2A:24:8A:BB:06:A5:26:42:52:30:A3:37:61:30:A9:' + + '5A:42:63:E0:21:2F:D6:70:63:07:96:6F:27:A7:78:12:08:02:7A:8B' + ); strictEqual(x509.keyUsage, undefined); strictEqual(x509.serialNumber, '147D36C1C2F74206DE9FAB5F2226D78ADB00A426'); @@ -242,15 +242,17 @@ export const test_ok = { ok(x509.publicKey instanceof PublicKeyObject); ok(x509.publicKey.type === 'public'); - strictEqual(x509.toString().replaceAll('\r\n', '\n'), - cert.toString().replaceAll('\r\n', '\n')); + strictEqual( + x509.toString().replaceAll('\r\n', '\n'), + cert.toString().replaceAll('\r\n', '\n') + ); strictEqual(x509.toJSON(), x509.toString()); // TODO(soon): Need to implement createPrivateKey this check // const privateKey = createPrivateKey(key); // ok(x509.checkPrivateKey(privateKey)); throws(() => x509.checkPrivateKey(x509.publicKey), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); strictEqual(x509.checkIP('127.0.0.1'), undefined); @@ -278,7 +280,7 @@ export const test_ok = { ].forEach((key) => { [1, '', {}].forEach((i) => { throws(() => x509.checkHost('agent1', { [key]: i }), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); }); }); @@ -307,13 +309,9 @@ export const test_ok = { strictEqual(legacyObject.valid_from, legacyObjectCheck.valid_from); strictEqual(legacyObject.valid_to, legacyObjectCheck.valid_to); strictEqual(legacyObject.fingerprint, legacyObjectCheck.fingerprint); - strictEqual( - legacyObject.fingerprint256, - legacyObjectCheck.fingerprint256); - strictEqual( - legacyObject.serialNumber, - legacyObjectCheck.serialNumber); - } + strictEqual(legacyObject.fingerprint256, legacyObjectCheck.fingerprint256); + strictEqual(legacyObject.serialNumber, legacyObjectCheck.serialNumber); + }, }; // This X.509 Certificate can be parsed by OpenSSL because it contains a diff --git a/src/workerd/api/node/tests/diagnostics-channel-test.js b/src/workerd/api/node/tests/diagnostics-channel-test.js index 0fd06d07ca4..cb102462512 100644 --- a/src/workerd/api/node/tests/diagnostics-channel-test.js +++ b/src/workerd/api/node/tests/diagnostics-channel-test.js @@ -1,7 +1,4 @@ -import { - ok, - strictEqual, -} from 'node:assert'; +import { ok, strictEqual } from 'node:assert'; import { hasSubscribers, @@ -12,9 +9,7 @@ import { Channel, } from 'node:diagnostics_channel'; -import { - AsyncLocalStorage, -} from 'node:async_hooks'; +import { AsyncLocalStorage } from 'node:async_hooks'; function deferredPromise() { let resolve, reject; @@ -55,7 +50,7 @@ export const test_basics = { ok(!hasSubscribers('foo')); await messagePromise.promise; - } + }, }; export const test_tracing = { @@ -104,15 +99,21 @@ export const test_tracing = { promises[1].reject(err); } }, - asyncStart() { promises[2].resolve(); }, - asyncEnd() { promises[3].resolve(); }, - error() { promises[4].resolve(); }, + asyncStart() { + promises[2].resolve(); + }, + asyncEnd() { + promises[3].resolve(); + }, + error() { + promises[4].resolve(); + }, }); tc.tracePromise(async () => { throw new Error('boom'); }, context); - await Promise.all(promises.map(p => p.promise)); - } + await Promise.all(promises.map((p) => p.promise)); + }, }; diff --git a/src/workerd/api/node/tests/mimetype-test.js b/src/workerd/api/node/tests/mimetype-test.js index e5c227b980e..3aa63b1522a 100644 --- a/src/workerd/api/node/tests/mimetype-test.js +++ b/src/workerd/api/node/tests/mimetype-test.js @@ -1,12 +1,7 @@ -import { - deepStrictEqual, - ok, - strictEqual, -} from 'node:assert'; +import { deepStrictEqual, ok, strictEqual } from 'node:assert'; import { MIMEType } from 'node:util'; - export const test_ok = { test() { const mt = new MIMEType('TeXt/PlAiN; ChArsEt="utf-8"'); @@ -24,18 +19,14 @@ export const test_ok = { deepStrictEqual(Array.from(mt.params), [ ['charset', 'utf-8'], - ['boundary', 'foo'] + ['boundary', 'foo'], ]); - deepStrictEqual(Array.from(mt.params.keys()), [ - 'charset', 'boundary' - ]); + deepStrictEqual(Array.from(mt.params.keys()), ['charset', 'boundary']); - deepStrictEqual(Array.from(mt.params.values()), [ - 'utf-8', 'foo' - ]); + deepStrictEqual(Array.from(mt.params.values()), ['utf-8', 'foo']); mt.params.delete('boundary'); ok(!mt.params.has('boundary')); - } + }, }; diff --git a/src/workerd/api/node/tests/node-compat-v2-test.js b/src/workerd/api/node/tests/node-compat-v2-test.js index 503ac6b1ad4..5b3e916a788 100644 --- a/src/workerd/api/node/tests/node-compat-v2-test.js +++ b/src/workerd/api/node/tests/node-compat-v2-test.js @@ -26,7 +26,7 @@ export const nodeJsExpectedGlobals = { assert.strictEqual(process, globalThis.process); assert.strictEqual(global, globalThis); - } + }, }; export const nodeJsGetBuiltins = { @@ -35,7 +35,7 @@ export const nodeJsGetBuiltins = { const { default: fs } = await import('node:fs'); const { default: path } = await import('node:path'); - await import ('node:path'); + await import('node:path'); // But process.getBuiltinModule should always return the built-in module. const builtInPath = process.getBuiltinModule('node:path'); @@ -62,18 +62,20 @@ export const nodeJsGetBuiltins = { const socket = await import('cloudflare:sockets'); assert.strictEqual(process.getBuiltinModule('cloudflare:sockets'), socket); - } + }, }; export const nodeJsEventsExports = { async test() { // Expected node:events exports should be present - const { EventEmitter, getMaxListeners, usingDomains } = await import('node:events'); + const { EventEmitter, getMaxListeners, usingDomains } = await import( + 'node:events' + ); assert.notEqual(getMaxListeners, undefined); assert.strictEqual(getMaxListeners, EventEmitter.getMaxListeners); assert.notEqual(usingDomains, undefined); assert.strictEqual(usingDomains, EventEmitter.usingDomains); - } + }, }; export const nodeJsBufferExports = { @@ -86,29 +88,31 @@ export const nodeJsBufferExports = { assert.strictEqual(btoa, globalThis.btoa); assert.notEqual(Blob, undefined); assert.strictEqual(Blob, globalThis.Blob); - } + }, }; export const nodeJsSetImmediate = { async test() { const als = new AsyncLocalStorage(); const { promise, resolve } = Promise.withResolvers(); - als.run('abc', () => setImmediate((a) => { - assert.strictEqual(als.getStore(), 'abc'); - resolve(a); - }, 1)); + als.run('abc', () => + setImmediate((a) => { + assert.strictEqual(als.getStore(), 'abc'); + resolve(a); + }, 1) + ); assert.strictEqual(await promise, 1); const i = setImmediate(() => { throw new Error('should not have fired'); }); - i[Symbol.dispose](); // Calls clear immediate - i[Symbol.dispose](); // Should be a no-op + i[Symbol.dispose](); // Calls clear immediate + i[Symbol.dispose](); // Should be a no-op const i2 = setImmediate(() => { throw new Error('should not have fired'); }); clearImmediate(i2); clearImmediate(i2); // clearing twice works fine - } + }, }; diff --git a/src/workerd/api/node/tests/path-test.js b/src/workerd/api/node/tests/path-test.js index 0d384319ba0..a56e70fec76 100644 --- a/src/workerd/api/node/tests/path-test.js +++ b/src/workerd/api/node/tests/path-test.js @@ -22,16 +22,18 @@ import { default as path } from 'node:path'; export const test_path = { test(ctrl, env, ctx) { - // Test thrown TypeErrors const typeErrorTests = [true, false, 7, null, {}, undefined, [], NaN]; function fail(fn) { const args = Array.from(arguments).slice(1); - throws(() => { - fn.apply(null, args); - }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' }); + throws( + () => { + fn.apply(null, args); + }, + { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' } + ); } typeErrorTests.forEach((test) => { @@ -67,7 +69,7 @@ export const test_path = { strictEqual(path.posix.delimiter, ':'); strictEqual(path, path.posix); - } + }, }; export const test_path_zero_length_strings = { @@ -95,7 +97,7 @@ export const test_path_zero_length_strings = { strictEqual(path.relative('', '/'), ''); strictEqual(path.relative('/', ''), ''); strictEqual(path.relative('/', '/'), ''); - } + }, }; export const test_path_resolve = { @@ -112,16 +114,15 @@ export const test_path_resolve = { [['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js'], ]; resolveTests.forEach(([test, expected]) => { - const actual = path.resolve.apply(null, test); - const message = - `path.posix.resolve(${test.map(JSON.stringify).join(',')})\n expect=${ - JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; - if (actual !== expected) - failures.push(message); + const actual = path.resolve.apply(null, test); + const message = `path.posix.resolve(${test.map(JSON.stringify).join(',')})\n expect=${JSON.stringify( + expected + )}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected) failures.push(message); }); strictEqual(failures.length, 0, failures.join('\n')); - } -} + }, +}; export const test_path_relative = { test(ctrl, env, ctx) { @@ -146,14 +147,17 @@ export const test_path_relative = { const actual = path.relative(test[0], test[1]); const expected = test[2]; if (actual !== expected) { - const message = `path.posix.relative(${ - test.slice(0, 2).map(JSON.stringify).join(',')})\n expect=${ - JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + const message = `path.posix.relative(${test + .slice(0, 2) + .map(JSON.stringify) + .join(',')})\n expect=${JSON.stringify( + expected + )}\n actual=${JSON.stringify(actual)}`; failures.push(`\n${message}`); } }); strictEqual(failures.length, 0, failures.join('')); - } + }, }; export const test_path_parse_format = { @@ -214,19 +218,21 @@ export const test_path_parse_format = { ['//', { root: '/', dir: '/', base: '', ext: '', name: '' }], ['///', { root: '/', dir: '/', base: '', ext: '', name: '' }], ['/foo///', { root: '/', dir: '/', base: 'foo', ext: '', name: 'foo' }], - ['/foo///bar.baz', - { root: '/', dir: '/foo//', base: 'bar.baz', ext: '.baz', name: 'bar' }, + [ + '/foo///bar.baz', + { root: '/', dir: '/foo//', base: 'bar.baz', ext: '.baz', name: 'bar' }, ], ]; const failures = []; trailingTests.forEach((test) => { const actual = path.parse(test[0]); const expected = test[1]; - const message = `path.posix.parse(${JSON.stringify(test[0])})\n expect=${ - JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + const message = `path.posix.parse(${JSON.stringify(test[0])})\n expect=${JSON.stringify( + expected + )}\n actual=${JSON.stringify(actual)}`; const actualKeys = Object.keys(actual); const expectedKeys = Object.keys(expected); - let failed = (actualKeys.length !== expectedKeys.length); + let failed = actualKeys.length !== expectedKeys.length; if (!failed) { for (let i = 0; i < actualKeys.length; ++i) { const key = actualKeys[i]; @@ -236,19 +242,21 @@ export const test_path_parse_format = { } } } - if (failed) - failures.push(`\n${message}`); + if (failed) failures.push(`\n${message}`); }); strictEqual(failures.length, 0, failures.join('')); function checkErrors() { errors.forEach(({ method, input }) => { - throws(() => { - path[method].apply(path, input); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' - }); + throws( + () => { + path[method].apply(path, input); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } + ); }); } @@ -275,24 +283,30 @@ export const test_path_parse_format = { }); [null, undefined, 1, true, false, 'string'].forEach((pathObject) => { - throws(() => { - path.format(pathObject); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); + throws( + () => { + path.format(pathObject); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } + ); }); } // See https://github.com/nodejs/node/issues/44343 strictEqual(path.format({ name: 'x', ext: 'png' }), 'x.png'); strictEqual(path.format({ name: 'x', ext: '.png' }), 'x.png'); - } + }, }; export const test_path_normalize = { test(ctrl, env, ctx) { - strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'), 'fixtures/b/c.js'); + strictEqual( + path.posix.normalize('./fixtures///b/../b/c.js'), + 'fixtures/b/c.js' + ); strictEqual(path.posix.normalize('/foo/../../../bar'), '/bar'); strictEqual(path.posix.normalize('a//b//../b'), 'a/b'); strictEqual(path.posix.normalize('a//b//./c'), 'a/b/c'); @@ -305,18 +319,25 @@ export const test_path_normalize = { strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../'); strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..'); strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar'); - strictEqual(path.posix.normalize('../.../.././.../../../bar'), - '../../bar'); - strictEqual(path.posix.normalize('../../../foo/../../../bar'), - '../../../../../bar'); - strictEqual(path.posix.normalize('../../../foo/../../../bar/../../'), - '../../../../../../'); - strictEqual(path.posix.normalize('../foobar/barfoo/foo/../../../bar/../../'), - '../../'); - strictEqual(path.posix.normalize('../.../../foobar/../../../bar/../../baz'), - '../../../../baz'); + strictEqual(path.posix.normalize('../.../.././.../../../bar'), '../../bar'); + strictEqual( + path.posix.normalize('../../../foo/../../../bar'), + '../../../../../bar' + ); + strictEqual( + path.posix.normalize('../../../foo/../../../bar/../../'), + '../../../../../../' + ); + strictEqual( + path.posix.normalize('../foobar/barfoo/foo/../../../bar/../../'), + '../../' + ); + strictEqual( + path.posix.normalize('../.../../foobar/../../../bar/../../baz'), + '../../../../baz' + ); strictEqual(path.posix.normalize('foo/bar\\baz'), 'foo/bar\\baz'); - } + }, }; export const test_path_join = { @@ -379,13 +400,14 @@ export const test_path_join = { const expected = test[1]; if (actual !== expected && actualAlt !== expected) { const delimiter = test[0].map(JSON.stringify).join(','); - const message = `path.posix.join(${delimiter})\n expect=${ - JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + const message = `path.posix.join(${delimiter})\n expect=${JSON.stringify( + expected + )}\n actual=${JSON.stringify(actual)}`; failures.push(`\n${message}`); } }); strictEqual(failures.length, 0, failures.join('')); - } + }, }; export const test_path_isabsolute = { @@ -398,7 +420,7 @@ export const test_path_isabsolute = { strictEqual(path.isAbsolute('/home/foo/..'), true); strictEqual(path.isAbsolute('bar/'), false); strictEqual(path.isAbsolute('./baz'), false); - } + }, }; export const test_path_extname = { @@ -452,10 +474,10 @@ export const test_path_extname = { ].forEach((test) => { const expected = test[1]; const actual = path.extname(test[0]); - const message = `path.posix.extname(${JSON.stringify(test[0])})\n expect=${ - JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; - if (actual !== expected) - failures.push(`\n${message}`); + const message = `path.posix.extname(${JSON.stringify(test[0])})\n expect=${JSON.stringify( + expected + )}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected) failures.push(`\n${message}`); }); strictEqual(failures.length, 0, failures.join('')); @@ -469,7 +491,7 @@ export const test_path_extname = { strictEqual(path.posix.extname('file\\\\'), ''); strictEqual(path.posix.extname('file.\\'), '.\\'); strictEqual(path.posix.extname('file.\\\\'), '.\\\\'); - } + }, }; export const test_path_dirname = { @@ -490,7 +512,7 @@ export const test_path_dirname = { strictEqual(path.dirname('////'), '/'); strictEqual(path.dirname('//a'), '//'); strictEqual(path.dirname('foo'), '.'); - } + }, }; export const test_path_basename = { @@ -526,8 +548,10 @@ export const test_path_basename = { strictEqual(path.basename('a', 'a'), ''); // On unix a backslash is just treated as any other character. - strictEqual(path.posix.basename('\\dir\\basename.ext'), - '\\dir\\basename.ext'); + strictEqual( + path.posix.basename('\\dir\\basename.ext'), + '\\dir\\basename.ext' + ); strictEqual(path.posix.basename('\\basename.ext'), '\\basename.ext'); strictEqual(path.posix.basename('basename.ext'), 'basename.ext'); strictEqual(path.posix.basename('basename.ext\\'), 'basename.ext\\'); @@ -537,7 +561,9 @@ export const test_path_basename = { // POSIX filenames may include control characters // c.f. http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html const controlCharFilename = `Icon${String.fromCharCode(13)}`; - strictEqual(path.posix.basename(`/a/b/${controlCharFilename}`), - controlCharFilename); - } + strictEqual( + path.posix.basename(`/a/b/${controlCharFilename}`), + controlCharFilename + ); + }, }; diff --git a/src/workerd/api/node/tests/streams-test.js b/src/workerd/api/node/tests/streams-test.js index 0fabc42e8e6..372a8bddd40 100644 --- a/src/workerd/api/node/tests/streams-test.js +++ b/src/workerd/api/node/tests/streams-test.js @@ -18,9 +18,7 @@ import { throws, } from 'node:assert'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; import { Readable, @@ -38,14 +36,10 @@ import { promises, } from 'node:stream'; -import { - ByteLengthQueuingStrategy, -} from 'node:stream/web'; +import { ByteLengthQueuingStrategy } from 'node:stream/web'; strictEqual(ByteLengthQueuingStrategy, globalThis.ByteLengthQueuingStrategy); -import { - EventEmitter, -} from 'node:events'; +import { EventEmitter } from 'node:events'; function deferredPromise() { let resolve, reject; @@ -70,7 +64,7 @@ function countedDeferred(n, action) { resolve(...args) { action(...args); if (--n === 0) resolve(); - } + }, }; } @@ -80,8 +74,11 @@ export const legacyAliases = { strictEqual(Writable, (await import('node:_stream_writable')).Writable); strictEqual(Duplex, (await import('node:_stream_duplex')).Duplex); strictEqual(Transform, (await import('node:_stream_transform')).Transform); - strictEqual(PassThrough, (await import('node:_stream_passthrough')).PassThrough); - } + strictEqual( + PassThrough, + (await import('node:_stream_passthrough')).PassThrough + ); + }, }; export const addAbortSignalTest = { @@ -98,7 +95,7 @@ export const addAbortSignalTest = { addAbortSignal(ac.signal, 'INVALID_STREAM'); }, /ERR_INVALID_ARG_TYPE/); } - } + }, }; export const autoDestroy = { @@ -118,7 +115,7 @@ export const autoDestroy = { destroy(err, cb) { rDestroyed.resolve(); cb(); - } + }, }); let ended = false; @@ -126,11 +123,7 @@ export const autoDestroy = { r.on('end', rEnded.resolve); r.on('close', rClosed.resolve); - await Promise.all([ - rDestroyed.promise, - rEnded.promise, - rClosed.promise, - ]); + await Promise.all([rDestroyed.promise, rEnded.promise, rClosed.promise]); } { @@ -146,7 +139,7 @@ export const autoDestroy = { destroy(err, cb) { rDestroyed.resolve(); cb(); - } + }, }); w.write('hello'); @@ -177,7 +170,7 @@ export const autoDestroy = { destroy(err, cb) { rDestroyed.resolve(); cb(); - } + }, }); t.write('hello'); @@ -206,13 +199,13 @@ export const autoDestroy = { const r = new Readable({ read() { r2.emit('error', err); - } + }, }); const r2 = new Readable({ autoDestroy: true, destroy(err, cb) { rDestroyed.resolve(err); - } + }, }); r.pipe(r2); @@ -227,7 +220,7 @@ export const autoDestroy = { const r = new Readable({ read() { w.emit('error', err); - } + }, }); const w = new Writable({ @@ -235,7 +228,7 @@ export const autoDestroy = { destroy(err, cb) { rDestroyed.resolve(err); cb(); - } + }, }); r.pipe(w); @@ -243,18 +236,17 @@ export const autoDestroy = { const check = await rDestroyed.promise; strictEqual(check, err); } - } + }, }; export const awaitDrainWritersInSyncRecursionWrite = { async test(ctrl, env, ctx) { - const encode = new PassThrough({ - highWaterMark: 1 + highWaterMark: 1, }); const decode = new PassThrough({ - highWaterMark: 1 + highWaterMark: 1, }); const send = countedDeferred(4, (buf) => { @@ -275,8 +267,7 @@ export const awaitDrainWritersInSyncRecursionWrite = { send.resolve(Buffer.from([0x2])); await send.promise; - - } + }, }; export const backpressure = { @@ -307,7 +298,7 @@ export const backpressure = { // We will be over highWaterMark at this point // but a new call to _read is scheduled anyway. - } + }, }); const closed = deferredPromise(); @@ -316,13 +307,13 @@ export const backpressure = { write(data, enc, cb) { queueMicrotask(cb); if (++writes === 410) closed.resolve(); - } + }, }); rs.pipe(ws); await closed.promise; - } + }, }; export const bigPacket = { @@ -332,8 +323,7 @@ export const bigPacket = { class TestStream extends Transform { _transform(chunk, encoding, done) { // Char 'a' only exists in the last write - if (chunk.includes('a')) - rPassed.resolve(); + if (chunk.includes('a')) rPassed.resolve(); done(); } } @@ -341,7 +331,7 @@ export const bigPacket = { const s1 = new Transform({ transform(chunk, encoding, cb) { queueMicrotask(() => cb(null, chunk)); - } + }, }); const s2 = new PassThrough(); const s3 = new TestStream(); @@ -362,7 +352,7 @@ export const bigPacket = { queueMicrotask(() => s1.write('later')); await rPassed.promise; - } + }, }; export const bigPush = { @@ -371,7 +361,7 @@ export const bigPush = { const r = new Readable({ highWaterMark: 5, - encoding: 'utf8' + encoding: 'utf8', }); let reads = 0; @@ -419,11 +409,8 @@ export const bigPush = { strictEqual(chunk, null); }); - await Promise.all([ - read.promise, - ended.promise, - ]); - } + await Promise.all([read.promise, ended.promise]); + }, }; export const catchRejections = { @@ -433,8 +420,7 @@ export const catchRejections = { const r = new Readable({ captureRejections: true, - read() { - } + read() {}, }); r.push('hello'); r.push('world'); @@ -462,7 +448,7 @@ export const catchRejections = { highWaterMark: 1, write(chunk, enc, cb) { queueMicrotask(cb); - } + }, }); const err = new Error('kaboom'); @@ -483,7 +469,7 @@ export const catchRejections = { await wErrored.promise; } - } + }, }; export const construct = { @@ -495,7 +481,7 @@ export const construct = { construct: (callback) => { callback(); callback(); - } + }, }).on('error', (err) => { errored.resolve(err); }); @@ -511,7 +497,7 @@ export const construct = { construct: (callback) => { callback(); callback(); - } + }, }).on('error', (err) => { errored.resolve(err); }); @@ -527,7 +513,7 @@ export const construct = { new Writable({ construct: (callback) => { callback(err); - } + }, }).on('error', (err) => { errored.resolve(err); }); @@ -543,7 +529,7 @@ export const construct = { new Readable({ construct: (callback) => { callback(err); - } + }, }).on('error', (err) => { errored.resolve(err); }); @@ -560,7 +546,7 @@ export const construct = { new Writable({ construct: (callback) => { queueMicrotask(() => callback(err)); - } + }, }).on('error', (err) => { errored.resolve(err); }); @@ -577,7 +563,7 @@ export const construct = { new Readable({ construct: (callback) => { queueMicrotask(() => callback(err)); - } + }, }).on('error', errored.resolve); const check = await errored.promise; @@ -592,14 +578,11 @@ export const construct = { construct: (cb) => { constructed.resolve(); queueMicrotask(cb); - } + }, }); s.on('close', closed.resolve); s.destroy(); - await Promise.all([ - constructed.promise, - closed.promise, - ]); + await Promise.all([constructed.promise, closed.promise]); } { @@ -610,7 +593,7 @@ export const construct = { construct: (cb) => { constructed.resolve(); queueMicrotask(cb); - } + }, }); s.on('close', closed.resolve); s.destroy(null, () => { @@ -631,17 +614,13 @@ export const construct = { construct: (cb) => { constructed.resolve(); queueMicrotask(cb); - } + }, }); s.on('close', closed.resolve); s.destroy(); - await Promise.all([ - constructed.promise, - closed.promise, - ]); + await Promise.all([constructed.promise, closed.promise]); } - { const constructed = deferredPromise(); const closed = deferredPromise(); @@ -651,7 +630,7 @@ export const construct = { construct: (cb) => { constructed.resolve(); queueMicrotask(cb); - } + }, }); s.on('close', closed.resolve); s.on('error', (err) => { @@ -676,7 +655,7 @@ export const construct = { construct: (cb) => { constructed.resolve(); queueMicrotask(cb); - } + }, }); s.on('error', errored.resolve); s.on('close', closed.resolve); @@ -689,15 +668,27 @@ export const construct = { ]); } } - await testDestroy((opts) => new Readable({ - read: () => { throw new Error("must not call"); }, - ...opts - })); - await testDestroy((opts) => new Writable({ - write: () => { throw new Error("must not call"); }, - final: () => { throw new Error("must not call"); }, - ...opts - })); + await testDestroy( + (opts) => + new Readable({ + read: () => { + throw new Error('must not call'); + }, + ...opts, + }) + ); + await testDestroy( + (opts) => + new Writable({ + write: () => { + throw new Error('must not call'); + }, + final: () => { + throw new Error('must not call'); + }, + ...opts, + }) + ); { const constructed = deferredPromise(); @@ -713,16 +704,14 @@ export const construct = { read: () => { r.push(null); read.resolve(); - } + }, }); r.on('close', closed.resolve); - r.on('data', () => { throw new Error('should not call'); }); + r.on('data', () => { + throw new Error('should not call'); + }); - await Promise.all([ - constructed.promise, - read.promise, - closed.promise, - ]); + await Promise.all([constructed.promise, read.promise, closed.promise]); } { @@ -744,7 +733,7 @@ export const construct = { final: (cb) => { final.resolve(); queueMicrotask(cb); - } + }, }); w.on('close', closed.resolve); w.end('data'); @@ -767,20 +756,18 @@ export const construct = { constructed.resolve(); queueMicrotask(cb); }, - write: () => { throw new Error('should not call'); }, + write: () => { + throw new Error('should not call'); + }, final: (cb) => { final.resolve(); queueMicrotask(cb); - } + }, }); w.on('close', closed.resolve); w.end(); - await Promise.all([ - constructed.promise, - final.promise, - closed.promise, - ]); + await Promise.all([constructed.promise, final.promise, closed.promise]); } { @@ -788,7 +775,7 @@ export const construct = { new Duplex({ construct() { constructed = true; - } + }, }); ok(constructed); } @@ -811,16 +798,13 @@ export const construct = { }, read() { this.push(null); - } + }, }); d.resume(); d.end('foo'); d.on('close', closed.resolve); - await Promise.all([ - constructed.promise, - closed.promise, - ]); + await Promise.all([constructed.promise, closed.promise]); } { @@ -831,10 +815,10 @@ export const construct = { }, read() { throw new Error('should not call'); - } + }, }); } - } + }, }; export const decoderObjectMode = { @@ -842,7 +826,7 @@ export const decoderObjectMode = { const readable = new Readable({ read: () => {}, encoding: 'utf16le', - objectMode: true + objectMode: true, }); readable.push(Buffer.from('abc', 'utf16le')); @@ -853,7 +837,7 @@ export const decoderObjectMode = { strictEqual(readable.read(), 'abc'); strictEqual(readable.read(), 'def'); strictEqual(readable.read(), null); - } + }, }; export const destroyEventOrder = { @@ -861,7 +845,7 @@ export const destroyEventOrder = { const destroyed = deferredPromise(); const events = []; const rs = new Readable({ - read() {} + read() {}, }); let closed = false; @@ -877,7 +861,7 @@ export const destroyEventOrder = { }); await destroyed; - } + }, }; export const destroyTests = { @@ -935,7 +919,7 @@ export const destroyTests = { strictEqual(check, err); await closed.promise; } - } + }, }; export const duplexDestroy = { @@ -944,14 +928,20 @@ export const duplexDestroy = { const closed = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); duplex.resume(); - duplex.on('end', () => { throw new Error('should not call') }); - duplex.on('finish', () => { throw new Error('should not call') }); + duplex.on('end', () => { + throw new Error('should not call'); + }); + duplex.on('finish', () => { + throw new Error('should not call'); + }); duplex.on('close', closed.resolve); duplex.destroy(); @@ -963,8 +953,10 @@ export const duplexDestroy = { const errored = deferredPromise(); const closed = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); duplex.resume(); @@ -986,13 +978,15 @@ export const duplexDestroy = { const errored = deferredPromise(); const destroyCalled = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); const expected = new Error('kaboom'); - duplex._destroy = function(err, cb) { + duplex._destroy = function (err, cb) { strictEqual(err, expected); cb(err); destroyCalled.resolve(); @@ -1013,13 +1007,15 @@ export const duplexDestroy = { const destroyCalled = deferredPromise(); const expected = new Error('kaboom'); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, - destroy: function(err, cb) { + destroy: function (err, cb) { strictEqual(err, expected); cb(); destroyCalled.resolve(); - } + }, }); duplex.resume(); @@ -1032,20 +1028,19 @@ export const duplexDestroy = { duplex.destroy(expected); strictEqual(duplex.destroyed, true); - await Promise.all([ - closed.promise, - destroyCalled.promise, - ]); + await Promise.all([closed.promise, destroyCalled.promise]); } { const destroyCalled = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); - duplex._destroy = function(err, cb) { + duplex._destroy = function (err, cb) { strictEqual(err, null); cb(); destroyCalled.resolve(); @@ -1060,12 +1055,14 @@ export const duplexDestroy = { const destroyCalled = deferredPromise(); const closed = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); duplex.resume(); - duplex._destroy = function(err, cb) { + duplex._destroy = function (err, cb) { strictEqual(err, null); queueMicrotask(() => { this.push(null); @@ -1088,23 +1085,22 @@ export const duplexDestroy = { duplex.on('finish', fail); duplex.on('close', closed.resolve); strictEqual(duplex.destroyed, true); - await Promise.all([ - closed.promise, - destroyCalled.promise, - ]); + await Promise.all([closed.promise, destroyCalled.promise]); } { const destroyCalled = deferredPromise(); const errored = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, - read() {} + write(chunk, enc, cb) { + cb(); + }, + read() {}, }); const expected = new Error('kaboom'); - duplex._destroy = function(err, cb) { + duplex._destroy = function (err, cb) { strictEqual(err, null); cb(expected); destroyCalled.resolve(); @@ -1122,9 +1118,11 @@ export const duplexDestroy = { { const closed = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, - allowHalfOpen: true + allowHalfOpen: true, }); duplex.resume(); @@ -1140,7 +1138,9 @@ export const duplexDestroy = { { const closed = deferredPromise(); const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, destroy() { throw new Error('should not be called'); @@ -1171,7 +1171,9 @@ export const duplexDestroy = { const duplex = new Duplex({ writable: false, autoDestroy: true, - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, }); duplex.push(null); @@ -1185,7 +1187,9 @@ export const duplexDestroy = { const duplex = new Duplex({ readable: false, autoDestroy: true, - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, }); duplex.end(); @@ -1198,7 +1202,9 @@ export const duplexDestroy = { const duplex = new Duplex({ allowHalfOpen: false, autoDestroy: true, - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, }); duplex.push(null); @@ -1223,7 +1229,9 @@ export const duplexDestroy = { const controller = new AbortController(); const { signal } = controller; const duplex = new Duplex({ - write(chunk, enc, cb) { cb(); }, + write(chunk, enc, cb) { + cb(); + }, read() {}, signal, }); @@ -1235,19 +1243,16 @@ export const duplexDestroy = { }); duplex.on('close', closed.resolve); controller.abort(); - await Promise.all([ - errored.promise, - closed.promise, - ]); + await Promise.all([errored.promise, closed.promise]); } - } + }, }; export const duplexEnd = { async test(ctrl, env, ctx) { { const stream = new Duplex({ - read() {} + read() {}, }); strictEqual(stream.allowHalfOpen, true); stream.on('finish', () => { @@ -1262,7 +1267,7 @@ export const duplexEnd = { const finishedCalled = deferredPromise(); const stream = new Duplex({ read() {}, - allowHalfOpen: false + allowHalfOpen: false, }); strictEqual(stream.allowHalfOpen, false); stream.on('finish', finishedCalled.resolve); @@ -1275,7 +1280,7 @@ export const duplexEnd = { { const stream = new Duplex({ read() {}, - allowHalfOpen: false + allowHalfOpen: false, }); strictEqual(stream.allowHalfOpen, false); stream._writableState.ended = true; @@ -1286,7 +1291,7 @@ export const duplexEnd = { stream.resume(); stream.push(null); } - } + }, }; export const duplexProps = { @@ -1294,7 +1299,7 @@ export const duplexProps = { { const d = new Duplex({ objectMode: true, - highWaterMark: 100 + highWaterMark: 100, }); strictEqual(d.writableObjectMode, true); @@ -1308,7 +1313,7 @@ export const duplexProps = { readableObjectMode: false, readableHighWaterMark: 10, writableObjectMode: true, - writableHighWaterMark: 100 + writableHighWaterMark: 100, }); strictEqual(d.writableObjectMode, true); @@ -1316,8 +1321,7 @@ export const duplexProps = { strictEqual(d.readableObjectMode, false); strictEqual(d.readableHighWaterMark, 10); } - - } + }, }; export const duplexReadableEnd = { @@ -1327,21 +1331,20 @@ export const duplexReadableEnd = { const src = new Readable({ read() { - if (loops--) - this.push(Buffer.alloc(20000)); - } + if (loops--) this.push(Buffer.alloc(20000)); + }, }); const dst = new Transform({ transform(chunk, output, fn) { this.push(null); fn(); - } + }, }); src.pipe(dst); - dst.on('data', () => { }); + dst.on('data', () => {}); dst.on('end', () => { strictEqual(loops, 3); ok(src.isPaused()); @@ -1349,7 +1352,7 @@ export const duplexReadableEnd = { }); await ended.promise; - } + }, }; export const duplexReadableWritable = { @@ -1357,7 +1360,7 @@ export const duplexReadableWritable = { { const errored = deferredPromise(); const duplex = new Duplex({ - readable: false + readable: false, }); strictEqual(duplex.readable, false); duplex.push('asd'); @@ -1385,16 +1388,13 @@ export const duplexReadableWritable = { }); duplex.on('finish', closed.reject); duplex.on('close', closed.resolve); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const closed = deferredPromise(); const duplex = new Duplex({ - readable: false + readable: false, }); strictEqual(duplex.readable, false); duplex.on('data', closed.reject); @@ -1405,12 +1405,9 @@ export const duplexReadableWritable = { ok(false, chunk); } } - await Promise.all([ - run(), - closed.promise, - ]); + await Promise.all([run(), closed.promise]); } - } + }, }; export const duplexWritableFinished = { @@ -1442,13 +1439,10 @@ export const duplexWritableFinished = { ended.resolve(); }); - await Promise.all([ - finishedCalled.promise, - ended.promise, - ]); + await Promise.all([finishedCalled.promise, ended.promise]); } - } -} + }, +}; export const duplex = { async test(ctrl, env, ctx) { @@ -1497,7 +1491,7 @@ export const duplex = { const writable = new WritableStream({ write: (chunk) => { strictEqual(chunk, dataToWrite); - } + }, }); const pair = { readable, writable }; @@ -1526,14 +1520,17 @@ export const duplex = { const writable = new WritableStream({ write: (chunk) => { strictEqual(chunk, dataToWrite); - } + }, }); const pair = { readable, - writable + writable, }; - const duplex = Duplex.fromWeb(pair, { encoding: 'utf8', objectMode: true }); + const duplex = Duplex.fromWeb(pair, { + encoding: 'utf8', + objectMode: true, + }); duplex.write(dataToWrite); const p = deferredPromise(); @@ -1556,20 +1553,23 @@ export const duplex = { }, write: (chunk) => { strictEqual(chunk, dataToWrite); - } + }, }); const { writable, readable } = Duplex.toWeb(duplex); writable.getWriter().write(dataToWrite); const p = deferredPromise(); - readable.getReader().read().then((result) => { - deepStrictEqual(Buffer.from(result.value), dataToRead); - p.resolve(); - }); + readable + .getReader() + .read() + .then((result) => { + deepStrictEqual(Buffer.from(result.value), dataToRead); + p.resolve(); + }); await p.promise; } - } + }, }; export const end_of_streams = { @@ -1588,7 +1588,7 @@ export const end_of_streams = { // Below code should not throw any errors as the // streamObj is `Stream` finished(streamObj, () => {}); - } + }, }; export const end_paused = { @@ -1596,7 +1596,7 @@ export const end_paused = { const calledRead = deferredPromise(); const ended = deferredPromise(); const stream = new Readable(); - stream._read = function() { + stream._read = function () { this.push(null); calledRead.resolve(); }; @@ -1605,15 +1605,12 @@ export const end_paused = { stream.on('end', ended.resolve); stream.pause(); - setTimeout(function() { + setTimeout(function () { stream.resume(); }); - await Promise.all([ - calledRead.promise, - ended.promise, - ]); - } + await Promise.all([calledRead.promise, ended.promise]); + }, }; export const error_once = { @@ -1637,8 +1634,7 @@ export const error_once = { readable.push('h'); await errored.promise; } - - } + }, }; export const finishedTest = { @@ -1647,7 +1643,7 @@ export const finishedTest = { { const finishedOk = deferredPromise(); const rs = new Readable({ - read() {} + read() {}, }); finished(rs, (err) => { @@ -1667,7 +1663,7 @@ export const finishedTest = { const ws = new Writable({ write(data, enc, cb) { cb(); - } + }, }); finished(ws, (err) => { @@ -1685,7 +1681,7 @@ export const finishedTest = { const tr = new Transform({ transform(data, enc, cb) { cb(); - } + }, }); let finish = false; @@ -1716,10 +1712,10 @@ export const finishedTest = { const finishedCalled = deferredPromise(); const rs = new Readable({ read() { - this.push(enc.encode("a")); - this.push(enc.encode("b")); + this.push(enc.encode('a')); + this.push(enc.encode('b')); this.push(null); - } + }, }); rs.resume(); @@ -1734,10 +1730,10 @@ export const finishedTest = { const enc = new TextEncoder(); const rs = new Readable({ read() { - this.push(enc.encode("a")); - this.push(enc.encode("b")); + this.push(enc.encode('a')); + this.push(enc.encode('b')); this.push(null); - } + }, }); let ended = false; @@ -1795,10 +1791,12 @@ export const finishedTest = { const ac = new AbortController(); const { signal } = ac; - const rs = Readable.from((function* () { - yield 5; - queueMicrotask(() => ac.abort()); - })()); + const rs = Readable.from( + (function* () { + yield 5; + queueMicrotask(() => ac.abort()); + })() + ); rs.resume(); const finishedOk = deferredPromise(); finished(rs, { signal }, finishedOk.resolve); @@ -1865,30 +1863,21 @@ export const finishedTest = { // Test faulty input values and options. { const rs = new Readable({ - read() {} + read() {}, }); - throws( - () => finished(rs, 'foo'), - { - code: 'ERR_INVALID_ARG_TYPE', - message: /callback/ - } - ); - throws( - () => finished(rs, 'foo', () => {}), - { - code: 'ERR_INVALID_ARG_TYPE', - message: /options/ - } - ); - throws( - () => finished(rs, {}, 'foo'), - { - code: 'ERR_INVALID_ARG_TYPE', - message: /callback/ - } - ); + throws(() => finished(rs, 'foo'), { + code: 'ERR_INVALID_ARG_TYPE', + message: /callback/, + }); + throws(() => finished(rs, 'foo', () => {}), { + code: 'ERR_INVALID_ARG_TYPE', + message: /options/, + }); + throws(() => finished(rs, {}, 'foo'), { + code: 'ERR_INVALID_ARG_TYPE', + message: /callback/, + }); const finishedOk = deferredPromise(); finished(rs, null, finishedOk.resolve); @@ -1905,7 +1894,7 @@ export const finishedTest = { const ws = new Writable({ write(data, env, cb) { cb(); - } + }, }); const removeListener = finished(ws, () => { throw new Error('should not have been called'); @@ -1927,7 +1916,7 @@ export const finishedTest = { } { - const EventEmitter = (await import("node:events")).EventEmitter; + const EventEmitter = (await import('node:events')).EventEmitter; const streamLike = new EventEmitter(); streamLike.readableEnded = true; streamLike.readable = true; @@ -1959,7 +1948,7 @@ export const finishedTest = { const check = await errored.promise; strictEqual(check.code, 'ERR_STREAM_PREMATURE_CLOSE'); } - } + }, }; export const highWaterMark = { @@ -1971,28 +1960,28 @@ export const highWaterMark = { // This number exceeds the range of 32 bit integer arithmetic but should still // be handled correctly. - const ovfl = Number.MAX_SAFE_INTEGER + const ovfl = Number.MAX_SAFE_INTEGER; const readable = Readable({ - highWaterMark: ovfl - }) - strictEqual(readable._readableState.highWaterMark, ovfl) + highWaterMark: ovfl, + }); + strictEqual(readable._readableState.highWaterMark, ovfl); const writable = Writable({ - highWaterMark: ovfl - }) - strictEqual(writable._writableState.highWaterMark, ovfl) + highWaterMark: ovfl, + }); + strictEqual(writable._writableState.highWaterMark, ovfl); for (const invalidHwm of [true, false, '5', {}, -5, NaN]) { for (const type of [Readable, Writable]) { throws( () => { type({ - highWaterMark: invalidHwm - }) + highWaterMark: invalidHwm, + }); }, { name: 'TypeError', code: 'ERR_INVALID_ARG_VALUE', } - ) + ); } } } @@ -2002,11 +1991,11 @@ export const highWaterMark = { // the state.length are both zero const readable = Readable({ - highWaterMark: 0 - }) + highWaterMark: 0, + }); for (let i = 0; i < 3; i++) { - const needMoreData = readable.push() - strictEqual(needMoreData, true) + const needMoreData = readable.push(); + strictEqual(needMoreData, true); } } { @@ -2015,40 +2004,39 @@ export const highWaterMark = { // and n are all zero const readable = Readable({ - highWaterMark: 0 - }) + highWaterMark: 0, + }); const readCalled = deferredPromise(); readable._read = readCalled.resolve; - readable.read(0) + readable.read(0); await readCalled.promise; } { const readCalled = deferredPromise(); // Parse size as decimal integer - await Promise.all(['1', '1.0', 1].map(async (size) => { - const readable = new Readable({ - read: readCalled.resolve, - highWaterMark: 0 + await Promise.all( + ['1', '1.0', 1].map(async (size) => { + const readable = new Readable({ + read: readCalled.resolve, + highWaterMark: 0, + }); + readable.read(size); + strictEqual(readable._readableState.highWaterMark, Number(size)); + await readCalled.promise; }) - readable.read(size) - strictEqual(readable._readableState.highWaterMark, Number(size)) - await readCalled.promise; - })); + ); } { // Test highwatermark limit - const hwm = 0x40000000 + 1 + const hwm = 0x40000000 + 1; const readable = Readable({ - read() {} - }) - throws( - () => readable.read(hwm), - { - code: 'ERR_OUT_OF_RANGE', - } - ) + read() {}, + }); + throws(() => readable.read(hwm), { + code: 'ERR_OUT_OF_RANGE', + }); } - } + }, }; export const pauseThenRead = { @@ -2059,15 +2047,15 @@ export const pauseThenRead = { let expectEndingData = expectTotalData; const closed = deferredPromise(); const r = new Readable({ - highWaterMark: 1000 - }) + highWaterMark: 1000, + }); r.on('close', closed.resolve); let chunks = totalChunks; r._read = function (n) { if (!(chunks % 2)) queueMicrotask(push); else if (!(chunks % 3)) queueMicrotask(push); else push(); - } + }; let totalPushed = 0; function push() { const chunk = chunks-- > 0 ? Buffer.alloc(chunkSize, 'x') : null; @@ -2085,7 +2073,7 @@ export const pauseThenRead = { } function readn(n, then) { expectEndingData -= n; - ;(function read() { + (function read() { const c = r.read(n); if (!c) r.once('readable', read); else { @@ -2142,7 +2130,7 @@ export const pauseThenRead = { } else { queueMicrotask(cb); } - } + }; r.pipe(w); } @@ -2177,7 +2165,7 @@ export const pauseThenRead = { }); r.pipe(w); } - } + }, }; export const corkUncork = { @@ -2218,7 +2206,7 @@ export const corkUncork = { // We were not told to stop writing. ok(writeState); writeChunks(remainingChunks, callback); - }) + }); } else { callback(); } @@ -2262,7 +2250,7 @@ export const corkUncork = { }); await closed.promise; - } + }, }; export const corkEnd = { @@ -2350,7 +2338,7 @@ export const corkEnd = { }); await closed.promise; - } + }, }; export const writable2Writable = { @@ -2363,11 +2351,14 @@ export const writable2Writable = { } _write(chunk, encoding, cb) { // Simulate a small unpredictable latency - queueMicrotask(() => { - this.buffer.push(chunk.toString()); - this.written += chunk.length; - cb(); - }, Math.floor(Math.random() * 10)); + queueMicrotask( + () => { + this.buffer.push(chunk.toString()); + this.written += chunk.length; + cb(); + }, + Math.floor(Math.random() * 10) + ); } } const chunks = new Array(50); @@ -2377,17 +2368,14 @@ export const writable2Writable = { { // Verify fast writing const tw = new TestWriter({ - highWaterMark: 100 + highWaterMark: 100, }); const finishCalled = deferredPromise(); - tw.on( - 'finish', - function () { - // Got chunks in the right order - deepStrictEqual(tw.buffer, chunks); - finishCalled.resolve(); - } - ); + tw.on('finish', function () { + // Got chunks in the right order + deepStrictEqual(tw.buffer, chunks); + finishCalled.resolve(); + }); chunks.forEach(function (chunk) { // Ignore backpressure. Just buffer it all up. tw.write(chunk); @@ -2398,17 +2386,14 @@ export const writable2Writable = { { // Verify slow writing const tw = new TestWriter({ - highWaterMark: 100 + highWaterMark: 100, }); const finishedCalled = deferredPromise(); - tw.on( - 'finish', - function () { - // Got chunks in the right order - deepStrictEqual(tw.buffer, chunks); - finishedCalled.resolve(); - } - ); + tw.on('finish', function () { + // Got chunks in the right order + deepStrictEqual(tw.buffer, chunks); + finishedCalled.resolve(); + }); let i = 0; (function W() { tw.write(chunks[i++]); @@ -2420,28 +2405,25 @@ export const writable2Writable = { { // Verify write backpressure const tw = new TestWriter({ - highWaterMark: 50 + highWaterMark: 50, }); let drains = 0; const finishCalled = deferredPromise(); - tw.on( - 'finish', - function () { - // Got chunks in the right order - deepStrictEqual(tw.buffer, chunks); - strictEqual(drains, 17); - finishCalled.resolve(); - } - ); + tw.on('finish', function () { + // Got chunks in the right order + deepStrictEqual(tw.buffer, chunks); + strictEqual(drains, 17); + finishCalled.resolve(); + }); tw.on('drain', function () { - drains++ + drains++; }); let i = 0; (function W() { let ret; do { ret = tw.write(chunks[i++]); - } while (ret !== false && i < chunks.length) + } while (ret !== false && i < chunks.length); if (i < chunks.length) { ok(tw.writableLength >= 50); tw.once('drain', W); @@ -2458,8 +2440,8 @@ export const writable2Writable = { return [ i, function () { - callbacks._called[i] = chunk - } + callbacks._called[i] = chunk; + }, ]; }) .reduce(function (set, x) { @@ -2469,22 +2451,17 @@ export const writable2Writable = { callbacks._called = []; const finishCalled = deferredPromise(); const tw = new TestWriter({ - highWaterMark: 100 + highWaterMark: 100, + }); + tw.on('finish', function () { + queueMicrotask(function () { + // Got chunks in the right order + deepStrictEqual(tw.buffer, chunks); + // Called all callbacks + deepStrictEqual(callbacks._called, chunks); + finishCalled.resolve(); + }); }); - tw.on( - 'finish', - function () { - queueMicrotask( - function () { - // Got chunks in the right order - deepStrictEqual(tw.buffer, chunks); - // Called all callbacks - deepStrictEqual(callbacks._called, chunks); - finishCalled.resolve(); - } - ); - } - ); chunks.forEach(function (chunk, i) { tw.write(chunk, callbacks[`callback-${i}`]); }); @@ -2508,7 +2485,7 @@ export const writable2Writable = { } { // Verify end() callback with chunk and encoding - const tw = new TestWriter() + const tw = new TestWriter(); const endCalled = deferredPromise(); tw.end('hello world', 'ascii', endCalled.resolve); await endCalled.promise; @@ -2551,12 +2528,12 @@ export const writable2Writable = { { // Verify writables cannot be piped const w = new Writable({ - autoDestroy: false - }) + autoDestroy: false, + }); const gotError = deferredPromise(); w._write = gotError.reject; - w.on('error', gotError.resolve) - w.pipe(new Writable({write() {}})); + w.on('error', gotError.resolve); + w.pipe(new Writable({ write() {} })); await gotError.promise; } { @@ -2564,12 +2541,14 @@ export const writable2Writable = { const d = new Duplex(); const readCalled = deferredPromise; d._read = readCalled.resolve; - d._write = () => { throw new Error('should not be called'); }; + d._write = () => { + throw new Error('should not be called'); + }; let gotError = false; d.on('error', function () { gotError = true; }); - d.pipe(new Writable({ write() {}})); + d.pipe(new Writable({ write() {} })); strictEqual(gotError, false); } { @@ -2587,10 +2566,7 @@ export const writable2Writable = { }); w.end('this is the end'); w.end('and so is this'); - await Promise.all([ - writeCalled.promise, - gotError.promise, - ]); + await Promise.all([writeCalled.promise, gotError.promise]); } { // Verify stream doesn't end while writing @@ -2605,20 +2581,14 @@ export const writable2Writable = { this.writing = false; cb(); }, 1); - } - w.on( - 'finish', - function () { - strictEqual(this.writing, false); - finishCalled.resolve(); - } - ); + }; + w.on('finish', function () { + strictEqual(this.writing, false); + finishCalled.resolve(); + }); w.write(Buffer.alloc(0)); w.end(); - await Promise.all([ - wrote.promise, - finishCalled.promise, - ]); + await Promise.all([wrote.promise, finishCalled.promise]); } { // Verify finish does not come before write() callback @@ -2631,13 +2601,10 @@ export const writable2Writable = { cb(); }, 10); }; - w.on( - 'finish', - function () { - strictEqual(writeCb, true); - finishCalled.resolve(); - } - ) + w.on('finish', function () { + strictEqual(writeCb, true); + finishCalled.resolve(); + }); w.write(Buffer.alloc(0)); w.end(); await finishCalled.promise; @@ -2650,13 +2617,10 @@ export const writable2Writable = { w._write = function (chunk, e, cb) { cb(); }; - w.on( - 'finish', - function () { - strictEqual(writeCb, true); - finishCalled.resolve(); - } - ); + w.on('finish', function () { + strictEqual(writeCb, true); + finishCalled.resolve(); + }); w.write(Buffer.alloc(0), function () { writeCb = true; }); @@ -2692,19 +2656,13 @@ export const writable2Writable = { w._write = function (chunk, e, cb) { queueMicrotask(cb); }; - w.on( - 'finish', - function () { - strictEqual(shutdown, true); - finishCalled.resolve(); - } - ); + w.on('finish', function () { + strictEqual(shutdown, true); + finishCalled.resolve(); + }); w.write(Buffer.allocUnsafe(1)); w.end(Buffer.allocUnsafe(0)); - await Promise.all([ - finalCalled.promise, - finishCalled.promise, - ]); + await Promise.all([finalCalled.promise, finishCalled.promise]); } { // Verify that error is only emitted once when failing in _finish. @@ -2715,21 +2673,17 @@ export const writable2Writable = { cb(new Error('test')); finalCalled.resolve(); }; - w.on( - 'error', - (err) => { - gotError.resolve(); - strictEqual(w._writableState.errorEmitted, true); - strictEqual(err.message, 'test'); - w.on('error', () => { throw new Error('should not be called again'); }); - w.destroy(new Error()); - } - ); + w.on('error', (err) => { + gotError.resolve(); + strictEqual(w._writableState.errorEmitted, true); + strictEqual(err.message, 'test'); + w.on('error', () => { + throw new Error('should not be called again'); + }); + w.destroy(new Error()); + }); w.end(); - await Promise.all([ - finalCalled.promise, - gotError.promise, - ]); + await Promise.all([finalCalled.promise, gotError.promise]); } { // Verify that error is only emitted once when failing in write. @@ -2739,7 +2693,7 @@ export const writable2Writable = { w.write(null); }, { - code: 'ERR_STREAM_NULL_VALUES' + code: 'ERR_STREAM_NULL_VALUES', } ); } @@ -2747,14 +2701,11 @@ export const writable2Writable = { // Verify that error is only emitted once when failing in write after end. const w = new Writable(); const gotError = deferredPromise(); - w.on( - 'error', - (err) => { - strictEqual(w._writableState.errorEmitted, true); - strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); - gotError.resolve(); - } - ); + w.on('error', (err) => { + strictEqual(w._writableState.errorEmitted, true); + strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); + gotError.resolve(); + }); w.end(); w.write('hello'); w.destroy(new Error()); @@ -2777,17 +2728,14 @@ export const writable2Writable = { w.on('finish', gotError.reject); w.write(Buffer.allocUnsafe(1)); w.end(Buffer.allocUnsafe(0)); - await Promise.all([ - finalCalled.promise, - gotError.promise, - ]); + await Promise.all([finalCalled.promise, gotError.promise]); } - } + }, }; export const unpipeLeak = { async test(ctrl, env, ctx) { - const chunk = Buffer.from('hallo') + const chunk = Buffer.from('hallo'); class TestWriter extends Writable { _write(buffer, encoding, callback) { callback(null); @@ -2800,7 +2748,7 @@ export const unpipeLeak = { class TestReader extends Readable { constructor() { super({ - highWaterMark: 0x10000 + highWaterMark: 0x10000, }); } _read(size) { @@ -2813,14 +2761,14 @@ export const unpipeLeak = { src.unpipe(dest); } - strictEqual(src.listeners('end').length, 0) - strictEqual(src.listeners('readable').length, 0) - strictEqual(dest.listeners('unpipe').length, 0) - strictEqual(dest.listeners('drain').length, 0) - strictEqual(dest.listeners('error').length, 0) - strictEqual(dest.listeners('close').length, 0) - strictEqual(dest.listeners('finish').length, 0) - } + strictEqual(src.listeners('end').length, 0); + strictEqual(src.listeners('readable').length, 0); + strictEqual(dest.listeners('unpipe').length, 0); + strictEqual(dest.listeners('drain').length, 0); + strictEqual(dest.listeners('error').length, 0); + strictEqual(dest.listeners('close').length, 0); + strictEqual(dest.listeners('finish').length, 0); + }, }; export const unpipeDrain = { @@ -2855,11 +2803,8 @@ export const unpipeDrain = { }); }); }); - await Promise.all([ - src1.done.promise, - src2.done.promise, - ]); - } + await Promise.all([src1.done.promise, src2.done.promise]); + }, }; export const transformTest = { @@ -2867,7 +2812,7 @@ export const transformTest = { { // Verify writable side consumption const tx = new Transform({ - highWaterMark: 10 + highWaterMark: 10, }); let transformed = 0; tx._transform = function (chunk, encoding, cb) { @@ -2904,7 +2849,7 @@ export const transformTest = { { // Verify object passthrough behavior const pt = new PassThrough({ - objectMode: true + objectMode: true, }); pt.write(1); pt.write(true); @@ -2913,7 +2858,7 @@ export const transformTest = { pt.write('foo'); pt.write(''); pt.write({ - a: 'b' + a: 'b', }); pt.end(); strictEqual(pt.read(), 1); @@ -2923,7 +2868,7 @@ export const transformTest = { strictEqual(pt.read(), 'foo'); strictEqual(pt.read(), ''); deepStrictEqual(pt.read(), { - a: 'b' + a: 'b', }); } { @@ -2943,7 +2888,7 @@ export const transformTest = { const ret = Buffer.alloc(c.length, 'x'); pt.push(ret); cb(); - } + }; pt.write(Buffer.from('foog')); pt.write(Buffer.from('bark')); pt.write(Buffer.from('bazy')); @@ -2957,7 +2902,7 @@ export const transformTest = { { // Verify simple object transform const pt = new Transform({ - objectMode: true + objectMode: true, }); pt._transform = function (c, e, cb) { pt.push(JSON.stringify(c)); @@ -2970,7 +2915,7 @@ export const transformTest = { pt.write('foo'); pt.write(''); pt.write({ - a: 'b' + a: 'b', }); pt.end(); strictEqual(pt.read(), '1'); @@ -2989,23 +2934,20 @@ export const transformTest = { pt.push(chunk); cb(); }, 10); - } + }; pt.write(Buffer.from('foog')); pt.write(Buffer.from('bark')); pt.write(Buffer.from('bazy')); pt.write(Buffer.from('kuel')); pt.end(); const finishCalled = deferredPromise(); - pt.on( - 'finish', - function () { - strictEqual(pt.read(5).toString(), 'foogb'); - strictEqual(pt.read(5).toString(), 'arkba'); - strictEqual(pt.read(5).toString(), 'zykue'); - strictEqual(pt.read(5).toString(), 'l'); - finishCalled.resolve(); - } - ) + pt.on('finish', function () { + strictEqual(pt.read(5).toString(), 'foogb'); + strictEqual(pt.read(5).toString(), 'arkba'); + strictEqual(pt.read(5).toString(), 'zykue'); + strictEqual(pt.read(5).toString(), 'l'); + finishCalled.resolve(); + }); await finishCalled.promise; } { @@ -3021,26 +2963,23 @@ export const transformTest = { cb(); }, 10); }, 10); - } + }; pt.write(Buffer.from('foog')); pt.write(Buffer.from('bark')); pt.write(Buffer.from('bazy')); pt.write(Buffer.from('kuel')); pt.end(); const finishCalled = deferredPromise(); - pt.on( - 'finish', - function () { - strictEqual(pt.read(5).toString(), 'foogf'); - strictEqual(pt.read(5).toString(), 'oogba'); - strictEqual(pt.read(5).toString(), 'rkbar'); - strictEqual(pt.read(5).toString(), 'kbazy'); - strictEqual(pt.read(5).toString(), 'bazyk'); - strictEqual(pt.read(5).toString(), 'uelku'); - strictEqual(pt.read(5).toString(), 'el'); - finishCalled.resolve(); - } - ); + pt.on('finish', function () { + strictEqual(pt.read(5).toString(), 'foogf'); + strictEqual(pt.read(5).toString(), 'oogba'); + strictEqual(pt.read(5).toString(), 'rkbar'); + strictEqual(pt.read(5).toString(), 'kbazy'); + strictEqual(pt.read(5).toString(), 'bazyk'); + strictEqual(pt.read(5).toString(), 'uelku'); + strictEqual(pt.read(5).toString(), 'el'); + finishCalled.resolve(); + }); await finishCalled.promise; } { @@ -3061,13 +3000,13 @@ export const transformTest = { } cb(); }, 10); - } + }; pt._flush = function (cb) { // Just output whatever we have. pt.push(Buffer.from(this.state)); this.state = ''; cb(); - } + }; pt.write(Buffer.from('aaaa')); pt.write(Buffer.from('bbbb')); pt.write(Buffer.from('cccc')); @@ -3086,15 +3025,12 @@ export const transformTest = { const finishCalled = deferredPromise(); // 'abcdeabcdeabcd' - pt.on( - 'finish', - function () { - strictEqual(pt.read(5).toString(), 'abcde'); - strictEqual(pt.read(5).toString(), 'abcde'); - strictEqual(pt.read(5).toString(), 'abcd'); - finishCalled.resolve(); - } - ) + pt.on('finish', function () { + strictEqual(pt.read(5).toString(), 'abcde'); + strictEqual(pt.read(5).toString(), 'abcde'); + strictEqual(pt.read(5).toString(), 'abcd'); + finishCalled.resolve(); + }); await finishCalled.promise; } @@ -3105,7 +3041,7 @@ export const transformTest = { let count = 0; let saved = null; const pt = new Transform({ - highWaterMark: 3 + highWaterMark: 3, }); pt._transform = function (c, e, cb) { if (count++ === 1) saved = c; @@ -3123,12 +3059,9 @@ export const transformTest = { pt.once('readable', function () { queueMicrotask(function () { pt.write(Buffer.from('d')); - pt.write( - Buffer.from('ef'), - function () { - pt.end(); - } - ); + pt.write(Buffer.from('ef'), function () { + pt.end(); + }); strictEqual(pt.read().toString(), 'abcdef'); strictEqual(pt.read(), null); }); @@ -3176,33 +3109,24 @@ export const transformTest = { const readable1 = deferredPromise(); const readable2 = deferredPromise(); const readable3 = deferredPromise(); - pt.once( - 'readable', - function () { - strictEqual(pt.read(5).toString(), 'arkba'); + pt.once('readable', function () { + strictEqual(pt.read(5).toString(), 'arkba'); + strictEqual(pt.read(5), null); + pt.once('readable', function () { + strictEqual(pt.read(5).toString(), 'zykue'); strictEqual(pt.read(5), null); - pt.once( - 'readable', - function () { - strictEqual(pt.read(5).toString(), 'zykue'); - strictEqual(pt.read(5), null); - pt.once( - 'readable', - function () { - strictEqual(pt.read(5).toString(), 'l'); - strictEqual(pt.read(5), null); - strictEqual(emits, 3); - readable3.resolve(); - } - ) - pt.end(); - readable2.resolve(); - } - ) - pt.write(Buffer.from('kuel')); - readable1.resolve(); - } - ) + pt.once('readable', function () { + strictEqual(pt.read(5).toString(), 'l'); + strictEqual(pt.read(5), null); + strictEqual(emits, 3); + readable3.resolve(); + }); + pt.end(); + readable2.resolve(); + }); + pt.write(Buffer.from('kuel')); + readable1.resolve(); + }); pt.write(Buffer.from('bazy')); await Promise.all([ readable1.promise, @@ -3218,13 +3142,10 @@ export const transformTest = { datas.push(chunk.toString()); }); const endCalled = deferredPromise(); - pt.on( - 'end', - function () { - deepStrictEqual(datas, ['foog', 'bark', 'bazy', 'kuel']); - endCalled.resolve(); - } - ) + pt.on('end', function () { + deepStrictEqual(datas, ['foog', 'bark', 'bazy', 'kuel']); + endCalled.resolve(); + }); pt.write(Buffer.from('foog')); setTimeout(function () { pt.write(Buffer.from('bark')); @@ -3244,7 +3165,7 @@ export const transformTest = { { // Verify object transform (JSON parse) const jp = new Transform({ - objectMode: true + objectMode: true, }); jp._transform = function (data, encoding, cb) { try { @@ -3259,7 +3180,7 @@ export const transformTest = { // those are "magic" in the stream API, because they signal EOF. const objects = [ { - foo: 'bar' + foo: 'bar', }, 100, 'string', @@ -3267,21 +3188,21 @@ export const transformTest = { nested: { things: [ { - foo: 'bar' + foo: 'bar', }, 100, - 'string' - ] - } - } - ] + 'string', + ], + }, + }, + ]; const ended = deferredPromise(); jp.on('end', ended.resolve); objects.forEach(function (obj) { jp.write(JSON.stringify(obj)); const res = jp.read(); deepStrictEqual(res, obj); - }) + }); jp.end(); // Read one more time to get the 'end' event jp.read(); @@ -3290,7 +3211,7 @@ export const transformTest = { { // Verify object transform (JSON stringify) const js = new Transform({ - objectMode: true + objectMode: true, }); js._transform = function (data, encoding, cb) { try { @@ -3305,7 +3226,7 @@ export const transformTest = { // those are "magic" in the stream API, because they signal EOF. const objects = [ { - foo: 'bar' + foo: 'bar', }, 100, 'string', @@ -3313,13 +3234,13 @@ export const transformTest = { nested: { things: [ { - foo: 'bar' + foo: 'bar', }, 100, - 'string' - ] - } - } + 'string', + ], + }, + }, ]; const ended = deferredPromise(); js.on('end', ended.resolve); @@ -3327,13 +3248,13 @@ export const transformTest = { js.write(obj); const res = js.read(); strictEqual(res, JSON.stringify(obj)); - }) + }); js.end(); // Read one more time to get the 'end' event js.read(); await ended.promise; } - } + }, }; export const set_encoding = { @@ -3360,7 +3281,7 @@ export const set_encoding = { this.pos += n; const ret = Buffer.alloc(n, 'a'); return this.push(ret); - }, 1) + }, 1); } } { @@ -3378,20 +3299,17 @@ export const set_encoding = { 'aaaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaa', - 'aaaaaaaaaa' + 'aaaaaaaaaa', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect) - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { @@ -3419,20 +3337,17 @@ export const set_encoding = { '6161616161', '6161616161', '6161616161', - '6161616161' + '6161616161', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ) + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { @@ -3456,20 +3371,17 @@ export const set_encoding = { '6161616161616', '1616161616161', '6161616161616', - '16161' + '16161', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(13))) out.push(chunk); - }) + }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { @@ -3491,26 +3403,23 @@ export const set_encoding = { 'YWFhYWFhYW', 'FhYWFhYWFh', 'YWFhYWFhYW', - 'FhYQ==' + 'FhYQ==', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); - }) + }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { // Verify utf8 encoding const tr = new TestReader(100, { - encoding: 'utf8' + encoding: 'utf8', }); const out = []; const expect = [ @@ -3523,26 +3432,23 @@ export const set_encoding = { 'aaaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaa', - 'aaaaaaaaaa' + 'aaaaaaaaaa', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); - }) + }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { // Verify hex encoding const tr = new TestReader(100, { - encoding: 'hex' + encoding: 'hex', }); const out = []; const expect = [ @@ -3565,26 +3471,23 @@ export const set_encoding = { '6161616161', '6161616161', '6161616161', - '6161616161' + '6161616161', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { // Verify hex encoding with read(13) const tr = new TestReader(100, { - encoding: 'hex' + encoding: 'hex', }); const out = []; const expect = [ @@ -3603,26 +3506,23 @@ export const set_encoding = { '6161616161616', '1616161616161', '6161616161616', - '16161' + '16161', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(13))) out.push(chunk); - }) + }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { // Verify base64 encoding const tr = new TestReader(100, { - encoding: 'base64' + encoding: 'base64', }); const out = []; const expect = [ @@ -3639,20 +3539,17 @@ export const set_encoding = { 'YWFhYWFhYW', 'FhYWFhYWFh', 'YWFhYWFhYW', - 'FhYQ==' + 'FhYQ==', ]; tr.on('readable', function flow() { let chunk; while (null !== (chunk = tr.read(10))) out.push(chunk); }); const ended = deferredPromise(); - tr.on( - 'end', - function () { - deepStrictEqual(out, expect); - ended.resolve(); - } - ); + tr.on('end', function () { + deepStrictEqual(out, expect); + ended.resolve(); + }); await ended.promise; } { @@ -3660,7 +3557,7 @@ export const set_encoding = { const tr = new TestReader(100); deepStrictEqual(tr.setEncoding('utf8'), tr); } - } + }, }; export const readable_wrap = { @@ -3670,7 +3567,7 @@ export const readable_wrap = { const old = new EventEmitter(); const r = new Readable({ highWaterMark, - objectMode + objectMode, }); strictEqual(r, r.wrap(old)); @@ -3685,13 +3582,13 @@ export const readable_wrap = { }; // Make sure pause is only emitted once. - let pausing = false + let pausing = false; r.on('pause', () => { strictEqual(pausing, false); pausing = true; queueMicrotask(() => { pausing = false; - }) + }); }); let flowing; let chunks = 10; @@ -3711,43 +3608,37 @@ export const readable_wrap = { } const w = new Writable({ highWaterMark: highWaterMark * 2, - objectMode + objectMode, }); const written = []; w._write = function (chunk, encoding, cb) { - written.push(chunk) - setTimeout(cb, 1) + written.push(chunk); + setTimeout(cb, 1); }; const finishCalled = deferredPromise(); - w.on( - 'finish', - function () { - performAsserts() - finishCalled.resolve(); - } - ); + w.on('finish', function () { + performAsserts(); + finishCalled.resolve(); + }); r.pipe(w); flow(); function performAsserts() { ok(oldEnded); deepStrictEqual(written, expected); } - await Promise.all([ - rEnded.promise, - finishCalled.promise, - ]); + await Promise.all([rEnded.promise, finishCalled.promise]); } await runTest(100, false, function () { return Buffer.allocUnsafe(100); - }) + }); await runTest(10, false, function () { return Buffer.from('xxxxxxxxxx'); - }) + }); await runTest(1, true, function () { return { - foo: 'bar' + foo: 'bar', }; - }) + }); const objectChunks = [ 5, 'a', @@ -3756,16 +3647,16 @@ export const readable_wrap = { '', 'xyz', { - x: 4 + x: 4, }, 7, [], - 555 + 555, ]; await runTest(1, true, function () { return objectChunks.shift(); }); - } + }, }; export const readable_wrap_error = { @@ -3779,18 +3670,15 @@ export const readable_wrap_error = { const oldStream = new LegacyStream(); const errored = deferredPromise(); const r = new Readable({ - autoDestroy: true + autoDestroy: true, }) .wrap(oldStream) - .on( - 'error', - () => { - strictEqual(r._readableState.errorEmitted, true) - strictEqual(r._readableState.errored, err) - strictEqual(r.destroyed, true) - errored.resolve(); - } - ) + .on('error', () => { + strictEqual(r._readableState.errorEmitted, true); + strictEqual(r._readableState.errored, err); + strictEqual(r.destroyed, true); + errored.resolve(); + }); oldStream.emit('error', err); await errored.promise; } @@ -3799,22 +3687,19 @@ export const readable_wrap_error = { const oldStream = new LegacyStream(); const errored = deferredPromise(); const r = new Readable({ - autoDestroy: false + autoDestroy: false, }) .wrap(oldStream) - .on( - 'error', - () => { - strictEqual(r._readableState.errorEmitted, true) - strictEqual(r._readableState.errored, err) - strictEqual(r.destroyed, false) - errored.resolve(); - } - ) - oldStream.emit('error', err) + .on('error', () => { + strictEqual(r._readableState.errorEmitted, true); + strictEqual(r._readableState.errored, err); + strictEqual(r.destroyed, false); + errored.resolve(); + }); + oldStream.emit('error', err); await errored.promise; } - } + }, }; export const readable_wrap_empty = { @@ -3827,7 +3712,7 @@ export const readable_wrap_empty = { newStream.on('readable', () => {}).on('end', ended.resolve); oldStream.emit('end'); await ended.promise; - } + }, }; export const readable_wrap_destroy = { @@ -3839,7 +3724,7 @@ export const readable_wrap_destroy = { const destroyCalled = deferredPromise; new Readable({ autoDestroy: false, - destroy: destroyCalled.resolve + destroy: destroyCalled.resolve, }).wrap(oldStream); oldStream.emit('destroy'); await destroyCalled.promise; @@ -3848,12 +3733,12 @@ export const readable_wrap_destroy = { const destroyCalled = deferredPromise; new Readable({ autoDestroy: false, - destroy: destroyCalled.resolve + destroy: destroyCalled.resolve, }).wrap(oldStream); oldStream.emit('close'); await destroyCalled.promise; } - } + }, }; export const readable_non_empty_end = { @@ -3871,7 +3756,7 @@ export const readable_non_empty_end = { setTimeout(function () { test.push(chunk === undefined ? null : chunk); }, 1); - } + }; test.on('end', thrower); function thrower() { throw new Error('this should not happen!'); @@ -3886,7 +3771,7 @@ export const readable_non_empty_end = { setTimeout(next, 1); } test.read(0); - }) + }); test.read(0); function next() { // Now let's make 'end' happen @@ -3901,7 +3786,7 @@ export const readable_non_empty_end = { strictEqual(r, null); } await ended.promise; - } + }, }; export const readable_legacy_drain = { @@ -3921,7 +3806,7 @@ export const readable_legacy_drain = { buffered += c.length; queueMicrotask(drain); return false; - } + }; function drain() { ok(buffered <= 3); buffered = 0; @@ -3930,11 +3815,8 @@ export const readable_legacy_drain = { const ended2 = deferredPromise(); w.end = ended2.resolve; r.pipe(w); - await Promise.all([ - ended1.promise, - ended2.promise, - ]); - } + await Promise.all([ended1.promise, ended2.promise]); + }, }; export const read_sync_stack = { @@ -3948,24 +3830,24 @@ export const read_sync_stack = { r._read = function (n) { const chunk = reads++ === N ? null : Buffer.allocUnsafe(1); r.push(chunk); - } + }; r.on('readable', function onReadable() { r.read(N * 2); - }) + }); const ended = deferredPromise(); r.on('end', ended.resolve); r.read(0); await ended.promise; - } + }, }; export const stream2_push = { async test(ctrl, env, ctx) { const stream = new Readable({ highWaterMark: 16, - encoding: 'utf8' + encoding: 'utf8', }); - const source = new EventEmitter() + const source = new EventEmitter(); stream._read = function () { readStart(); }; @@ -3974,7 +3856,7 @@ export const stream2_push = { source.on('data', function (chunk) { const ret = stream.push(chunk); if (!ret) readStop(); - }) + }); source.on('end', function () { stream.push(null); }); @@ -3990,7 +3872,7 @@ export const stream2_push = { }); } const writer = new Writable({ - decodeStrings: false + decodeStrings: false, }); const written = []; const expectWritten = [ @@ -3999,12 +3881,12 @@ export const stream2_push = { 'asdfgasdfgasdfgasdfg', 'asdfgasdfgasdfgasdfg', 'asdfgasdfgasdfgasdfg', - 'asdfgasdfgasdfgasdfg' + 'asdfgasdfgasdfgasdfg', ]; writer._write = function (chunk, encoding, cb) { written.push(chunk); queueMicrotask(cb); - } + }; writer.on('finish', finish); // Now emit some chunks. @@ -4032,10 +3914,10 @@ export const stream2_push = { function end() { source.emit('end'); ok(!reading); - writer.end(stream.read()) + writer.end(stream.read()); } await ended.promise; - } + }, }; export const stream2_pipe_error_once_listener = { @@ -4055,10 +3937,10 @@ export const stream2_pipe_error_once_listener = { const write = new Write(); const errored = deferredPromise(); write.once('error', errored.resolve); - read.pipe(write) + read.pipe(write); await errored.promise; - } + }, }; export const stream2_pipe_error_handling = { @@ -4109,7 +3991,7 @@ export const stream2_pipe_error_handling = { Readable.prototype.unpipe.call(this, dest); }; const dest = new Writable({ - autoDestroy: false + autoDestroy: false, }); dest._write = function (chunk, encoding, cb) { cb(); @@ -4130,14 +4012,14 @@ export const stream2_pipe_error_handling = { strictEqual(unpipedSource, source); strictEqual(unpipedDest, dest); } - } + }, }; export const stream2_objects = { async test(ctrl, env, ctx) { function toArray(callback) { const stream = new Writable({ - objectMode: true + objectMode: true, }); const list = []; stream.write = function (chunk) { @@ -4152,9 +4034,11 @@ export const stream2_objects = { } function fromArray(list) { const r = new Readable({ - objectMode: true + objectMode: true, }); - r._read = () => { throw new Error('should not have been called'); }; + r._read = () => { + throw new Error('should not have been called'); + }; list.forEach(function (chunk) { r.push(chunk); }); @@ -4165,20 +4049,20 @@ export const stream2_objects = { // Verify that objects can be read from the stream const r = fromArray([ { - one: '1' + one: '1', }, { - two: '2' - } + two: '2', + }, ]); const v1 = r.read(); const v2 = r.read(); const v3 = r.read(); deepStrictEqual(v1, { - one: '1' + one: '1', }); deepStrictEqual(v2, { - two: '2' + two: '2', }); strictEqual(v3, null); } @@ -4186,24 +4070,22 @@ export const stream2_objects = { // Verify that objects can be piped into the stream const r = fromArray([ { - one: '1' + one: '1', }, { - two: '2' - } + two: '2', + }, ]); - const w = toArray( - function (list) { - deepStrictEqual(list, [ - { - one: '1' - }, - { - two: '2' - } - ]) - } - ); + const w = toArray(function (list) { + deepStrictEqual(list, [ + { + one: '1', + }, + { + two: '2', + }, + ]); + }); r.pipe(w); await w.ended.promise; } @@ -4211,131 +4093,123 @@ export const stream2_objects = { // Verify that read(n) is ignored const r = fromArray([ { - one: '1' + one: '1', }, { - two: '2' - } + two: '2', + }, ]); const value = r.read(2); deepStrictEqual(value, { - one: '1' + one: '1', }); } { // Verify that objects can be synchronously read const r = new Readable({ - objectMode: true + objectMode: true, }); const list = [ { - one: '1' + one: '1', }, { - two: '2' - } + two: '2', + }, ]; r._read = function (n) { - const item = list.shift() - r.push(item || null) + const item = list.shift(); + r.push(item || null); }; - const dest = toArray( - function (list) { - deepStrictEqual(list, [ - { - one: '1' - }, - { - two: '2' - } - ]) - } - ); + const dest = toArray(function (list) { + deepStrictEqual(list, [ + { + one: '1', + }, + { + two: '2', + }, + ]); + }); r.pipe(dest); await dest.ended.promise; } { // Verify that objects can be asynchronously read const r = new Readable({ - objectMode: true + objectMode: true, }); const list = [ { - one: '1' + one: '1', }, { - two: '2' - } + two: '2', + }, ]; r._read = function (n) { const item = list.shift(); queueMicrotask(function () { r.push(item || null); }); - } - const dest = toArray( - function (list) { - deepStrictEqual(list, [ - { - one: '1' - }, - { - two: '2' - } - ]) - } - ); + }; + const dest = toArray(function (list) { + deepStrictEqual(list, [ + { + one: '1', + }, + { + two: '2', + }, + ]); + }); r.pipe(dest); await dest.ended.promise; } { // Verify that strings can be read as objects const r = new Readable({ - objectMode: true + objectMode: true, }); - r._read = () => { throw new Error('should not have been called'); }; + r._read = () => { + throw new Error('should not have been called'); + }; const list = ['one', 'two', 'three']; list.forEach(function (str) { r.push(str); }); r.push(null); - const dest = toArray( - function (array) { - deepStrictEqual(array, list); - } - ); + const dest = toArray(function (array) { + deepStrictEqual(array, list); + }); r.pipe(dest); await dest.ended.promise; } { // Verify read(0) behavior for object streams const r = new Readable({ - objectMode: true + objectMode: true, }); r.push('foobar'); r.push(null); - const dest = toArray( - function (array) { - deepStrictEqual(array, ['foobar']) - } - ); + const dest = toArray(function (array) { + deepStrictEqual(array, ['foobar']); + }); r.pipe(dest); await dest.ended.promise; } { // Verify the behavior of pushing falsey values const r = new Readable({ - objectMode: true + objectMode: true, }); r.push(false); r.push(0); r.push(''); r.push(null); - const dest = toArray( - function (array) { - deepStrictEqual(array, [false, 0, '']); - } - ); + const dest = toArray(function (array) { + deepStrictEqual(array, [false, 0, '']); + }); r.pipe(dest); await dest.ended.promise; } @@ -4343,7 +4217,7 @@ export const stream2_objects = { // Verify high watermark _read() behavior const r = new Readable({ highWaterMark: 6, - objectMode: true + objectMode: true, }); let calls = 0; const list = ['1', '2', '3', '4', '5', '6', '7', '8']; @@ -4366,9 +4240,11 @@ export const stream2_objects = { // Verify high watermark push behavior const r = new Readable({ highWaterMark: 6, - objectMode: true + objectMode: true, }); - r._read = () => { throw new Error("should not have been called"); }; + r._read = () => { + throw new Error('should not have been called'); + }; for (let i = 0; i < 6; i++) { const bool = r.push(i); strictEqual(bool, i !== 5); @@ -4377,18 +4253,18 @@ export const stream2_objects = { { // Verify that objects can be written to stream const w = new Writable({ - objectMode: true + objectMode: true, }); w._write = function (chunk, encoding, cb) { deepStrictEqual(chunk, { - foo: 'bar' + foo: 'bar', }); cb(); - } + }; const finishCalled = deferredPromise(); w.on('finish', finishCalled.resolve); w.write({ - foo: 'bar' + foo: 'bar', }); w.end(); await finishCalled.promise; @@ -4396,7 +4272,7 @@ export const stream2_objects = { { // Verify that multiple objects can be written to stream const w = new Writable({ - objectMode: true + objectMode: true, }); const list = []; w._write = function (chunk, encoding, cb) { @@ -4404,13 +4280,10 @@ export const stream2_objects = { cb(); }; const finishCalled = deferredPromise(); - w.on( - 'finish', - function () { - deepStrictEqual(list, [0, 1, 2, 3, 4]); - finishCalled.resolve(); - } - ) + w.on('finish', function () { + deepStrictEqual(list, [0, 1, 2, 3, 4]); + finishCalled.resolve(); + }); w.write(0); w.write(1); w.write(2); @@ -4422,21 +4295,18 @@ export const stream2_objects = { { // Verify that strings can be written as objects const w = new Writable({ - objectMode: true + objectMode: true, }); const list = []; w._write = function (chunk, encoding, cb) { list.push(chunk); queueMicrotask(cb); - } + }; const finishCalled = deferredPromise(); - w.on( - 'finish', - function () { - deepStrictEqual(list, ['0', '1', '2', '3', '4']); - finishCalled.resolve(); - } - ) + w.on('finish', function () { + deepStrictEqual(list, ['0', '1', '2', '3', '4']); + finishCalled.resolve(); + }); w.write('0'); w.write('1'); w.write('2'); @@ -4448,7 +4318,7 @@ export const stream2_objects = { { // Verify that stream buffers finish until callback is called const w = new Writable({ - objectMode: true + objectMode: true, }); let called = false; w._write = function (chunk, encoding, cb) { @@ -4457,20 +4327,17 @@ export const stream2_objects = { called = true; cb(); }); - } + }; const finishCalled = deferredPromise(); - w.on( - 'finish', - function () { - strictEqual(called, true); - finishCalled.resolve(); - } - ) + w.on('finish', function () { + strictEqual(called, true); + finishCalled.resolve(); + }); w.write('foo'); w.end(); await finishCalled.promise; } - } + }, }; export const stream2_large_read_stall = { @@ -4483,7 +4350,7 @@ export const stream2_large_read_stall = { const PUSHCOUNT = 1000; const HWM = 50; const r = new Readable({ - highWaterMark: HWM + highWaterMark: HWM, }); const rs = r._readableState; r._read = push; @@ -4494,13 +4361,10 @@ export const stream2_large_read_stall = { } while (ret && ret.length === READSIZE); }); const ended = deferredPromise(); - r.on( - 'end', - function () { - strictEqual(pushes, PUSHCOUNT + 1); - ended.resolve(); - } - ) + r.on('end', function () { + strictEqual(pushes, PUSHCOUNT + 1); + ended.resolve(); + }); let pushes = 0; function push() { if (pushes > PUSHCOUNT) return; @@ -4510,7 +4374,7 @@ export const stream2_large_read_stall = { if (r.push(Buffer.allocUnsafe(PUSHSIZE))) setTimeout(push, 1); } await ended.promise; - } + }, }; export const stream2_decode_partial = { @@ -4520,7 +4384,7 @@ export const stream2_decode_partial = { const cent = Buffer.from([0xc2, 0xa2]); const source = Buffer.concat([euro, cent]); const readable = Readable({ - encoding: 'utf8' + encoding: 'utf8', }); readable.push(source.slice(0, 2)); readable.push(source.slice(2, 4)); @@ -4534,7 +4398,7 @@ export const stream2_decode_partial = { await closed.promise; strictEqual(buf, '€¢'); - } + }, }; export const stream2_compatibility = { @@ -4546,7 +4410,7 @@ export const stream2_compatibility = { this._buffer = Buffer.alloc(100, 'x'); this.on('data', () => { ondataCalled++; - }) + }); } _read(n) { this.push(this._buffer); @@ -4557,7 +4421,7 @@ export const stream2_compatibility = { queueMicrotask(function () { strictEqual(ondataCalled, 1); reader.push(null); - }) + }); class TestWriter extends Writable { constructor() { super(); @@ -4575,68 +4439,64 @@ export const stream2_compatibility = { reader.on('close', readerClose.resolve); writer.on('close', writerClose.resolve); - await Promise.all([ - readerClose.promise, - writerClose.promise, - ]); + await Promise.all([readerClose.promise, writerClose.promise]); strictEqual(reader.readable, false); strictEqual(writer.writable, false); - } + }, }; export const stream2_basic = { async test(ctrl, env, ctx) { - class TestReader extends Readable { constructor(n) { - super() - this._buffer = Buffer.alloc(n || 100, 'x') - this._pos = 0 - this._bufs = 10 + super(); + this._buffer = Buffer.alloc(n || 100, 'x'); + this._pos = 0; + this._bufs = 10; } _read(n) { - const max = this._buffer.length - this._pos - n = Math.max(n, 0) - const toRead = Math.min(n, max) + const max = this._buffer.length - this._pos; + n = Math.max(n, 0); + const toRead = Math.min(n, max); if (toRead === 0) { // Simulate the read buffer filling up with some more bytes some time // in the future. setTimeout(() => { - this._pos = 0 - this._bufs -= 1 + this._pos = 0; + this._bufs -= 1; if (this._bufs <= 0) { // read them all! - if (!this.ended) this.push(null) + if (!this.ended) this.push(null); } else { // now we have more. // kinda cheating by calling _read, but whatever, // it's just fake anyway. - this._read(n) + this._read(n); } - }, 10) - return + }, 10); + return; } - const ret = this._buffer.slice(this._pos, this._pos + toRead) - this._pos += toRead - this.push(ret) + const ret = this._buffer.slice(this._pos, this._pos + toRead); + this._pos += toRead; + this.push(ret); } } class TestWriter extends EventEmitter { constructor() { - super() - this.received = [] - this.flush = false + super(); + this.received = []; + this.flush = false; } write(c) { - this.received.push(c.toString()) - this.emit('write', c) - return true + this.received.push(c.toString()); + this.emit('write', c); + return true; } end(c) { - if (c) this.write(c) - this.emit('end', this.received) + if (c) this.write(c); + this.emit('end', this.received); } } @@ -4660,14 +4520,11 @@ export const stream2_basic = { 'xxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxx', - 'xxxxxxxxxxxxxxxxxxxxx' + 'xxxxxxxxxxxxxxxxxxxxx', ]; - r.on( - 'end', - function () { - deepStrictEqual(reads, expect); - } - ); + r.on('end', function () { + deepStrictEqual(reads, expect); + }); let readSize = 1; function flow() { let res; @@ -4683,119 +4540,148 @@ export const stream2_basic = { { // Verify pipe const r = new TestReader(5); - const expect = ['xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx']; + const expect = [ + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + ]; const w = new TestWriter(); - w.on( - 'end', - function (received) { - deepStrictEqual(received, expect); - } - ); + w.on('end', function (received) { + deepStrictEqual(received, expect); + }); r.pipe(w); await promises.finished(r); } - await Promise.all([1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) { - // Verify unpipe - const r = new TestReader(5); - - // Unpipe after 3 writes, then write to another stream instead. - let expect = ['xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx']; - expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)]; - const w = [new TestWriter(), new TestWriter()]; - let writes = SPLIT; - w[0].on('write', function () { - if (--writes === 0) { - r.unpipe(); - deepStrictEqual(r._readableState.pipes, []); - w[0].end(); - r.pipe(w[1]); - deepStrictEqual(r._readableState.pipes, [w[1]]); - } - }); - let ended = 0; - w[0].on( - 'end', - function (results) { + await Promise.all( + [1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) { + // Verify unpipe + const r = new TestReader(5); + + // Unpipe after 3 writes, then write to another stream instead. + let expect = [ + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + ]; + expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)]; + const w = [new TestWriter(), new TestWriter()]; + let writes = SPLIT; + w[0].on('write', function () { + if (--writes === 0) { + r.unpipe(); + deepStrictEqual(r._readableState.pipes, []); + w[0].end(); + r.pipe(w[1]); + deepStrictEqual(r._readableState.pipes, [w[1]]); + } + }); + let ended = 0; + w[0].on('end', function (results) { ended++; strictEqual(ended, 1); deepStrictEqual(results, expect[0]); - } - ); - w[1].on( - 'end', - function (results) { + }); + w[1].on('end', function (results) { ended++; strictEqual(ended, 2); deepStrictEqual(results, expect[1]); - } - ); - r.pipe(w[0]); - await promises.finished(r); - })); + }); + r.pipe(w[0]); + await promises.finished(r); + }) + ); { // Verify both writers get the same data when piping to destinations const r = new TestReader(5); const w = [new TestWriter(), new TestWriter()]; - const expect = ['xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx']; - w[0].on( - 'end', - function (received) { - deepStrictEqual(received, expect); - } - ); - w[1].on( - 'end', - function (received) { - deepStrictEqual(received, expect); - } - ); + const expect = [ + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + ]; + w[0].on('end', function (received) { + deepStrictEqual(received, expect); + }); + w[1].on('end', function (received) { + deepStrictEqual(received, expect); + }); r.pipe(w[0]); r.pipe(w[1]); await promises.finished(r); } - await Promise.all([1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) { - // Verify multi-unpipe - const r = new TestReader(5); - - // Unpipe after 3 writes, then write to another stream instead. - let expect = ['xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx']; - expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)]; - const w = [new TestWriter(), new TestWriter(), new TestWriter()]; - let writes = SPLIT; - w[0].on('write', function () { - if (--writes === 0) { - r.unpipe(); - w[0].end(); - r.pipe(w[1]); - } - }); - let ended = 0; - w[0].on( - 'end', - function (results) { - ended++ + await Promise.all( + [1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) { + // Verify multi-unpipe + const r = new TestReader(5); + + // Unpipe after 3 writes, then write to another stream instead. + let expect = [ + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + ]; + expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)]; + const w = [new TestWriter(), new TestWriter(), new TestWriter()]; + let writes = SPLIT; + w[0].on('write', function () { + if (--writes === 0) { + r.unpipe(); + w[0].end(); + r.pipe(w[1]); + } + }); + let ended = 0; + w[0].on('end', function (results) { + ended++; strictEqual(ended, 1); deepStrictEqual(results, expect[0]); - } - ); - w[1].on( - 'end', - function (results) { + }); + w[1].on('end', function (results) { ended++; strictEqual(ended, 2); deepStrictEqual(results, expect[1]); - } - ); - r.pipe(w[0]); - r.pipe(w[2]); - await promises.finished(r); - })); + }); + r.pipe(w[0]); + r.pipe(w[2]); + await promises.finished(r); + }) + ); { // Verify that back pressure is respected const r = new Readable({ - objectMode: true + objectMode: true, }); - r._read = () => { throw new Error('should not have been called'); }; + r._read = () => { + throw new Error('should not have been called'); + }; let counter = 0; r.push(['one']); r.push(['two']); @@ -4811,7 +4697,9 @@ export const stream2_basic = { r.pipe(w3); }); }; - w1.end = () => { throw new Error('should not have been called'); }; + w1.end = () => { + throw new Error('should not have been called'); + }; r.pipe(w1); const expected = ['two', 'two', 'three', 'three', 'four', 'four']; const w2 = new Readable(); @@ -4827,7 +4715,7 @@ export const stream2_basic = { w2.emit('drain'); }, 10); return false; - } + }; const ended2 = deferredPromise(); w2.end = ended2.resolve; const w3 = new Readable(); @@ -4843,24 +4731,23 @@ export const stream2_basic = { w3.emit('drain'); }, 50); return false; - } + }; const ended3 = deferredPromise(); w3.end = function () { strictEqual(counter, 2); strictEqual(expected.length, 0); ended3.resolve(); }; - await Promise.all([ - ended2.promise, - ended3.promise, - ]); + await Promise.all([ended2.promise, ended3.promise]); } { // Verify read(0) behavior for ended streams const r = new Readable(); let written = false; let ended = false; - r._read = () => { throw new Error('should not have been called'); }; + r._read = () => { + throw new Error('should not have been called'); + }; r.push(Buffer.from('foo')); r.push(null); const v = r.read(0); @@ -4872,7 +4759,7 @@ export const stream2_basic = { strictEqual(ended, false); strictEqual(buffer.toString(), 'foo'); writeCalled.resolve(); - } + }; const endCalled = deferredPromise(); w.end = function () { ended = true; @@ -4880,10 +4767,7 @@ export const stream2_basic = { endCalled.resolve(); }; r.pipe(w); - await Promise.all([ - endCalled.promise, - writeCalled.promise, - ]); + await Promise.all([endCalled.promise, writeCalled.promise]); } { // Verify synchronous _read ending @@ -4891,40 +4775,37 @@ export const stream2_basic = { let called = false; r._read = function (n) { r.push(null); - } + }; r.once('end', function () { // Verify that this is called before the next tick called = true; - }) + }); r.read(); queueMicrotask(function () { - strictEqual(called, true) - }) + strictEqual(called, true); + }); } { // Verify that adding readable listeners trigger data flow const r = new Readable({ - highWaterMark: 5 + highWaterMark: 5, }); let onReadable = false; let readCalled = 0; r._read = function (n) { if (readCalled++ === 2) r.push(null); else r.push(Buffer.from('asdf')); - } + }; r.on('readable', function () { onReadable = true; r.read(); }); const endCalled = deferredPromise(); - r.on( - 'end', - function () { - strictEqual(readCalled, 3); - ok(onReadable); - endCalled.resolve(); - } - ); + r.on('end', function () { + strictEqual(readCalled, 3); + ok(onReadable); + endCalled.resolve(); + }); await endCalled.promise; } { @@ -4940,7 +4821,7 @@ export const stream2_basic = { // Verify readableEncoding property ok(Reflect.has(Readable.prototype, 'readableEncoding')); const r = new Readable({ - encoding: 'utf8' + encoding: 'utf8', }); strictEqual(r.readableEncoding, 'utf8'); } @@ -4948,7 +4829,7 @@ export const stream2_basic = { // Verify readableObjectMode property ok(Reflect.has(Readable.prototype, 'readableObjectMode')); const r = new Readable({ - objectMode: true + objectMode: true, }); strictEqual(r.readableObjectMode, true); } @@ -4956,17 +4837,17 @@ export const stream2_basic = { // Verify writableObjectMode property ok(Reflect.has(Writable.prototype, 'writableObjectMode')); const w = new Writable({ - objectMode: true + objectMode: true, }); strictEqual(w.writableObjectMode, true); } - } + }, }; export const stream2_base64_single_char_read_end = { async test(ctrl, env, ctx) { const src = new Readable({ - encoding: 'base64' + encoding: 'base64', }); const dst = new Writable(); let hasRead = false; @@ -4987,12 +4868,12 @@ export const stream2_base64_single_char_read_end = { src.on('end', function () { strictEqual(String(Buffer.concat(accum)), 'MQ=='); clearTimeout(timeout); - }) + }); src.pipe(dst); const timeout = setTimeout(function () { fail('timed out waiting for _write'); }, 100); - } + }, }; export const writev = { @@ -5020,67 +4901,73 @@ export const writev = { ifError(er); counter++; strictEqual(counter, expect); - } + }; } const w = new Writable({ - decodeStrings: decode + decodeStrings: decode, }); - w._write = () => { throw new Error('Should not call _write'); }; + w._write = () => { + throw new Error('Should not call _write'); + }; const expectChunks = decode ? [ { encoding: 'buffer', - chunk: [104, 101, 108, 108, 111, 44, 32] + chunk: [104, 101, 108, 108, 111, 44, 32], }, { encoding: 'buffer', - chunk: [119, 111, 114, 108, 100] + chunk: [119, 111, 114, 108, 100], }, { encoding: 'buffer', - chunk: [33] + chunk: [33], }, { encoding: 'buffer', - chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46] + chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46], }, { encoding: 'buffer', - chunk: [250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173] - } + chunk: [ + 250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173, + ], + }, ] : [ { encoding: 'ascii', - chunk: 'hello, ' + chunk: 'hello, ', }, { encoding: 'utf8', - chunk: 'world' + chunk: 'world', }, { encoding: 'buffer', - chunk: [33] + chunk: [33], }, { encoding: 'latin1', - chunk: '\nand then...' + chunk: '\nand then...', }, { encoding: 'hex', - chunk: 'facebea7deadbeefdecafbad' - } + chunk: 'facebea7deadbeefdecafbad', + }, ]; let actualChunks; w._writev = function (chunks, cb) { actualChunks = chunks.map(function (chunk) { return { encoding: chunk.encoding, - chunk: Buffer.isBuffer(chunk.chunk) ? Array.prototype.slice.call(chunk.chunk) : chunk.chunk + chunk: Buffer.isBuffer(chunk.chunk) + ? Array.prototype.slice.call(chunk.chunk) + : chunk.chunk, }; }); cb(); - } + }; w.cork(); w.write('hello, ', 'ascii', cnt('hello')); w.write('world', 'utf8', cnt('world')); @@ -5105,15 +4992,12 @@ export const writev = { writev: function (chunks, cb) { cb(); writeCalled.resolve(); - } - }) + }, + }); w.write('asd', writeFinished.resolve); - await Promise.all([ - writeCalled.promise, - writeFinished.promise, - ]); + await Promise.all([writeCalled.promise, writeFinished.promise]); } - } + }, }; export const writeFinal = { @@ -5132,36 +5016,32 @@ export const writeFinal = { }, write: function (chunk, e, cb) { queueMicrotask(cb); - } - }) - w.on( - 'finish', - function () { - ok(shutdown); - finishCalled.resolve(); - } - ) + }, + }); + w.on('finish', function () { + ok(shutdown); + finishCalled.resolve(); + }); w.write(Buffer.allocUnsafe(1)); w.end(Buffer.allocUnsafe(0)); - await Promise.all([ - finalCalled.promise, - finishCalled.promise, - ]); - } + await Promise.all([finalCalled.promise, finishCalled.promise]); + }, }; export const writeDrain = { async test(ctrl, env, ctx) { const w = new Writable({ write(data, enc, cb) { - queueMicrotask(cb) + queueMicrotask(cb); }, - highWaterMark: 1 + highWaterMark: 1, + }); + w.on('drain', () => { + throw new Error('should not be called'); }); - w.on('drain', () => { throw new Error('should not be called'); }); w.write('asd'); w.end(); - } + }, }; export const writeDestroy = { @@ -5174,7 +5054,7 @@ export const writeDestroy = { callbacks.push(cb); }, // Effectively disable the HWM to observe 'drain' events more easily. - highWaterMark: 1 + highWaterMark: 1, }); let chunksWritten = 0; let drains = 0; @@ -5186,7 +5066,7 @@ export const writeDestroy = { } else { chunksWritten++; } - }; + } w.write('abc', onWrite); strictEqual(chunksWritten, 0); strictEqual(drains, 0); @@ -5208,13 +5088,13 @@ export const writeDestroy = { strictEqual(chunksWritten, 1); w.destroy(); strictEqual(chunksWritten, 1); - callbacks.shift()() + callbacks.shift()(); strictEqual(chunksWritten, useEnd && !withPendingData ? 1 : 2); strictEqual(callbacks.length, 0); strictEqual(drains, 1); } } - } + }, }; export const writableState_uncorked_bufferedRequestCount = { @@ -5258,7 +5138,7 @@ export const writableState_uncorked_bufferedRequestCount = { const uncorkCalled = deferredPromise(); function uncork() { // Second uncork flushes the buffer - writable.uncork() + writable.uncork(); strictEqual(writable._writableState.corked, 0); strictEqual(writable._writableState.bufferedRequestCount, 0); @@ -5278,7 +5158,7 @@ export const writableState_uncorked_bufferedRequestCount = { writeCalled.promise, uncorkCalled.promise, ]); - } + }, }; export const writeableState_ending = { @@ -5309,7 +5189,7 @@ export const writeableState_ending = { // Ending, ended = true. // finished = false. testStates(true, false, true); - } + }, }; export const writable_write_writev_finish = { @@ -5319,16 +5199,13 @@ export const writable_write_writev_finish = { const errored = deferredPromise(); writable._write = (chunks, encoding, cb) => { cb(new Error('write test error')); - } + }; writable.on('finish', errored.reject); writable.on('prefinish', errored.reject); - writable.on( - 'error', - (er) => { - strictEqual(er.message, 'write test error'); - errored.resolve(); - } - ); + writable.on('error', (er) => { + strictEqual(er.message, 'write test error'); + errored.resolve(); + }); writable.end('test'); await errored.promise; } @@ -5337,16 +5214,13 @@ export const writable_write_writev_finish = { const errored = deferredPromise(); writable._write = (chunks, encoding, cb) => { queueMicrotask(() => cb(new Error('write test error'))); - } + }; writable.on('finish', errored.reject); - writable.on('prefinish', errored.reject) - writable.on( - 'error', - (er) => { - strictEqual(er.message, 'write test error'); - errored.resolve(); - } - ) + writable.on('prefinish', errored.reject); + writable.on('error', (er) => { + strictEqual(er.message, 'write test error'); + errored.resolve(); + }); writable.end('test'); await errored.promise; } @@ -5361,13 +5235,10 @@ export const writable_write_writev_finish = { }; writable.on('finish', errored.reject); writable.on('prefinish', errored.reject); - writable.on( - 'error', - (er) => { - strictEqual(er.message, 'writev test error'); - errored.resolve(); - } - ); + writable.on('error', (er) => { + strictEqual(er.message, 'writev test error'); + errored.resolve(); + }); writable.cork(); writable.write('test'); queueMicrotask(function () { @@ -5380,19 +5251,16 @@ export const writable_write_writev_finish = { const errored = deferredPromise(); writable._write = (chunks, encoding, cb) => { queueMicrotask(() => cb(new Error('write test error'))); - } + }; writable._writev = (chunks, cb) => { queueMicrotask(() => cb(new Error('writev test error'))); - } + }; writable.on('finish', errored.reject); writable.on('prefinish', errored.reject); - writable.on( - 'error', - (er) => { - strictEqual(er.message, 'writev test error'); - errored.resolve(); - } - ) + writable.on('error', (er) => { + strictEqual(er.message, 'writev test error'); + errored.resolve(); + }); writable.cork(); writable.write('test'); queueMicrotask(function () { @@ -5415,7 +5283,7 @@ export const writable_write_writev_finish = { ws.on('error', errored.resolve); ws._write = (chunk, encoding, done) => { queueMicrotask(() => done(new Error())); - } + }; rs.pipe(ws); await errored.promise; } @@ -5430,7 +5298,7 @@ export const writable_write_writev_finish = { ws.on('error', errored.resolve); ws._write = (chunk, encoding, done) => { done(new Error()); - } + }; rs.pipe(ws); await errored.promise; } @@ -5438,13 +5306,13 @@ export const writable_write_writev_finish = { const w = new Writable(); w._write = (chunk, encoding, cb) => { queueMicrotask(cb); - } + }; const errored = deferredPromise(); w.on('error', errored.resolve); - w.on('finish', errored.reject) + w.on('finish', errored.reject); w.on('prefinish', () => { w.write("shouldn't write in prefinish listener"); - }) + }); w.end(); await errored.promise; } @@ -5457,11 +5325,11 @@ export const writable_write_writev_finish = { w.on('error', errored.resolve); w.on('finish', () => { w.write("shouldn't write in finish listener"); - }) + }); w.end(); await errored.promise; } - } + }, }; export const writable_write_error = { @@ -5470,7 +5338,7 @@ export const writable_write_error = { if (sync) { if (code) { throws(() => w.write(...args), { - code + code, }); } else { w.write(...args); @@ -5479,33 +5347,24 @@ export const writable_write_error = { let ticked = false; const writeCalled = deferredPromise(); const errorCalled = deferredPromise(); - w.write( - ...args, - (err) => { - strictEqual(ticked, true); - strictEqual(err.code, code); - writeCalled.resolve(); - } - ); + w.write(...args, (err) => { + strictEqual(ticked, true); + strictEqual(err.code, code); + writeCalled.resolve(); + }); ticked = true; - w.on( - 'error', - (err) => { - strictEqual(err.code, code); - errorCalled.resolve(); - } - ); - await Promise.all([ - writeCalled.promise, - errorCalled.promise, - ]); + w.on('error', (err) => { + strictEqual(err.code, code); + errorCalled.resolve(); + }); + await Promise.all([writeCalled.promise, errorCalled.promise]); } } async function test(autoDestroy) { { const w = new Writable({ autoDestroy, - _write() {} + _write() {}, }); w.end(); await expectError(w, ['asd'], 'ERR_STREAM_WRITE_AFTER_END'); @@ -5513,21 +5372,21 @@ export const writable_write_error = { { const w = new Writable({ autoDestroy, - _write() {} + _write() {}, }); w.destroy(); } { const w = new Writable({ autoDestroy, - _write() {} + _write() {}, }); await expectError(w, [null], 'ERR_STREAM_NULL_VALUES', true); } { const w = new Writable({ autoDestroy, - _write() {} + _write() {}, }); await expectError(w, [{}], 'ERR_INVALID_ARG_TYPE', true); } @@ -5535,14 +5394,19 @@ export const writable_write_error = { const w = new Writable({ decodeStrings: false, autoDestroy, - _write() {} + _write() {}, }); - await expectError(w, ['asd', 'noencoding'], 'ERR_UNKNOWN_ENCODING', true); + await expectError( + w, + ['asd', 'noencoding'], + 'ERR_UNKNOWN_ENCODING', + true + ); } } - await test(false) - await test(true) - } + await test(false); + await test(true); + }, }; export const writable_write_cb_twice = { @@ -5556,20 +5420,14 @@ export const writable_write_cb_twice = { cb(); cb(); writeCalled.resolve(); - } + }, }); writable.write('hi'); - writable.on( - 'error', - function(err) { - strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); - errored.resolve(); - } - ); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + writable.on('error', function (err) { + strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); + errored.resolve(); + }); + await Promise.all([writeCalled.promise, errored.promise]); } { // Sync + Async @@ -5582,20 +5440,14 @@ export const writable_write_cb_twice = { cb(); writeCalled.resolve(); }); - } - }) + }, + }); writable.write('hi'); - writable.on( - 'error', - function (err) { - strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); - errored.resolve(); - } - ); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + writable.on('error', function (err) { + strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); + errored.resolve(); + }); + await Promise.all([writeCalled.promise, errored.promise]); } { // Async + Async @@ -5608,22 +5460,16 @@ export const writable_write_cb_twice = { cb(); writeCalled.resolve(); }); - } + }, }); writable.write('hi'); - writable.on( - 'error', - function (err) { - strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); - errored.resolve(); - } - ); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + writable.on('error', function (err) { + strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); + errored.resolve(); + }); + await Promise.all([writeCalled.promise, errored.promise]); } - } + }, }; export const writable_write_cb_error = { @@ -5638,22 +5484,16 @@ export const writable_write_cb_error = { write: (buf, enc, cb) => { cb(new Error()); writeCalled.resolve(); - } + }, + }); + writable.on('error', () => { + strictEqual(callbackCalled, true); + errored.resolve(); + }); + writable.write('hi', () => { + callbackCalled = true; + writeFinished.resolve(); }); - writable.on( - 'error', - () => { - strictEqual(callbackCalled, true); - errored.resolve(); - } - ); - writable.write( - 'hi', - () => { - callbackCalled = true; - writeFinished.resolve(); - } - ); await Promise.all([ writeCalled.promise, errored.promise, @@ -5670,22 +5510,16 @@ export const writable_write_cb_error = { write: (buf, enc, cb) => { queueMicrotask(() => cb(new Error())); writeCalled.resolve(); - } + }, + }); + writable.on('error', () => { + strictEqual(callbackCalled, true); + errored.resolve(); + }); + writable.write('hi', () => { + callbackCalled = true; + writeFinished.resolve(); }); - writable.on( - 'error', - () => { - strictEqual(callbackCalled, true); - errored.resolve(); - } - ); - writable.write( - 'hi', - () => { - callbackCalled = true; - writeFinished.resolve(); - } - ); await Promise.all([ writeCalled.promise, errored.promise, @@ -5700,26 +5534,23 @@ export const writable_write_cb_error = { write: (buf, enc, cb) => { cb(new Error()); writeCalled.resolve(); - } + }, }); writable.on('error', errored.resolve); let cnt = 0; // Ensure we don't live lock on sync error while (writable.write('a')) cnt++; strictEqual(cnt, 0); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + await Promise.all([writeCalled.promise, errored.promise]); } - } + }, }; export const writable_writable = { async test(ctrl, env, ctx) { { const w = new Writable({ - write() {} + write() {}, }); strictEqual(w.writable, true); w.destroy(); @@ -5732,16 +5563,13 @@ export const writable_writable = { write: (chunk, encoding, callback) => { callback(new Error()); writeCalled.resolve(); - } - }) + }, + }); strictEqual(w.writable, true); w.write('asd'); strictEqual(w.writable, false); w.on('error', errored.resolve); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + await Promise.all([writeCalled.promise, errored.promise]); } { const writeCalled = deferredPromise(); @@ -5749,31 +5577,28 @@ export const writable_writable = { const w = new Writable({ write: (chunk, encoding, callback) => { queueMicrotask(() => { - callback(new Error()) + callback(new Error()); strictEqual(w.writable, false); writeCalled.resolve(); - }) - } + }); + }, }); w.write('asd'); w.on('error', errored.resolve); - await Promise.all([ - writeCalled.promise, - errored.promise, - ]); + await Promise.all([writeCalled.promise, errored.promise]); } { const closed = deferredPromise(); const w = new Writable({ - write: closed.reject - }) + write: closed.reject, + }); w.on('close', closed.resolve); strictEqual(w.writable, true); - w.end() + w.end(); strictEqual(w.writable, false); await closed.promise; } - } + }, }; export const writable_properties = { @@ -5794,8 +5619,7 @@ export const writable_properties = { w.uncork(); strictEqual(w.writableCorked, 0); } - - } + }, }; export const writable_null = { @@ -5804,7 +5628,7 @@ export const writable_null = { constructor(options) { super({ autoDestroy: false, - ...options + ...options, }); } _write(chunk, encoding, callback) { @@ -5814,55 +5638,59 @@ export const writable_null = { } { const m = new MyWritable({ - objectMode: true + objectMode: true, + }); + m.on('error', () => { + throw new Error('should not be called'); }); - m.on('error', () => { throw new Error('should not be called') }); throws( () => { m.write(null); }, { - code: 'ERR_STREAM_NULL_VALUES' + code: 'ERR_STREAM_NULL_VALUES', } ); } { const m = new MyWritable(); - m.on('error', () => { throw new Error('should not be called') }); + m.on('error', () => { + throw new Error('should not be called'); + }); throws( () => { m.write(false); }, { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', } ); } { // Should not throw. const m = new MyWritable({ - objectMode: true + objectMode: true, }); m.write(false, ifError); } { // Should not throw. const m = new MyWritable({ - objectMode: true + objectMode: true, }).on('error', (e) => { ifError(e || new Error('should not get here')); - }) + }); m.write(false, ifError); } - } + }, }; export const writable_needdrain_state = { async test(ctrl, env, ctx) { const transform = new Transform({ transform: _transform, - highWaterMark: 1 - }) + highWaterMark: 1, + }); const transformCalled = deferredPromise(); const writeFinished = deferredPromise(); function _transform(chunk, encoding, cb) { @@ -5870,22 +5698,16 @@ export const writable_needdrain_state = { strictEqual(transform._writableState.needDrain, true); cb(); transformCalled.resolve(); - }) + }); } strictEqual(transform._writableState.needDrain, false); - transform.write( - 'asdasd', - () => { - strictEqual(transform._writableState.needDrain, false); - writeFinished.resolve(); - } - ) + transform.write('asdasd', () => { + strictEqual(transform._writableState.needDrain, false); + writeFinished.resolve(); + }); strictEqual(transform._writableState.needDrain, true); - await Promise.all([ - transformCalled.promise, - writeFinished.promise, - ]); - } + await Promise.all([transformCalled.promise, writeFinished.promise]); + }, }; export const writable_invalid_chunk = { @@ -5893,16 +5715,18 @@ export const writable_invalid_chunk = { function testWriteType(val, objectMode, code) { const writable = new Writable({ objectMode, - write: () => {} + write: () => {}, + }); + writable.on('error', () => { + throw new Error('should not have been called'); }); - writable.on('error', () => { throw new Error('should not have been called'); }); if (code) { throws( () => { writable.write(val); }, { - code + code, } ); } else { @@ -5923,7 +5747,7 @@ export const writable_invalid_chunk = { testWriteType(0.0, true); testWriteType(undefined, true); testWriteType(null, true, 'ERR_STREAM_NULL_VALUES'); - } + }, }; export const writable_finished = { @@ -5944,24 +5768,15 @@ export const writable_finished = { }; const finishCalled = deferredPromise(); const endCalled = deferredPromise(); - writable.on( - 'finish', - () => { - strictEqual(writable.writableFinished, true); - finishCalled.resolve(); - } - ); - writable.end( - 'testing finished state', - () => { - strictEqual(writable.writableFinished, true); - endCalled.resolve(); - } - ); - await Promise.all([ - finishCalled.promise, - endCalled.promise, - ]); + writable.on('finish', () => { + strictEqual(writable.writableFinished, true); + finishCalled.resolve(); + }); + writable.end('testing finished state', () => { + strictEqual(writable.writableFinished, true); + endCalled.resolve(); + }); + await Promise.all([finishCalled.promise, endCalled.promise]); } { // Emit finish asynchronously. @@ -5969,7 +5784,7 @@ export const writable_finished = { const w = new Writable({ write(chunk, encoding, cb) { cb(); - } + }, }); w.end(); const finishCalled = deferredPromise(); @@ -5982,15 +5797,12 @@ export const writable_finished = { const w = new Writable({ write(chunk, encoding, cb) { cb(); - } - }) + }, + }); let sync = true; - w.on( - 'prefinish', - () => { - strictEqual(sync, true); - } - ) + w.on('prefinish', () => { + strictEqual(sync, true); + }); w.end(); sync = false; } @@ -6003,22 +5815,19 @@ export const writable_finished = { }, final(cb) { cb(); - } - }) + }, + }); let sync = true; - w.on( - 'prefinish', - () => { - strictEqual(sync, true); - } - ) + w.on('prefinish', () => { + strictEqual(sync, true); + }); w.end(); sync = false; } { // Call _final synchronously. - let sync = true + let sync = true; const w = new Writable({ write(chunk, encoding, cb) { cb(); @@ -6026,17 +5835,17 @@ export const writable_finished = { final: (cb) => { strictEqual(sync, true); cb(); - } + }, }); w.end(); sync = false; } - } + }, }; export const writable_finished_state = { async test(ctrl, env, ctx) { - const writable = new Writable() + const writable = new Writable(); writable._write = (chunk, encoding, cb) => { // The state finished should start in false. strictEqual(writable._writableState.finished, false); @@ -6044,25 +5853,16 @@ export const writable_finished_state = { }; const finishCalled = deferredPromise(); const endCalled = deferredPromise(); - writable.on( - 'finish', - () => { - strictEqual(writable._writableState.finished, true); - finishCalled.resolve(); - } - ); - writable.end( - 'testing finished state', - () => { - strictEqual(writable._writableState.finished, true); - endCalled.resolve(); - } - ); - await Promise.all([ - finishCalled.promise, - endCalled.promise, - ]); - } + writable.on('finish', () => { + strictEqual(writable._writableState.finished, true); + finishCalled.resolve(); + }); + writable.end('testing finished state', () => { + strictEqual(writable._writableState.finished, true); + endCalled.resolve(); + }); + await Promise.all([finishCalled.promise, endCalled.promise]); + }, }; export const writable_finish_destroyed = { @@ -6072,52 +5872,40 @@ export const writable_finish_destroyed = { const closed = deferredPromise(); const w = new Writable({ write: (chunk, encoding, cb) => { - w.on( - 'close', - () => { - cb(); - writeCalled.resolve(); - } - ); - } + w.on('close', () => { + cb(); + writeCalled.resolve(); + }); + }, }); w.on('close', closed.resolve); w.on('finish', closed.reject); w.end('asd'); w.destroy(); - await Promise.all([ - writeCalled.promise, - closed.promise, - ]); + await Promise.all([writeCalled.promise, closed.promise]); } { const writeCalled = deferredPromise(); const closed = deferredPromise(); const w = new Writable({ write: (chunk, encoding, cb) => { - w.on( - 'close', - () => { - cb(); - w.end(); - writeCalled.resolve(); - } - ); - } + w.on('close', () => { + cb(); + w.end(); + writeCalled.resolve(); + }); + }, }); w.on('finish', closed.reject); w.on('close', closed.resolve); w.write('asd'); w.destroy(); - await Promise.all([ - writeCalled.promise, - closed.promise, - ]); + await Promise.all([writeCalled.promise, closed.promise]); } { const w = new Writable({ - write() {} - }) + write() {}, + }); const closed = deferredPromise(); w.on('finish', closed.reject); w.on('close', closed.resolve); @@ -6125,7 +5913,7 @@ export const writable_finish_destroyed = { w.destroy(); await closed.promise; } - } + }, }; export const writable_final_throw = { @@ -6141,43 +5929,40 @@ export const writable_final_throw = { const errored = deferredPromise(); const foo = new Foo(); foo._write = (chunk, encoding, cb) => { - cb() + cb(); writeCalled.resolve(); }; - foo.end( - 'test', - function(err) { - strictEqual(err.message, 'fhqwhgads'); - endFinished.resolve(); - } - ); + foo.end('test', function (err) { + strictEqual(err.message, 'fhqwhgads'); + endFinished.resolve(); + }); foo.on('error', errored.resolve); await Promise.all([ writeCalled.promise, endFinished.promise, errored.promise, ]); - } + }, }; export const writable_final_destroy = { async test(ctrl, env, ctx) { const w = new Writable({ write(chunk, encoding, callback) { - callback(null) + callback(null); }, final(callback) { - queueMicrotask(callback) - } - }) + queueMicrotask(callback); + }, + }); const closed = deferredPromise(); - w.end() - w.destroy() + w.end(); + w.destroy(); w.on('prefinish', closed.reject); w.on('finish', closed.reject); w.on('close', closed.resolve); await closed.promise; - } + }, }; export const writable_final_async = { @@ -6199,12 +5984,9 @@ export const writable_final_async = { }; foo.end('test', endCalled.resolve); foo.on('error', endCalled.reject); - await Promise.all([ - endCalled.promise, - writeCalled.promise, - ]); + await Promise.all([endCalled.promise, writeCalled.promise]); } - } + }, }; export const writable_ended_state = { @@ -6218,30 +6000,24 @@ export const writable_ended_state = { strictEqual(writable.writableEnded, false); cb(); writeCalled.resolve(); - } + }; strictEqual(writable._writableState.ended, false); strictEqual(writable._writableState.writable, undefined); strictEqual(writable.writable, true); strictEqual(writable.writableEnded, false); - writable.end( - 'testing ended state', - () => { - strictEqual(writable._writableState.ended, true); - strictEqual(writable._writableState.writable, undefined); - strictEqual(writable.writable, false); - strictEqual(writable.writableEnded, true); - endCalled.resolve(); - } - ) + writable.end('testing ended state', () => { + strictEqual(writable._writableState.ended, true); + strictEqual(writable._writableState.writable, undefined); + strictEqual(writable.writable, false); + strictEqual(writable.writableEnded, true); + endCalled.resolve(); + }); strictEqual(writable._writableState.ended, true); strictEqual(writable._writableState.writable, undefined); strictEqual(writable.writable, false); strictEqual(writable.writableEnded, true); - await Promise.all([ - writeCalled.promise, - endCalled.promise, - ]); - } + await Promise.all([writeCalled.promise, endCalled.promise]); + }, }; export const writable_end_multiple = { @@ -6249,32 +6025,27 @@ export const writable_end_multiple = { const writable = new Writable(); writable._write = (chunk, encoding, cb) => { setTimeout(() => cb(), 10); - } + }; const endCalled1 = deferredPromise(); const endCalled2 = deferredPromise(); const finishCalled = deferredPromise(); writable.end('testing ended state', endCalled1.resolve); writable.end(endCalled2.resolve); - writable.on( - 'finish', - () => { - let ticked = false; - writable.end( - (err) => { - strictEqual(ticked, true); - strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED'); - finishCalled.resolve(); - } - ); - ticked = true; - } - ); + writable.on('finish', () => { + let ticked = false; + writable.end((err) => { + strictEqual(ticked, true); + strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED'); + finishCalled.resolve(); + }); + ticked = true; + }); await Promise.all([ endCalled1.promise, endCalled2.promise, finishCalled.promise, ]); - } + }, }; export const writable_end_cb_error = { @@ -6285,30 +6056,23 @@ export const writable_end_cb_error = { const _err = new Error('kaboom'); writable._write = (chunk, encoding, cb) => { queueMicrotask(() => cb(_err)); - } + }; const errored = deferredPromise(); const endCalled1 = deferredPromise(); const endCalled2 = deferredPromise(); - writable.on( - 'error', - (err) => { - strictEqual(err, _err); - errored.resolve(); - } - ) + writable.on('error', (err) => { + strictEqual(err, _err); + errored.resolve(); + }); writable.write('asd'); - writable.end( - (err) => { - strictEqual(err, _err); - endCalled1.resolve(); - } - ); - writable.end( - (err) => { - strictEqual(err, _err); - endCalled2.resolve(); - } - ); + writable.end((err) => { + strictEqual(err, _err); + endCalled1.resolve(); + }); + writable.end((err) => { + strictEqual(err, _err); + endCalled2.resolve(); + }); await Promise.all([ errored.promise, endCalled1.promise, @@ -6325,29 +6089,20 @@ export const writable_end_cb_error = { const endCalled = deferredPromise(); const errored = deferredPromise(); const finishCalled = deferredPromise(); - writable.end( - 'asd', - (err) => { - called = true; - strictEqual(err, undefined); - endCalled.resolve(); - } - ); - writable.on( - 'error', - (err) => { - strictEqual(err.message, 'kaboom'); - errored.resolve(); - } - ); - writable.on( - 'finish', - () => { - strictEqual(called, true); - writable.emit('error', new Error('kaboom')); - finishCalled.resolve(); - } - ); + writable.end('asd', (err) => { + called = true; + strictEqual(err, undefined); + endCalled.resolve(); + }); + writable.on('error', (err) => { + strictEqual(err.message, 'kaboom'); + errored.resolve(); + }); + writable.on('finish', () => { + strictEqual(called, true); + writable.emit('error', new Error('kaboom')); + finishCalled.resolve(); + }); await Promise.all([ endCalled.promise, errored.promise, @@ -6361,44 +6116,33 @@ export const writable_end_cb_error = { }, finish(callback) { queueMicrotask(callback); - } + }, }); const endCalled1 = deferredPromise(); const endCalled2 = deferredPromise(); const endCalled3 = deferredPromise(); const errored = deferredPromise(); - w.end( - 'testing ended state', - (err) => { - strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); - endCalled1.resolve(); - } - ) + w.end('testing ended state', (err) => { + strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); + endCalled1.resolve(); + }); strictEqual(w.destroyed, false); strictEqual(w.writableEnded, true); - w.end( - (err) => { - strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); - endCalled2.resolve(); - } - ) + w.end((err) => { + strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); + endCalled2.resolve(); + }); strictEqual(w.destroyed, false); strictEqual(w.writableEnded, true); - w.end( - 'end', - (err) => { - strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); - endCalled3.resolve(); - } - ) + w.end('end', (err) => { + strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); + endCalled3.resolve(); + }); strictEqual(w.destroyed, true); - w.on( - 'error', - (err) => { - strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); - errored.resolve(); - } - ) + w.on('error', (err) => { + strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); + errored.resolve(); + }); w.on('finish', errored.reject); await Promise.all([ endCalled1.promise, @@ -6407,7 +6151,7 @@ export const writable_end_cb_error = { errored.promise, ]); } - } + }, }; export const writable_destroy = { @@ -6416,7 +6160,7 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); const closed = deferredPromise(); write.on('finish', closed.reject); @@ -6430,8 +6174,8 @@ export const writable_destroy = { write(chunk, enc, cb) { this.destroy(new Error('asd')); cb(); - } - }) + }, + }); const errored = deferredPromise(); write.on('error', errored.resolve); write.on('finish', errored.reject); @@ -6442,56 +6186,44 @@ export const writable_destroy = { { const write = new Writable({ write(chunk, enc, cb) { - cb() - } + cb(); + }, }); const expected = new Error('kaboom'); const errored = deferredPromise(); const closed = deferredPromise(); write.on('finish', closed.reject); write.on('close', closed.resolve); - write.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + write.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); write.destroy(expected); strictEqual(write.destroyed, true); - await Promise.all([ - errored.promise, - closed.promise, - ]); + await Promise.all([errored.promise, closed.promise]); } { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); write._destroy = function (err, cb) { strictEqual(err, expected); cb(err); - } + }; const errored = deferredPromise(); const closed = deferredPromise(); const expected = new Error('kaboom'); write.on('finish', closed.reject); write.on('close', closed.resolve); - write.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + write.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); write.destroy(expected); strictEqual(write.destroyed, true); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const closed = deferredPromise(); @@ -6504,7 +6236,7 @@ export const writable_destroy = { strictEqual(err, expected); cb(); destroyCalled.resolve(); - } + }, }); const expected = new Error('kaboom'); write.on('finish', closed.reject); @@ -6514,16 +6246,13 @@ export const writable_destroy = { write.on('error', closed.reject); write.destroy(expected); strictEqual(write.destroyed, true); - await Promise.all([ - destroyCalled.promise, - closed.promise, - ]); + await Promise.all([destroyCalled.promise, closed.promise]); } { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); const destroyCalled = deferredPromise(); write._destroy = function (err, cb) { @@ -6539,8 +6268,8 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } - }) + }, + }); const destroyCalled = deferredPromise(); const closed = deferredPromise(); write._destroy = function (err, cb) { @@ -6549,22 +6278,19 @@ export const writable_destroy = { this.end(); cb(); destroyCalled.resolve(); - }) + }); }; write.on('finish', closed.reject); write.on('close', closed.resolve); write.destroy(); strictEqual(write.destroyed, true); - await Promise.all([ - destroyCalled.promise, - closed.promise, - ]); + await Promise.all([destroyCalled.promise, closed.promise]); } { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); const expected = new Error('kaboom'); const destroyCalled = deferredPromise(); @@ -6577,13 +6303,10 @@ export const writable_destroy = { }; write.on('close', closed.resolve); write.on('finish', closed.reject); - write.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + write.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); write.destroy(); strictEqual(write.destroyed, true); await Promise.all([ @@ -6597,27 +6320,21 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); let ticked = false; const writeFinished = deferredPromise(); const errored = deferredPromise(); - write.on( - 'close', - () => { - strictEqual(ticked, true); - writeFinished.resolve(); - } - ); - write.on( - 'error', - (err) => { - strictEqual(ticked, true); - strictEqual(err.message, 'kaboom 1'); - strictEqual(write._writableState.errorEmitted, true); - errored.resolve(); - } - ); + write.on('close', () => { + strictEqual(ticked, true); + writeFinished.resolve(); + }); + write.on('error', (err) => { + strictEqual(ticked, true); + strictEqual(err.message, 'kaboom 1'); + strictEqual(write._writableState.errorEmitted, true); + errored.resolve(); + }); const expected = new Error('kaboom 1'); write.destroy(expected); write.destroy(new Error('kaboom 2')); @@ -6625,10 +6342,7 @@ export const writable_destroy = { strictEqual(write._writableState.errorEmitted, false); strictEqual(write.destroyed, true); ticked = true; - await Promise.all([ - writeFinished.promise, - errored.promise, - ]); + await Promise.all([writeFinished.promise, errored.promise]); } { const writable = new Writable({ @@ -6637,30 +6351,26 @@ export const writable_destroy = { }, write(chunk, enc, cb) { cb(); - } + }, }); let ticked = false; const closed = deferredPromise(); const errored = deferredPromise(); - writable.on( - 'close', - () => { - writable.on('error', () => { throw new Error('should not have been called') }); - writable.destroy(new Error('hello')); - strictEqual(ticked, true); - strictEqual(writable._writableState.errorEmitted, true); - closed.resolve(); - } - ) - writable.on( - 'error', - (err) => { - strictEqual(ticked, true); - strictEqual(err.message, 'kaboom 1'); - strictEqual(writable._writableState.errorEmitted, true); - errored.resolve(); - } - ) + writable.on('close', () => { + writable.on('error', () => { + throw new Error('should not have been called'); + }); + writable.destroy(new Error('hello')); + strictEqual(ticked, true); + strictEqual(writable._writableState.errorEmitted, true); + closed.resolve(); + }); + writable.on('error', (err) => { + strictEqual(ticked, true); + strictEqual(err.message, 'kaboom 1'); + strictEqual(writable._writableState.errorEmitted, true); + errored.resolve(); + }); writable.destroy(); strictEqual(writable.destroyed, true); strictEqual(writable._writableState.errored, null); @@ -6673,22 +6383,21 @@ export const writable_destroy = { strictEqual(writable._writableState.errored, null); ticked = true; - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); write.destroyed = true; strictEqual(write.destroyed, true); // The internal destroy() mechanism should not be triggered - write.on('close', () => { throw new Error('should not have been called'); }); + write.on('close', () => { + throw new Error('should not have been called'); + }); write.destroy(); } { @@ -6706,18 +6415,15 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); write.destroy(); const expected = new Error('kaboom'); const destroyed = deferredPromise(); - write.destroy( - expected, - (err) => { - strictEqual(err, undefined); - destroyed.resolve(); - } - ); + write.destroy(expected, (err) => { + strictEqual(err, undefined); + destroyed.resolve(); + }); await destroyed.promise; } { @@ -6733,17 +6439,14 @@ export const writable_destroy = { cb(); if (++finalCounter === 2) finalCalled.resolve(); }, - autoDestroy: true - }) + autoDestroy: true, + }); write.end(); - write.once( - 'close', - () => { - write._undestroy(); - write.end(); - closed.resolve(); - } - ); + write.once('close', () => { + write._undestroy(); + write.end(); + closed.resolve(); + }); await Promise.all([ writeCalled.promise, finalCalled.promise, @@ -6755,20 +6458,17 @@ export const writable_destroy = { write.destroy(); const writeFinished = deferredPromise(); write.on('error', writeFinished.reject); - write.write( - 'asd', - function(err) { - strictEqual(err.code, 'ERR_STREAM_DESTROYED'); - writeFinished.resolve(); - } - ); + write.write('asd', function (err) { + strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + writeFinished.resolve(); + }); await writeFinished.promise; } { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); const writeFinished1 = deferredPromise(); const writeFinished2 = deferredPromise(); @@ -6778,21 +6478,15 @@ export const writable_destroy = { write.write('asd', writeFinished1.resolve); write.uncork(); write.cork(); - write.write( - 'asd', - function(err) { - strictEqual(err.code, 'ERR_STREAM_DESTROYED'); - writeFinished2.resolve(); - } - ); + write.write('asd', function (err) { + strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + writeFinished2.resolve(); + }); write.destroy(); - write.write( - 'asd', - function(err) { - strictEqual(err.code, 'ERR_STREAM_DESTROYED'); - writeFinished3.resolve(); - } - ); + write.write('asd', function (err) { + strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + writeFinished3.resolve(); + }); write.uncork(); await Promise.all([ writeFinished1.promise, @@ -6806,24 +6500,19 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(new Error('asd')); - } + }, }); const errored = deferredPromise(); - write.on( - 'error', - () => { - write.destroy(); - let ticked = false; - write.end( - (err) => { - strictEqual(ticked, true); - strictEqual(err.code, 'ERR_STREAM_DESTROYED'); - errored.resolve(); - } - ) - ticked = true; - } - ) + write.on('error', () => { + write.destroy(); + let ticked = false; + write.end((err) => { + strictEqual(ticked, true); + strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + errored.resolve(); + }); + ticked = true; + }); write.write('asd'); await errored.promise; } @@ -6833,24 +6522,19 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } + }, }); const finishCalled = deferredPromise(); - write.on( - 'finish', - () => { - write.destroy(); - let ticked = false; - write.end( - (err) => { - strictEqual(ticked, true); - strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED'); - finishCalled.resolve(); - } - ) - ticked = true; - } - ) + write.on('finish', () => { + write.destroy(); + let ticked = false; + write.end((err) => { + strictEqual(ticked, true); + strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED'); + finishCalled.resolve(); + }); + ticked = true; + }); write.end(); await finishCalled.promise; } @@ -6861,30 +6545,21 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { queueMicrotask(cb); - } - }) + }, + }); const _err = new Error('asd'); const errored = deferredPromise(); const ended = deferredPromise(); - write.once( - 'error', - (err) => { - strictEqual(err.message, 'asd'); - errored.resolve(); - } - ) - write.end( - 'asd', - (err) => { - strictEqual(err, _err); - ended.resolve(); - } - ) + write.once('error', (err) => { + strictEqual(err.message, 'asd'); + errored.resolve(); + }); + write.end('asd', (err) => { + strictEqual(err, _err); + ended.resolve(); + }); write.destroy(_err); - await Promise.all([ - errored.promise, - ended.promise, - ]); + await Promise.all([errored.promise, ended.promise]); } { // Call buffered write callback with error @@ -6894,33 +6569,24 @@ export const writable_destroy = { write(chunk, enc, cb) { queueMicrotask(() => cb(_err)); }, - autoDestroy: false + autoDestroy: false, }); write.cork(); const writeFinished1 = deferredPromise(); const writeFinished2 = deferredPromise(); const errored = deferredPromise(); - write.write( - 'asd', - (err) => { - strictEqual(err, _err); - writeFinished1.resolve(); - } - ); - write.write( - 'asd', - (err) => { - strictEqual(err, _err); - writeFinished2.resolve(); - } - ); - write.on( - 'error', - (err) => { - strictEqual(err, _err); - errored.resolve(); - } - ); + write.write('asd', (err) => { + strictEqual(err, _err); + writeFinished1.resolve(); + }); + write.write('asd', (err) => { + strictEqual(err, _err); + writeFinished2.resolve(); + }); + write.on('error', (err) => { + strictEqual(err, _err); + errored.resolve(); + }); write.uncork(); await Promise.all([ writeFinished1.promise, @@ -6937,30 +6603,21 @@ export const writable_destroy = { // `queueMicrotask()` is used on purpose to ensure the callback is called // after `queueMicrotask()` callbacks. queueMicrotask(cb); - } - }) + }, + }); const writeFinished1 = deferredPromise(); const writeFinished2 = deferredPromise(); - write.write( - 'asd', - () => { - strictEqual(state++, 0); - writeFinished1.resolve(); - } - ); - write.write( - 'asd', - (err) => { - strictEqual(err.code, 'ERR_STREAM_DESTROYED'); - strictEqual(state++, 1); - writeFinished2.resolve(); - } - ); + write.write('asd', () => { + strictEqual(state++, 0); + writeFinished1.resolve(); + }); + write.write('asd', (err) => { + strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + strictEqual(state++, 1); + writeFinished2.resolve(); + }); write.destroy(); - await Promise.all([ - writeFinished1.promise, - writeFinished2.promise, - ]); + await Promise.all([writeFinished1.promise, writeFinished2.promise]); } { const write = new Writable({ @@ -6968,16 +6625,13 @@ export const writable_destroy = { write(chunk, enc, cb) { cb(); cb(); - } - }) + }, + }); const errored = deferredPromise(); - write.on( - 'error', - () => { - ok(write._writableState.errored); - errored.resolve(); - } - ); + write.on('error', () => { + ok(write._writableState.errored); + errored.resolve(); + }); write.write('asd'); await errored.promise; } @@ -6988,18 +6642,15 @@ export const writable_destroy = { new Writable({ write(chunk, enc, cb) { cb(); - } + }, }) ); const errored = deferredPromise(); - write.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - strictEqual(write.destroyed, true); - errored.resolve(); - } - ) + write.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + strictEqual(write.destroyed, true); + errored.resolve(); + }); write.write('asd'); ac.abort(); await errored.promise; @@ -7010,17 +6661,14 @@ export const writable_destroy = { signal: ac.signal, write(chunk, enc, cb) { cb(); - } + }, }); const errored = deferredPromise(); - write.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - strictEqual(write.destroyed, true); - errored.resolve(); - } - ) + write.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + strictEqual(write.destroyed, true); + errored.resolve(); + }); write.write('asd'); ac.abort(); await errored.promise; @@ -7031,17 +6679,14 @@ export const writable_destroy = { signal, write(chunk, enc, cb) { cb(); - } + }, }); const errored = deferredPromise(); - write.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - strictEqual(write.destroyed, true); - errored.resolve(); - } - ); + write.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + strictEqual(write.destroyed, true); + errored.resolve(); + }); await errored.promise; } { @@ -7049,9 +6694,9 @@ export const writable_destroy = { const write = new Writable({ write(chunk, enc, cb) { cb(); - } - }) - const ended = deferredPromise() + }, + }); + const ended = deferredPromise(); write.end(ended.resolve); write.destroy(); write.destroy(); @@ -7060,32 +6705,24 @@ export const writable_destroy = { { // https://github.com/nodejs/node/issues/39356 const s = new Writable({ - final() {} - }) + final() {}, + }); const _err = new Error('oh no'); // Remove `callback` and it works const ended = deferredPromise(); const errored = deferredPromise(); - s.end( - (err) => { - strictEqual(err, _err); - ended.resolve(); - } - ) - s.on( - 'error', - (err) => { - strictEqual(err, _err); - errored.resolve(); - } - ) + s.end((err) => { + strictEqual(err, _err); + ended.resolve(); + }); + s.on('error', (err) => { + strictEqual(err, _err); + errored.resolve(); + }); s.destroy(_err); - await Promise.all([ - errored.promise, - ended.promise, - ]); + await Promise.all([errored.promise, ended.promise]); } - } + }, }; export const writable_decoded_encoding = { @@ -7108,9 +6745,9 @@ export const writable_decoded_encoding = { strictEqual(enc, 'buffer'); }, { - decodeStrings: true + decodeStrings: true, } - ) + ); m.write('some-text', 'utf8'); m.end(); await promises.finished(m); @@ -7123,14 +6760,14 @@ export const writable_decoded_encoding = { strictEqual(enc, 'utf8'); }, { - decodeStrings: false + decodeStrings: false, } - ) + ); m.write('some-text', 'utf8'); m.end(); await promises.finished(m); } - } + }, }; export const writable_constructor_set_methods = { @@ -7144,7 +6781,7 @@ export const writable_constructor_set_methods = { { name: 'Error', code: 'ERR_METHOD_NOT_IMPLEMENTED', - message: 'The _write() method is not implemented' + message: 'The _write() method is not implemented', } ); const writeCalled = deferredPromise(); @@ -7157,10 +6794,10 @@ export const writable_constructor_set_methods = { strictEqual(chunks.length, 2); next(); writevCalled.resolve(); - } + }; const w2 = new Writable({ write: _write, - writev: _writev + writev: _writev, }); strictEqual(w2._write, _write); strictEqual(w2._writev, _writev); @@ -7169,11 +6806,8 @@ export const writable_constructor_set_methods = { w2.write(bufferBlerg); w2.write(bufferBlerg); w2.end(); - await Promise.all([ - writeCalled.promise, - writevCalled.promise, - ]); - } + await Promise.all([writeCalled.promise, writevCalled.promise]); + }, }; export const writable_clear_buffer = { @@ -7181,7 +6815,7 @@ export const writable_clear_buffer = { class StreamWritable extends Writable { constructor() { super({ - objectMode: true + objectMode: true, }); } @@ -7198,17 +6832,17 @@ export const writable_clear_buffer = { for (let i = 1; i <= 5; i++) { const p = deferredPromise(); writePromises.push(p.promise); - testStream.write( - i, - () => { - strictEqual(testStream._writableState.bufferedRequestCount, testStream._writableState.getBuffer().length); - p.resolve(); - } - ); + testStream.write(i, () => { + strictEqual( + testStream._writableState.bufferedRequestCount, + testStream._writableState.getBuffer().length + ); + p.resolve(); + }); } - testStream.end() + testStream.end(); await Promise.all(writePromises); - } + }, }; export const writable_change_deafult_encoding = { @@ -7230,9 +6864,9 @@ export const writable_change_deafult_encoding = { strictEqual(enc, 'utf8'); }, { - decodeStrings: false + decodeStrings: false, } - ) + ); m.write('foo'); m.end(); await promises.finished(m); @@ -7244,21 +6878,21 @@ export const writable_change_deafult_encoding = { strictEqual(enc, 'ascii'); }, { - decodeStrings: false + decodeStrings: false, } ); m.setDefaultEncoding('ascii'); m.write('bar'); m.end(); await promises.finished(m); - })() + })(); // Change default encoding to invalid value. throws( () => { const m = new MyWritable((isBuffer, type, enc) => {}, { - decodeStrings: false - }) + decodeStrings: false, + }); m.setDefaultEncoding({}); m.write('bar'); m.end(); @@ -7273,22 +6907,22 @@ export const writable_change_deafult_encoding = { strictEqual(enc, 'ascii'); }, { - decodeStrings: false + decodeStrings: false, } - ) + ); m.setDefaultEncoding('AsCii'); m.write('bar'); m.end(); await promises.finished(m); - })() - } + })(); + }, }; export const writable_aborted = { async test(ctrl, env, ctx) { { const writable = new Writable({ - write() {} + write() {}, }); strictEqual(writable.writableAborted, false); writable.destroy(); @@ -7296,14 +6930,14 @@ export const writable_aborted = { } { const writable = new Writable({ - write() {} + write() {}, }); strictEqual(writable.writableAborted, false); writable.end(); writable.destroy(); strictEqual(writable.writableAborted, true); } - } + }, }; export const unshift_read_race = { @@ -7311,7 +6945,7 @@ export const unshift_read_race = { const hwm = 10; const r = Readable({ highWaterMark: hwm, - autoDestroy: false + autoDestroy: false, }); const chunks = 10; const data = Buffer.allocUnsafe(chunks * hwm + Math.ceil(hwm / 2)); @@ -7342,7 +6976,7 @@ export const unshift_read_race = { }, 1); } } - } + }; function pushError() { r.unshift(Buffer.allocUnsafe(1)); w.end(); @@ -7353,7 +6987,7 @@ export const unshift_read_race = { { code: 'ERR_STREAM_PUSH_AFTER_EOF', name: 'Error', - message: 'stream.push() after EOF' + message: 'stream.push() after EOF', } ); } @@ -7363,7 +6997,7 @@ export const unshift_read_race = { w._write = function (chunk, encoding, cb) { written.push(chunk.toString()); cb(); - } + }; r.on('end', finishCalled.reject); r.on('readable', function () { let chunk; @@ -7372,41 +7006,38 @@ export const unshift_read_race = { if (chunk.length > 4) r.unshift(Buffer.from('1234')); } }); - w.on( - 'finish', - function () { - // Each chunk should start with 1234, and then be asfdasdfasdf... - // The first got pulled out before the first unshift('1234'), so it's - // lacking that piece. - strictEqual(written[0], 'asdfasdfas'); - let asdf = 'd'; - for (let i = 1; i < written.length; i++) { - strictEqual(written[i].slice(0, 4), '1234'); - for (let j = 4; j < written[i].length; j++) { - const c = written[i].charAt(j); - strictEqual(c, asdf); - switch (asdf) { - case 'a': - asdf = 's'; - break; - case 's': - asdf = 'd'; - break; - case 'd': - asdf = 'f'; - break; - case 'f': - asdf = 'a'; - break; - } + w.on('finish', function () { + // Each chunk should start with 1234, and then be asfdasdfasdf... + // The first got pulled out before the first unshift('1234'), so it's + // lacking that piece. + strictEqual(written[0], 'asdfasdfas'); + let asdf = 'd'; + for (let i = 1; i < written.length; i++) { + strictEqual(written[i].slice(0, 4), '1234'); + for (let j = 4; j < written[i].length; j++) { + const c = written[i].charAt(j); + strictEqual(c, asdf); + switch (asdf) { + case 'a': + asdf = 's'; + break; + case 's': + asdf = 'd'; + break; + case 'd': + asdf = 'f'; + break; + case 'f': + asdf = 'a'; + break; } } - finishCalled.resolve(); } - ); + finishCalled.resolve(); + }); await finishCalled.promise; strictEqual(written.length, 18); - } + }, }; export const unshift_empty_chunk = { @@ -7416,9 +7047,9 @@ export const unshift_empty_chunk = { const chunk = Buffer.alloc(10, 'x'); r._read = function (n) { queueMicrotask(() => { - r.push(--nChunks === 0 ? null : chunk) + r.push(--nChunks === 0 ? null : chunk); }); - } + }; let readAll = false; const seen = []; r.on('readable', () => { @@ -7434,7 +7065,7 @@ export const unshift_empty_chunk = { readAll = !readAll; r.unshift(putBack); } - }) + }); const expect = [ 'xxxxxxxxxx', 'yyyyy', @@ -7453,13 +7084,13 @@ export const unshift_empty_chunk = { 'xxxxxxxxxx', 'yyyyy', 'xxxxxxxxxx', - 'yyyyy' + 'yyyyy', ]; r.on('end', () => { deepStrictEqual(seen, expect); }); await promises.finished(r); - } + }, }; export const unpipe_event = { @@ -7485,10 +7116,7 @@ export const unpipe_event = { dest.on('pipe', pipeCalled.resolve); dest.on('unpipe', unpipeCalled.resolve); src.pipe(dest); - await Promise.all([ - pipeCalled.promise, - unpipeCalled.promise, - ]); + await Promise.all([pipeCalled.promise, unpipeCalled.promise]); strictEqual(src._readableState.pipes.length, 0); } { @@ -7510,10 +7138,7 @@ export const unpipe_event = { dest.on('unpipe', unpipeCalled.resolve); src.pipe(dest); src.unpipe(dest); - await Promise.all([ - pipeCalled.promise, - unpipeCalled.promise, - ]); + await Promise.all([pipeCalled.promise, unpipeCalled.promise]); strictEqual(src._readableState.pipes.length, 0); } { @@ -7524,23 +7149,20 @@ export const unpipe_event = { dest.on('pipe', pipeCalled.resolve); dest.on('unpipe', unpipeCalled.resolve); src.pipe(dest, { - end: false - }) - await Promise.all([ - pipeCalled.promise, - unpipeCalled.promise, - ]); + end: false, + }); + await Promise.all([pipeCalled.promise, unpipeCalled.promise]); strictEqual(src._readableState.pipes.length, 0); } { const pipeCalled = deferredPromise(); - const dest = new NullWriteable() - const src = new NeverEndReadable() - dest.on('pipe', pipeCalled.resolve) - dest.on('unpipe', pipeCalled.reject) + const dest = new NullWriteable(); + const src = new NeverEndReadable(); + dest.on('pipe', pipeCalled.resolve); + dest.on('unpipe', pipeCalled.reject); src.pipe(dest, { - end: false - }) + end: false, + }); await pipeCalled.promise; strictEqual(src._readableState.pipes.length, 1); } @@ -7552,16 +7174,13 @@ export const unpipe_event = { dest.on('pipe', pipeCalled.resolve); dest.on('unpipe', unpipeCalled.resolve); src.pipe(dest, { - end: false + end: false, }); src.unpipe(dest); - await Promise.all([ - pipeCalled.promise, - unpipeCalled.promise, - ]); + await Promise.all([pipeCalled.promise, unpipeCalled.promise]); strictEqual(src._readableState.pipes.length, 0); } - } + }, }; export const uint8array = { @@ -7585,7 +7204,7 @@ export const uint8array = { } cb(); if (++writeCount === 2) writeCalled.resolve(); - } + }, }); writable.write(ABC); writable.end(DEF); @@ -7603,7 +7222,7 @@ export const uint8array = { strictEqual(encoding, 'utf8'); cb(); writeCalled.resolve(); - } + }, }); writable.end(ABC); await writeCalled.promise; @@ -7627,21 +7246,18 @@ export const uint8array = { strictEqual(chunks[1].encoding, 'buffer'); strictEqual(chunks[0].chunk + chunks[1].chunk, 'DEFGHI'); writevCalled.resolve(); - } + }, }); writable.write(ABC); writable.write(DEF); writable.end(GHI); callback(); - await Promise.all([ - writeCalled.promise, - writevCalled.promise, - ]); + await Promise.all([writeCalled.promise, writevCalled.promise]); } { // Simple Readable test. const readable = new Readable({ - read() {} + read() {}, }); readable.push(DEF); readable.unshift(ABC); @@ -7652,7 +7268,7 @@ export const uint8array = { { // Readable test, setEncoding. const readable = new Readable({ - read() {} + read() {}, }); readable.setEncoding('utf8'); readable.push(DEF); @@ -7660,23 +7276,29 @@ export const uint8array = { const out = readable.read(); strictEqual(out, 'ABCDEF'); } - } + }, }; export const transform_split_objectmode = { async test(ctrl, env, ctx) { const parser = new Transform({ - readableObjectMode: true + readableObjectMode: true, }); ok(parser._readableState.objectMode); ok(!parser._writableState.objectMode); strictEqual(parser.readableHighWaterMark, 16); strictEqual(parser.writableHighWaterMark, 16 * 1024); - strictEqual(parser.readableHighWaterMark, parser._readableState.highWaterMark); - strictEqual(parser.writableHighWaterMark, parser._writableState.highWaterMark); + strictEqual( + parser.readableHighWaterMark, + parser._readableState.highWaterMark + ); + strictEqual( + parser.writableHighWaterMark, + parser._writableState.highWaterMark + ); parser._transform = function (chunk, enc, callback) { callback(null, { - val: chunk[0] + val: chunk[0], }); }; let parsed; @@ -7686,14 +7308,20 @@ export const transform_split_objectmode = { parser.end(Buffer.from([42])); const serializer = new Transform({ - writableObjectMode: true + writableObjectMode: true, }); ok(!serializer._readableState.objectMode); ok(serializer._writableState.objectMode); strictEqual(serializer.readableHighWaterMark, 16 * 1024); strictEqual(serializer.writableHighWaterMark, 16); - strictEqual(parser.readableHighWaterMark, parser._readableState.highWaterMark); - strictEqual(parser.writableHighWaterMark, parser._writableState.highWaterMark); + strictEqual( + parser.readableHighWaterMark, + parser._readableState.highWaterMark + ); + strictEqual( + parser.writableHighWaterMark, + parser._writableState.highWaterMark + ); serializer._transform = function (obj, _, callback) { callback(null, Buffer.from([obj.val])); }; @@ -7702,12 +7330,12 @@ export const transform_split_objectmode = { serialized = chunk; }); serializer.write({ - val: 42 + val: 42, }); strictEqual(parsed.val, 42); strictEqual(serialized[0], 42); - } + }, }; export const transform_split_highwatermark = { @@ -7721,46 +7349,46 @@ export const transform_split_highwatermark = { // Test overriding defaultHwm testTransform(666, DEFAULT, { - readableHighWaterMark: 666 + readableHighWaterMark: 666, }); testTransform(DEFAULT, 777, { - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); testTransform(666, 777, { readableHighWaterMark: 666, - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); // Test highWaterMark overriding testTransform(555, 555, { highWaterMark: 555, - readableHighWaterMark: 666 + readableHighWaterMark: 666, }); testTransform(555, 555, { highWaterMark: 555, - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); testTransform(555, 555, { highWaterMark: 555, readableHighWaterMark: 666, - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); // Test undefined, null - ;[undefined, null].forEach((v) => { + [undefined, null].forEach((v) => { testTransform(DEFAULT, DEFAULT, { - readableHighWaterMark: v + readableHighWaterMark: v, }); testTransform(DEFAULT, DEFAULT, { - writableHighWaterMark: v + writableHighWaterMark: v, }); testTransform(666, DEFAULT, { highWaterMark: v, - readableHighWaterMark: 666 + readableHighWaterMark: 666, }); testTransform(DEFAULT, 777, { highWaterMark: v, - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); }); @@ -7769,7 +7397,7 @@ export const transform_split_highwatermark = { throws( () => { new Transform({ - readableHighWaterMark: NaN + readableHighWaterMark: NaN, }); }, { @@ -7780,7 +7408,7 @@ export const transform_split_highwatermark = { throws( () => { new Transform({ - writableHighWaterMark: NaN + writableHighWaterMark: NaN, }); }, { @@ -7793,27 +7421,27 @@ export const transform_split_highwatermark = { // Test non Duplex streams ignore the options { const r = new Readable({ - readableHighWaterMark: 666 + readableHighWaterMark: 666, }); strictEqual(r._readableState.highWaterMark, DEFAULT); const w = new Writable({ - writableHighWaterMark: 777 + writableHighWaterMark: 777, }); strictEqual(w._writableState.highWaterMark, DEFAULT); } - } + }, }; export const transform_objectmode_falsey_value = { async test(ctrl, env, ctx) { const src = new PassThrough({ - objectMode: true + objectMode: true, }); const tx = new PassThrough({ - objectMode: true + objectMode: true, }); const dest = new PassThrough({ - objectMode: true + objectMode: true, }); const expect = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const results = []; @@ -7821,31 +7449,24 @@ export const transform_objectmode_falsey_value = { const intervalFinished = deferredPromise(); let dataCount = 0; let intCount = 0; - dest.on( - 'data', - function (x) { - results.push(x); - if (++dataCount === expect.length) dataCalled.resolve(); - } - ) + dest.on('data', function (x) { + results.push(x); + if (++dataCount === expect.length) dataCalled.resolve(); + }); src.pipe(tx).pipe(dest); let i = -1; - const int = setInterval( - function () { - if (results.length === expect.length) { - src.end(); - clearInterval(int); - deepStrictEqual(results, expect); - } else { - src.write(i++); - } - if (++intCount === expect.length + 1) intervalFinished.resolve(); - }, 1); - await Promise.all([ - dataCalled.promise, - intervalFinished.promise, - ]); - } + const int = setInterval(function () { + if (results.length === expect.length) { + src.end(); + clearInterval(int); + deepStrictEqual(results, expect); + } else { + src.write(i++); + } + if (++intCount === expect.length + 1) intervalFinished.resolve(); + }, 1); + await Promise.all([dataCalled.promise, intervalFinished.promise]); + }, }; export const transform_hwm0 = { @@ -7855,42 +7476,28 @@ export const transform_hwm0 = { highWaterMark: 0, transform(chunk, enc, callback) { queueMicrotask(() => callback(null, chunk, enc)); - } + }, }); strictEqual(t.write(1), false); const drainCalled = deferredPromise(); const readableCalled = deferredPromise(); - t.on( - 'drain', - () => { - strictEqual(t.write(2), false); - t.end(); - drainCalled.resolve(); - } - ) - t.once( - 'readable', - () => { - strictEqual(t.read(), 1); - queueMicrotask( - () => { - strictEqual(t.read(), null); - t.once( - 'readable', - () => { - strictEqual(t.read(), 2); - readableCalled.resolve(); - } - ); - } - ); - } - ); - await Promise.all([ - drainCalled.promise, - readableCalled.promise, - ]); - } + t.on('drain', () => { + strictEqual(t.write(2), false); + t.end(); + drainCalled.resolve(); + }); + t.once('readable', () => { + strictEqual(t.read(), 1); + queueMicrotask(() => { + strictEqual(t.read(), null); + t.once('readable', () => { + strictEqual(t.read(), 2); + readableCalled.resolve(); + }); + }); + }); + await Promise.all([drainCalled.promise, readableCalled.promise]); + }, }; export const transform_flush_data = { @@ -7904,14 +7511,14 @@ export const transform_flush_data = { } const t = new Transform({ transform: _transform, - flush: _flush + flush: _flush, }); t.end(Buffer.from('blerg')); t.on('data', (data) => { strictEqual(data.toString(), expected); }); await promises.finished(t); - } + }, }; export const transform_final = { @@ -7922,7 +7529,7 @@ export const transform_final = { const flushCalled = deferredPromise(); const finishCalled = deferredPromise(); const endCalled = deferredPromise(); - const dataCalled =deferredPromise(); + const dataCalled = deferredPromise(); const endFinished = deferredPromise(); let dataCount = 0; let transformCount = 0; @@ -7959,46 +7566,34 @@ export const transform_final = { strictEqual(state, 13); done(); flushCalled.resolve(); - }) - } + }); + }, + }); + t.on('finish', function () { + state++; + // finishListener + strictEqual(state, 15); + finishCalled.resolve(); + }); + t.on('end', function () { + state++; + // end event + strictEqual(state, 16); + endCalled.resolve(); + }); + t.on('data', function (d) { + // dataListener + strictEqual(++state, d + 1); + if (++dataCount) dataCalled.resolve(); }); - t.on( - 'finish', - function () { - state++; - // finishListener - strictEqual(state, 15); - finishCalled.resolve(); - } - ); - t.on( - 'end', - function () { - state++; - // end event - strictEqual(state, 16); - endCalled.resolve(); - } - ); - t.on( - 'data', - function (d) { - // dataListener - strictEqual(++state, d + 1); - if (++dataCount) dataCalled.resolve(); - } - ); t.write(1); t.write(4); - t.end( - 7, - function () { - state++; - // endMethodCallback - strictEqual(state, 14); - endFinished.resolve(); - } - ); + t.end(7, function () { + state++; + // endMethodCallback + strictEqual(state, 14); + endFinished.resolve(); + }); await Promise.all([ transformCalled.promise, finalCalled.promise, @@ -8008,7 +7603,7 @@ export const transform_final = { dataCalled.promise, endFinished.promise, ]); - } + }, }; export const transform_final_sync = { @@ -8055,45 +7650,33 @@ export const transform_final_sync = { done(); flushCalled.resolve(); }); - } + }, + }); + t.on('finish', function () { + state++; + // finishListener + strictEqual(state, 15); + finishCalled.resolve(); + }); + t.on('end', function () { + state++; + // endEvent + strictEqual(state, 16); + endCalled.resolve(); + }); + t.on('data', function (d) { + // dataListener + strictEqual(++state, d + 1); + if (++dataCount === 3) dataCalled.resolve(); }); - t.on( - 'finish', - function () { - state++; - // finishListener - strictEqual(state, 15); - finishCalled.resolve(); - } - ); - t.on( - 'end', - function () { - state++; - // endEvent - strictEqual(state, 16); - endCalled.resolve(); - } - ); - t.on( - 'data', - function (d) { - // dataListener - strictEqual(++state, d + 1); - if (++dataCount === 3) dataCalled.resolve(); - } - ); t.write(1); t.write(4); - t.end( - 7, - function () { - state++; - // endMethodCallback - strictEqual(state, 14); - endFinished.resolve(); - } - ); + t.end(7, function () { + state++; + // endMethodCallback + strictEqual(state, 14); + endFinished.resolve(); + }); await Promise.all([ transformCalled.promise, finalCalled.promise, @@ -8103,14 +7686,14 @@ export const transform_final_sync = { dataCalled.promise, endFinished.promise, ]); - } + }, }; export const transform_destroy = { async test(ctrl, env, ctx) { { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); transform.resume(); const closed = deferredPromise(); @@ -8122,7 +7705,7 @@ export const transform_destroy = { } { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); transform.resume(); const expected = new Error('kaboom'); @@ -8131,22 +7714,16 @@ export const transform_destroy = { transform.on('end', closed.reject); transform.on('finish', closed.reject); transform.on('close', closed.resolve); - transform.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ); + transform.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); transform.destroy(expected); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); transform._destroy = function (err, cb) { strictEqual(err, expected); @@ -8157,18 +7734,12 @@ export const transform_destroy = { const errored = deferredPromise(); transform.on('finish', closed.reject); transform.on('close', closed.resolve); - transform.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + transform.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); transform.destroy(expected); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const expected = new Error('kaboom'); @@ -8180,7 +7751,7 @@ export const transform_destroy = { strictEqual(err, expected); cb(); destroyCalled.resolve(); - } + }, }); transform.resume(); transform.on('end', closed.reject); @@ -8190,14 +7761,11 @@ export const transform_destroy = { // Error is swallowed by the custom _destroy transform.on('error', closed.reject); transform.destroy(expected); - await Promise.all([ - destroyCalled.promise, - closed.promise, - ]); + await Promise.all([destroyCalled.promise, closed.promise]); } { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); const destroyCalled = deferredPromise(); transform._destroy = function (err, cb) { @@ -8210,7 +7778,7 @@ export const transform_destroy = { } { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); transform.resume(); const destroyCalled = deferredPromise(); @@ -8223,7 +7791,7 @@ export const transform_destroy = { this.end(); cb(); destroyCalled.resolve(); - }) + }); }; transform.on('finish', closed.reject); transform.on('end', closed.reject); @@ -8241,7 +7809,7 @@ export const transform_destroy = { } { const transform = new Transform({ - transform(chunk, enc, cb) {} + transform(chunk, enc, cb) {}, }); const expected = new Error('kaboom'); const destroyCalled = deferredPromise(); @@ -8255,13 +7823,10 @@ export const transform_destroy = { transform.on('close', closed.resolve); transform.on('finish', closed.reject); transform.on('end', closed.reject); - transform.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ); + transform.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); transform.destroy(); await Promise.all([ destroyCalled.promise, @@ -8269,7 +7834,7 @@ export const transform_destroy = { errored.promise, ]); } - } + }, }; export const transform_constructor_set_methods = { @@ -8282,7 +7847,7 @@ export const transform_constructor_set_methods = { { name: 'Error', code: 'ERR_METHOD_NOT_IMPLEMENTED', - message: 'The _transform() method is not implemented' + message: 'The _transform() method is not implemented', } ); const transformCalled = deferredPromise(); @@ -8303,7 +7868,7 @@ export const transform_constructor_set_methods = { const t2 = new Transform({ transform: _transform, flush: _flush, - final: _final + final: _final, }); strictEqual(t2._transform, _transform); strictEqual(t2._flush, _flush); @@ -8315,7 +7880,7 @@ export const transform_constructor_set_methods = { finalCalled.promise, flushCalled.promise, ]); - } + }, }; export const transform_callback_twice = { @@ -8324,19 +7889,16 @@ export const transform_callback_twice = { transform(chunk, enc, cb) { cb(); cb(); - } + }, }); const errored = deferredPromise(); - stream.on( - 'error', - function (err) { - strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); - errored.resolve(); - } - ) + stream.on('error', function (err) { + strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK'); + errored.resolve(); + }); stream.write('foo'); await errored.promise; - } + }, }; export const toarray = { @@ -8350,7 +7912,7 @@ export const toarray = { [1, 2, 3], Array(100) .fill() - .map((_, i) => i) + .map((_, i) => i), ]; for (const test of tests) { const stream = Readable.from(test); @@ -8365,7 +7927,7 @@ export const toarray = { const firstBuffer = Buffer.from([1, 2, 3]); const secondBuffer = Buffer.from([4, 5, 6]); const stream = Readable.from([firstBuffer, secondBuffer], { - objectMode: false + objectMode: false, }); const result = await stream.toArray(); strictEqual(Array.isArray(result), true); @@ -8381,7 +7943,7 @@ export const toarray = { [1, 2, 3], Array(100) .fill() - .map((_, i) => i) + .map((_, i) => i), ]; for (const test of tests) { const stream = Readable.from(test).map((x) => Promise.resolve(x)); @@ -8396,22 +7958,22 @@ export const toarray = { let stream; queueMicrotask(() => ac.abort()); await rejects( - async () => { - stream = Readable.from([1, 2, 3]).map(async (x) => { - if (x === 3) { - await new Promise(() => {}); // Explicitly do not pass signal here - } + async () => { + stream = Readable.from([1, 2, 3]).map(async (x) => { + if (x === 3) { + await new Promise(() => {}); // Explicitly do not pass signal here + } - return Promise.resolve(x); - }) - await stream.toArray({ - signal: ac.signal - }); - }, - { - name: 'AbortError' - } - ); + return Promise.resolve(x); + }); + await stream.toArray({ + signal: ac.signal, + }); + }, + { + name: 'AbortError', + } + ); // Only stops toArray, does not destroy the stream ok(stream.destroyed, false); @@ -8424,15 +7986,15 @@ export const toarray = { { // Error cases await rejects(async () => { - await Readable.from([1]).toArray(1) - }, /ERR_INVALID_ARG_TYPE/); + await Readable.from([1]).toArray(1); + }, /ERR_INVALID_ARG_TYPE/); await rejects(async () => { - await Readable.from([1]).toArray({ - signal: true - }) - }, /ERR_INVALID_ARG_TYPE/); + await Readable.from([1]).toArray({ + signal: true, + }); + }, /ERR_INVALID_ARG_TYPE/); } - } + }, }; export const some_find_every = { @@ -8547,7 +8109,7 @@ export const some_find_every = { return true; }, { concurrency: 2 } - ) + ); strictEqual(found, 1); } @@ -8558,22 +8120,26 @@ export const some_find_every = { const ac = new AbortController(); queueMicrotask(() => ac.abort()); await rejects( - Readable.from([1, 2, 3])[op](() => new Promise(() => {}), { signal: ac.signal }), - { - name: 'AbortError' - }, - `${op} should abort correctly with sync abort` - ); + Readable.from([1, 2, 3])[op](() => new Promise(() => {}), { + signal: ac.signal, + }), + { + name: 'AbortError', + }, + `${op} should abort correctly with sync abort` + ); } { // Support for pre-aborted AbortSignal await rejects( - Readable.from([1, 2, 3])[op](() => new Promise(() => {}), { signal: AbortSignal.abort() }), - { - name: 'AbortError' - }, - `${op} should abort with pre-aborted abort controller` - ); + Readable.from([1, 2, 3])[op](() => new Promise(() => {}), { + signal: AbortSignal.abort(), + }), + { + name: 'AbortError', + }, + `${op} should abort with pre-aborted abort controller` + ); } } } @@ -8581,37 +8147,37 @@ export const some_find_every = { // Error cases for (const op of ['some', 'every', 'find']) { await rejects( - async () => { - await Readable.from([1])[op](1); - }, - /ERR_INVALID_ARG_TYPE/, - `${op} should throw for invalid function` - ); + async () => { + await Readable.from([1])[op](1); + }, + /ERR_INVALID_ARG_TYPE/, + `${op} should throw for invalid function` + ); await rejects( - async () => { - await Readable.from([1])[op]((x) => x, { - concurrency: 'Foo' - }); - }, - /RangeError/, - `${op} should throw for invalid concurrency` - ); + async () => { + await Readable.from([1])[op]((x) => x, { + concurrency: 'Foo', + }); + }, + /RangeError/, + `${op} should throw for invalid concurrency` + ); await rejects( - async () => { - await Readable.from([1])[op]((x) => x, 1); - }, - /ERR_INVALID_ARG_TYPE/, - `${op} should throw for invalid concurrency` - ); + async () => { + await Readable.from([1])[op]((x) => x, 1); + }, + /ERR_INVALID_ARG_TYPE/, + `${op} should throw for invalid concurrency` + ); await rejects( - async () => { - await Readable.from([1])[op]((x) => x, { - signal: true - }); - }, - /ERR_INVALID_ARG_TYPE/, - `${op} should throw for invalid signal` - ); + async () => { + await Readable.from([1])[op]((x) => x, { + signal: true, + }); + }, + /ERR_INVALID_ARG_TYPE/, + `${op} should throw for invalid signal` + ); } } { @@ -8620,13 +8186,13 @@ export const some_find_every = { Object.defineProperty(stream, 'map', { value: () => { throw new Error('should not be called'); - } + }, }); // Check that map isn't getting called. stream[op](() => {}); } } - } + }, }; export const reduce = { @@ -8644,7 +8210,7 @@ export const reduce = { [[...Array(100).keys()], sum, 0], [['a', 'b', 'c'], sum, ''], [[1, 2], sum], - [[1, 2, 3], (x, y) => y] + [[1, 2, 3], (x, y) => y], ]; for (const [values, fn, initial] of tests) { const streamReduce = await Readable.from(values).reduce(fn, initial); @@ -8665,120 +8231,126 @@ export const reduce = { { // Works with an async reducer, with or without initial value await (async () => { - const six = await Readable.from([1, 2, 3]).reduce(async (p, c) => p + c, 0); + const six = await Readable.from([1, 2, 3]).reduce( + async (p, c) => p + c, + 0 + ); strictEqual(six, 6); })(); await (async () => { - const six = await Readable.from([1, 2, 3]).reduce(async (p, c) => p + c); + const six = await Readable.from([1, 2, 3]).reduce( + async (p, c) => p + c + ); strictEqual(six, 6); })(); } { // Works lazily await rejects( - Readable.from([1, 2, 3, 4, 5, 6]) - .map( - (x) => { - return x - } - ) // Two consumed and one buffered by `map` due to default concurrency - .reduce(async (p, c) => { - if (p === 1) { - throw new Error('boom'); - } - return c; - }, 0), - /boom/ - ); + Readable.from([1, 2, 3, 4, 5, 6]) + .map((x) => { + return x; + }) // Two consumed and one buffered by `map` due to default concurrency + .reduce(async (p, c) => { + if (p === 1) { + throw new Error('boom'); + } + return c; + }, 0), + /boom/ + ); } { // Support for AbortSignal const ac = new AbortController(); queueMicrotask(() => ac.abort()); - await rejects( - async () => { - await Readable.from([1, 2, 3]).reduce( - async (p, c) => { - if (c === 3) { - await new Promise(() => {}); // Explicitly do not pass signal here - } - - return Promise.resolve(); - }, - 0, - { - signal: ac.signal - } - ); - }, - { - name: 'AbortError' - } - ); + await rejects( + async () => { + await Readable.from([1, 2, 3]).reduce( + async (p, c) => { + if (c === 3) { + await new Promise(() => {}); // Explicitly do not pass signal here + } + + return Promise.resolve(); + }, + 0, + { + signal: ac.signal, + } + ); + }, + { + name: 'AbortError', + } + ); } { // Support for AbortSignal - pre aborted const stream = Readable.from([1, 2, 3]); await rejects( - async () => { - await stream.reduce( - async (p, c) => { - if (c === 3) { - await new Promise(() => {}) // Explicitly do not pass signal here - } - - return Promise.resolve() - }, - 0, - { - signal: AbortSignal.abort() + async () => { + await stream.reduce( + async (p, c) => { + if (c === 3) { + await new Promise(() => {}); // Explicitly do not pass signal here } - ) - }, - { - name: 'AbortError' - } - ); + + return Promise.resolve(); + }, + 0, + { + signal: AbortSignal.abort(), + } + ); + }, + { + name: 'AbortError', + } + ); strictEqual(stream.destroyed, true); } { // Support for AbortSignal - deep - const stream = Readable.from([1, 2, 3]) + const stream = Readable.from([1, 2, 3]); await rejects( - async () => { - await stream.reduce( - async (p, c, { signal }) => { - signal.addEventListener('abort', () => {}, { - once: true - }) - if (c === 3) { - await new Promise(() => {}) // Explicitly do not pass signal here - } - - return Promise.resolve() - }, - 0, - { - signal: AbortSignal.abort() + async () => { + await stream.reduce( + async (p, c, { signal }) => { + signal.addEventListener('abort', () => {}, { + once: true, + }); + if (c === 3) { + await new Promise(() => {}); // Explicitly do not pass signal here } - ) - }, - { - name: 'AbortError' - } - ); + + return Promise.resolve(); + }, + 0, + { + signal: AbortSignal.abort(), + } + ); + }, + { + name: 'AbortError', + } + ); strictEqual(stream.destroyed, true); } { // Error cases await rejects(() => Readable.from([]).reduce(1), /TypeError/); await rejects(() => Readable.from([]).reduce('5'), /TypeError/); - await rejects(() => Readable.from([]).reduce((x, y) => x + y, 0, 1), /ERR_INVALID_ARG_TYPE/); + await rejects( + () => Readable.from([]).reduce((x, y) => x + y, 0, 1), + /ERR_INVALID_ARG_TYPE/ + ); await rejects( () => Readable.from([]).reduce((x, y) => x + y, 0, { - signal: true + signal: true, }), /ERR_INVALID_ARG_TYPE/ ); @@ -8788,49 +8360,40 @@ export const reduce = { const result = Readable.from([1, 2, 3, 4, 5]).reduce(sum, 0); ok(result instanceof Promise); } - } + }, }; export const readablelistening_state = { async test(ctrl, env, ctx) { const r = new Readable({ - read: () => {} + read: () => {}, }); // readableListening state should start in `false`. strictEqual(r._readableState.readableListening, false); const readableCalled = deferredPromise(); const dataCalled = deferredPromise(); - r.on( - 'readable', - () => { - // Inside the readable event this state should be true. - strictEqual(r._readableState.readableListening, true); - readableCalled.resolve(); - } - ) - r.push(Buffer.from('Testing readableListening state')) + r.on('readable', () => { + // Inside the readable event this state should be true. + strictEqual(r._readableState.readableListening, true); + readableCalled.resolve(); + }); + r.push(Buffer.from('Testing readableListening state')); const r2 = new Readable({ - read: () => {} + read: () => {}, }); // readableListening state should start in `false`. strictEqual(r2._readableState.readableListening, false); - r2.on( - 'data', - (chunk) => { - // readableListening should be false because we don't have - // a `readable` listener - strictEqual(r2._readableState.readableListening, false); - dataCalled.resolve(); - } - ) - r2.push(Buffer.from('Testing readableListening state')) - await Promise.all([ - readableCalled.promise, - dataCalled.promise, - ]); - } + r2.on('data', (chunk) => { + // readableListening should be false because we don't have + // a `readable` listener + strictEqual(r2._readableState.readableListening, false); + dataCalled.resolve(); + }); + r2.push(Buffer.from('Testing readableListening state')); + await Promise.all([readableCalled.promise, dataCalled.promise]); + }, }; export const readable_with_unimplemented_read = { @@ -8839,19 +8402,13 @@ export const readable_with_unimplemented_read = { readable.read(); const errored = deferredPromise(); const closed = deferredPromise(); - readable.on( - 'error', - function(err) { - strictEqual(err.code, 'ERR_METHOD_NOT_IMPLEMENTED'); - errored.resolve(); - } - ); + readable.on('error', function (err) { + strictEqual(err.code, 'ERR_METHOD_NOT_IMPLEMENTED'); + errored.resolve(); + }); readable.on('close', closed.resolve); - await Promise.all([ - errored.promise, - closed.promise, - ]); - } + await Promise.all([errored.promise, closed.promise]); + }, }; export const readable_unshift = { @@ -8859,38 +8416,32 @@ export const readable_unshift = { { // Check that strings are saved as Buffer const readable = new Readable({ - read() {} + read() {}, }); const string = 'abc'; const dataCalled = deferredPromise(); - readable.on( - 'data', - (chunk) => { - ok(Buffer.isBuffer(chunk)); - strictEqual(chunk.toString('utf8'), string); - dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + ok(Buffer.isBuffer(chunk)); + strictEqual(chunk.toString('utf8'), string); + dataCalled.resolve(); + }); readable.unshift(string); await dataCalled.promise; } { // Check that data goes at the beginning const readable = new Readable({ - read() {} + read() {}, }); const unshift = 'front'; const push = 'back'; const expected = [unshift, push]; const dataCalled = deferredPromise(); let dataCount = 0; - readable.on( - 'data', - (chunk) => { - strictEqual(chunk.toString('utf8'), expected.shift()); - if (++dataCount === 2) dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + strictEqual(chunk.toString('utf8'), expected.shift()); + if (++dataCount === 2) dataCalled.resolve(); + }); readable.push(push); readable.unshift(unshift); await dataCalled.promise; @@ -8898,18 +8449,15 @@ export const readable_unshift = { { // Check that buffer is saved with correct encoding const readable = new Readable({ - read() {} + read() {}, }); const encoding = 'base64'; const string = Buffer.from('abc').toString(encoding); const dataCalled = deferredPromise(); - readable.on( - 'data', - (chunk) => { - strictEqual(chunk.toString(encoding), string); - dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + strictEqual(chunk.toString(encoding), string); + dataCalled.resolve(); + }); readable.unshift(string, encoding); await dataCalled.promise; } @@ -8921,35 +8469,35 @@ export const readable_unshift = { const encodings = ['utf8', 'binary', 'hex', 'base64']; const expected = []; let dataCount = 0; - readable.on( - 'data', - (chunk) => { - const { encoding, string } = expected.pop(); - strictEqual(chunk.toString(encoding), string); - if (++dataCount === encodings.length) dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + const { encoding, string } = expected.pop(); + strictEqual(chunk.toString(encoding), string); + if (++dataCount === encodings.length) dataCalled.resolve(); + }); for (const encoding of encodings) { const string = 'abc'; // If encoding is the same as the state.encoding the string is // saved as is - const expect = encoding !== streamEncoding ? Buffer.from(string, encoding).toString(streamEncoding) : string; + const expect = + encoding !== streamEncoding + ? Buffer.from(string, encoding).toString(streamEncoding) + : string; expected.push({ encoding, - string: expect + string: expect, }); readable.unshift(string, encoding); } } const r1 = new Readable({ - read() {} + read() {}, }); r1.setEncoding(streamEncoding); checkEncoding(r1); const r2 = new Readable({ read() {}, - encoding: streamEncoding + encoding: streamEncoding, }); checkEncoding(r2); await dataCalled.promise; @@ -8962,24 +8510,21 @@ export const readable_unshift = { function checkEncoding(readable) { const string = 'abc'; let dataCount = 0; - readable.on( - 'data', - (chunk) => { - strictEqual(chunk, Buffer.from(string).toString(encoding)); - if (++dataCount === 2) dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + strictEqual(chunk, Buffer.from(string).toString(encoding)); + if (++dataCount === 2) dataCalled.resolve(); + }); readable.push(string); readable.unshift(string); } const r1 = new Readable({ - read() {} + read() {}, }); r1.setEncoding(encoding); checkEncoding(r1); const r2 = new Readable({ read() {}, - encoding + encoding, }); checkEncoding(r2); await dataCalled.promise; @@ -8988,18 +8533,15 @@ export const readable_unshift = { // Check that ObjectMode works const readable = new Readable({ objectMode: true, - read() {} + read() {}, }); const chunks = ['a', 1, {}, []]; const dataCalled = deferredPromise(); let dataCount = 0; - readable.on( - 'data', - (chunk) => { - strictEqual(chunk, chunks.pop()); - if (++dataCount === chunks.length) dataCalled.resolve(); - } - ); + readable.on('data', (chunk) => { + strictEqual(chunk, chunks.pop()); + if (++dataCount === chunks.length) dataCalled.resolve(); + }); for (const chunk of chunks) { readable.unshift(chunk); } @@ -9011,7 +8553,7 @@ export const readable_unshift = { class ArrayReader extends Readable { constructor(opt) { super({ - highWaterMark + highWaterMark, }); // The error happened only when pushing above hwm this.buffer = new Array(highWaterMark * 2).fill(0).map(String); @@ -9042,18 +8584,18 @@ export const readable_unshift = { stream.once('readable', onRead); await readCalled.promise; } - } + }, }; export const readable_setencoding_null = { async test(ctrl, env, ctx) { const readable = new Readable({ - encoding: 'hex' + encoding: 'hex', }); strictEqual(readable._readableState.encoding, 'hex'); readable.setEncoding(null); strictEqual(readable._readableState.encoding, 'utf8'); - } + }, }; export const readable_setencoding_existing_buffers = { @@ -9061,7 +8603,7 @@ export const readable_setencoding_existing_buffers = { { // Call .setEncoding() while there are bytes already in the buffer. const r = new Readable({ - read() {} + read() {}, }); r.push(Buffer.from('a')); r.push(Buffer.from('b')); @@ -9076,7 +8618,7 @@ export const readable_setencoding_existing_buffers = { // Call .setEncoding() while the buffer contains a complete, // but chunked character. const r = new Readable({ - read() {} + read() {}, }); r.push(Buffer.from([0xf0])); r.push(Buffer.from([0x9f])); @@ -9093,7 +8635,7 @@ export const readable_setencoding_existing_buffers = { // Call .setEncoding() while the buffer contains an incomplete character, // and finish the character later. const r = new Readable({ - read() {} + read() {}, }); r.push(Buffer.from([0xf0])); r.push(Buffer.from([0x9f])); @@ -9106,7 +8648,7 @@ export const readable_setencoding_existing_buffers = { deepStrictEqual(chunks, ['🎉']); }); } - } + }, }; export const readable_resumescheduled = { @@ -9114,7 +8656,7 @@ export const readable_resumescheduled = { { // pipe() test case const r = new Readable({ - read() {} + read() {}, }); const w = new Writable(); @@ -9124,16 +8666,14 @@ export const readable_resumescheduled = { // Calling pipe() should change the state value = true. r.pipe(w); strictEqual(r._readableState.resumeScheduled, true); - queueMicrotask( - () => { - strictEqual(r._readableState.resumeScheduled, false); - } - ); + queueMicrotask(() => { + strictEqual(r._readableState.resumeScheduled, false); + }); } { // 'data' listener test case const r = new Readable({ - read() {} + read() {}, }); // resumeScheduled should start = `false`. @@ -9141,23 +8681,18 @@ export const readable_resumescheduled = { r.push(Buffer.from([1, 2, 3])); // Adding 'data' listener should change the state value - r.on( - 'data', - () => { - strictEqual(r._readableState.resumeScheduled, false); - } - ); + r.on('data', () => { + strictEqual(r._readableState.resumeScheduled, false); + }); strictEqual(r._readableState.resumeScheduled, true); - queueMicrotask( - () => { - strictEqual(r._readableState.resumeScheduled, false); - } - ); + queueMicrotask(() => { + strictEqual(r._readableState.resumeScheduled, false); + }); } { // resume() test case const r = new Readable({ - read() {} + read() {}, }); // resumeScheduled should start = `false`. @@ -9166,27 +8701,24 @@ export const readable_resumescheduled = { // Calling resume() should change the state value. r.resume(); strictEqual(r._readableState.resumeScheduled, true); - r.on( - 'resume', - () => { - // The state value should be `false` again - strictEqual(r._readableState.resumeScheduled, false); - } - ); - queueMicrotask( - () => { - strictEqual(r._readableState.resumeScheduled, false); - } - ); + r.on('resume', () => { + // The state value should be `false` again + strictEqual(r._readableState.resumeScheduled, false); + }); + queueMicrotask(() => { + strictEqual(r._readableState.resumeScheduled, false); + }); } - } + }, }; export const readable_resume_hwm = { async test(ctrl, env, ctx) { const readable = new Readable({ - read: () => { throw new Error('should not be called'); }, - highWaterMark: 100 + read: () => { + throw new Error('should not be called'); + }, + highWaterMark: 100, }); // Fill up the internal buffer so that we definitely exceed the HWM: @@ -9197,22 +8729,19 @@ export const readable_resume_hwm = { // be a valid reason to call ._read(). readable.resume(); const dataCalled = deferredPromise(); - readable.once( - 'data', - () => { - readable.pause(); - dataCalled.resolve(); - } - ); + readable.once('data', () => { + readable.pause(); + dataCalled.resolve(); + }); await dataCalled.promise; - } + }, }; export const readable_reading_readingmore = { async test(ctrl, env, ctx) { { const readable = new Readable({ - read(size) {} + read(size) {}, }); const state = readable._readableState; @@ -9224,18 +8753,15 @@ export const readable_reading_readingmore = { const dataCalled = deferredPromise(); const readableCalled = deferredPromise(); const ended = deferredPromise(); - readable.on( - 'data', - (data) => { - // While in a flowing state with a 'readable' listener - // we should not be reading more - if (readable.readableFlowing) strictEqual(state.readingMore, true); - - // Reading as long as we've not ended - strictEqual(state.reading, !state.ended); - if (++dataCount === 2) dataCalled.resolve(); - } - ); + readable.on('data', (data) => { + // While in a flowing state with a 'readable' listener + // we should not be reading more + if (readable.readableFlowing) strictEqual(state.readingMore, true); + + // Reading as long as we've not ended + strictEqual(state.reading, !state.ended); + if (++dataCount === 2) dataCalled.resolve(); + }); function onStreamEnd() { // End of stream; state.reading is false // And so should be readingMore. @@ -9244,24 +8770,21 @@ export const readable_reading_readingmore = { ended.resolve(); } const expectedReadingMore = [true, true, false]; - readable.on( - 'readable', - () => { - // There is only one readingMore scheduled from on('data'), - // after which everything is governed by the .read() call - strictEqual(state.readingMore, expectedReadingMore.shift()); - - // If the stream has ended, we shouldn't be reading - strictEqual(state.ended, !state.reading); - - // Consume all the data - while (readable.read() !== null); - if (expectedReadingMore.length === 0) - // Reached end of stream - queueMicrotask(onStreamEnd); - if (++readableCount === 3) readableCalled.resolve(); - } - ); + readable.on('readable', () => { + // There is only one readingMore scheduled from on('data'), + // after which everything is governed by the .read() call + strictEqual(state.readingMore, expectedReadingMore.shift()); + + // If the stream has ended, we shouldn't be reading + strictEqual(state.ended, !state.reading); + + // Consume all the data + while (readable.read() !== null); + if (expectedReadingMore.length === 0) + // Reached end of stream + queueMicrotask(onStreamEnd); + if (++readableCount === 3) readableCalled.resolve(); + }); readable.on('end', onStreamEnd); readable.push('pushed'); readable.read(6); @@ -9283,7 +8806,7 @@ export const readable_reading_readingmore = { } { const readable = new Readable({ - read(size) {} + read(size) {}, }); const state = readable._readableState; @@ -9293,18 +8816,15 @@ export const readable_reading_readingmore = { let dataCount = 0; const dataCalled = deferredPromise(); const ended = deferredPromise(); - readable.on( - 'data', - (data) => { - // While in a flowing state without a 'readable' listener - // we should be reading more - if (readable.readableFlowing) strictEqual(state.readingMore, true); - - // Reading as long as we've not ended - strictEqual(state.reading, !state.ended); - if (++dataCount === 2) dataCalled.resolve(); - } - ) + readable.on('data', (data) => { + // While in a flowing state without a 'readable' listener + // we should be reading more + if (readable.readableFlowing) strictEqual(state.readingMore, true); + + // Reading as long as we've not ended + strictEqual(state.reading, !state.ended); + if (++dataCount === 2) dataCalled.resolve(); + }); function onStreamEnd() { // End of stream; state.reading is false // And so should be readingMore. @@ -9331,14 +8851,11 @@ export const readable_reading_readingmore = { // end readable.push(null); - await Promise.all([ - dataCalled.promise, - ended.promise, - ]); + await Promise.all([dataCalled.promise, ended.promise]); } { const readable = new Readable({ - read(size) {} + read(size) {}, }); const state = readable._readableState; @@ -9350,14 +8867,11 @@ export const readable_reading_readingmore = { strictEqual(state.reading, false); strictEqual(state.readingMore, false); readable.on('readable', fail); - readable.on( - 'data', - (data) => { - // Reading as long as we've not ended - strictEqual(state.reading, !state.ended); - if (++dataCount === 2) dataCalled.resolve(); - } - ); + readable.on('data', (data) => { + // Reading as long as we've not ended + strictEqual(state.reading, !state.ended); + if (++dataCount === 2) dataCalled.resolve(); + }); readable.removeListener('readable', fail); function onStreamEnd() { // End of stream; state.reading is false @@ -9365,7 +8879,7 @@ export const readable_reading_readingmore = { strictEqual(state.readingMore, false); strictEqual(state.reading, false); ended.resolve(); - }; + } readable.on('end', onStreamEnd); readable.push('pushed'); @@ -9392,19 +8906,16 @@ export const readable_reading_readingmore = { readable.push(null); }); - await Promise.all([ - dataCalled.promise, - ended.promise, - ]); + await Promise.all([dataCalled.promise, ended.promise]); } - } + }, }; export const readable_readable = { async test(ctrl, env, ctx) { { const r = new Readable({ - read() {} + read() {}, }); strictEqual(r.readable, true); r.destroy(); @@ -9412,7 +8923,7 @@ export const readable_readable = { } { const r = new Readable({ - read() {} + read() {}, }); strictEqual(r.readable, true); r.on('end', fail); @@ -9421,13 +8932,10 @@ export const readable_readable = { strictEqual(r.readable, true); r.off('end', fail); const ended = deferredPromise(); - r.on( - 'end', - () => { - strictEqual(r.readable, false); - ended.resolve(); - } - ); + r.on('end', () => { + strictEqual(r.readable, false); + ended.resolve(); + }); } { const readCalled = deferredPromise(); @@ -9438,23 +8946,17 @@ export const readable_readable = { r.destroy(new Error()); strictEqual(r.readable, false); readCalled.resolve(); - }) - } - }) + }); + }, + }); r.resume(); - r.on( - 'error', - () => { - strictEqual(r.readable, false); - errored.resolve(); - } - ); - await Promise.all([ - readCalled.promise, - errored.promise, - ]); + r.on('error', () => { + strictEqual(r.readable, false); + errored.resolve(); + }); + await Promise.all([readCalled.promise, errored.promise]); } - } + }, }; export const readable_readable_then_resume = { @@ -9470,7 +8972,7 @@ export const readable_readable_then_resume = { return; } this.push(null); - } + }, }) ); async function check(s) { @@ -9482,7 +8984,7 @@ export const readable_readable_then_resume = { s.resume(); await ended.promise; } - } + }, }; export const readable_pause_and_resume = { @@ -9495,8 +8997,8 @@ export const readable_pause_and_resume = { if (ticks-- > 0) return queueMicrotask(() => rs.push({})); rs.push({}); rs.push(null); - } - }) + }, + }); const ended = deferredPromise(); const ondataCalled = deferredPromise(); rs.on('end', ended.resolve); @@ -9513,20 +9015,17 @@ export const readable_pause_and_resume = { readAndPause(); rs.resume(); ondataCalled.resolve(); - }) + }); }; // Only call ondata once rs.on('data', ondata); - await Promise.all([ - ended.promise, - ondataCalled.promise, - ]); + await Promise.all([ended.promise, ondataCalled.promise]); } { const readable = new Readable({ - read() {} + read() {}, }); - function read() {}; + function read() {} readable.setEncoding('utf8'); readable.on('readable', read); readable.removeListener('readable', read); @@ -9542,23 +9041,20 @@ export const readable_pause_and_resume = { while (target3.write(chunk)); source3.pipe(target3); const drainCalled = deferredPromise(); - target3.on( - 'drain', - () => { - ok(!source3.isPaused()); - drainCalled.resolve(); - } - ); + target3.on('drain', () => { + ok(!source3.isPaused()); + drainCalled.resolve(); + }); target3.on('data', () => {}); await drainCalled.promise; } - } + }, }; export const readable_object_multi_push_async = { async test(ctrl, env, ctx) { - const MAX = 42 - const BATCH = 10 + const MAX = 42; + const BATCH = 10; { const readCalled = deferredPromise(); const ended = deferredPromise(); @@ -9577,10 +9073,9 @@ export const readable_object_multi_push_async = { } data.forEach((d) => this.push(d)); }); - if (++readCount === Math.floor(MAX / BATCH) + 2) - readCalled.resolve(); - } - }) + if (++readCount === Math.floor(MAX / BATCH) + 2) readCalled.resolve(); + }, + }); let i = 0; function fetchData(cb) { if (i > MAX) { @@ -9598,17 +9093,11 @@ export const readable_object_multi_push_async = { let data; while ((data = readable.read()) !== null) {} }); - readable.on( - 'end', - () => { - strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); - ended.resolve(); - } - ); - await Promise.all([ - readCalled.promise, - ended.promise, - ]); + readable.on('end', () => { + strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); + ended.resolve(); + }); + await Promise.all([readCalled.promise, ended.promise]); } { const readCalled = deferredPromise(); @@ -9628,9 +9117,8 @@ export const readable_object_multi_push_async = { } data.forEach((d) => this.push(d)); }); - if (++readCount === Math.floor(MAX / BATCH) + 2) - readCalled.resolve(); - } + if (++readCount === Math.floor(MAX / BATCH) + 2) readCalled.resolve(); + }, }); let i = 0; function fetchData(cb) { @@ -9646,17 +9134,11 @@ export const readable_object_multi_push_async = { } } readable.on('data', (data) => {}); - readable.on( - 'end', - () => { - strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); - ended.resolve(); - } - ); - await Promise.all([ - readCalled.promise, - ended.promise, - ]); + readable.on('end', () => { + strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); + ended.resolve(); + }); + await Promise.all([readCalled.promise, ended.promise]); } { const readCalled = deferredPromise(); @@ -9675,9 +9157,8 @@ export const readable_object_multi_push_async = { this.push(null); } }); - if (++readCount === Math.floor(MAX / BATCH) + 1) - readCalled.resolve(); - } + if (++readCount === Math.floor(MAX / BATCH) + 1) readCalled.resolve(); + }, }); let i = 0; function fetchData(cb) { @@ -9687,19 +9168,13 @@ export const readable_object_multi_push_async = { array.push(i); } setTimeout(cb, 10, null, array); - } - readable.on('data', (data) => {}); - readable.on( - 'end', - () => { - strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); - ended.resolve(); - } - ); - await Promise.all([ - readCalled.promise, - ended.promise, - ]); + } + readable.on('data', (data) => {}); + readable.on('end', () => { + strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); + ended.resolve(); + }); + await Promise.all([readCalled.promise, ended.promise]); } { const ended = deferredPromise(); @@ -9713,13 +9188,10 @@ export const readable_object_multi_push_async = { queueMicrotask(() => { nextTickPassed = true; }); - readable.on( - 'end', - () => { - strictEqual(nextTickPassed, true); - ended.resolve(); - } - ); + readable.on('end', () => { + strictEqual(nextTickPassed, true); + ended.resolve(); + }); await ended.promise; } { @@ -9734,13 +9206,10 @@ export const readable_object_multi_push_async = { queueMicrotask(() => { readable.push('aaa'); readable.push(null); - }) - await Promise.all([ - readCalled.promise, - ended.promise, - ]); + }); + await Promise.all([readCalled.promise, ended.promise]); } - } + }, }; export const readable_no_unneeded_readable = { @@ -9759,9 +9228,9 @@ export const readable_no_unneeded_readable = { wrapper.push(data); } // else: the end event should fire - }) - } - }) + }); + }, + }); r.once('end', function () { wrapper.push(null); @@ -9773,7 +9242,7 @@ export const readable_no_unneeded_readable = { } { const source = new Readable({ - read: () => {} + read: () => {}, }); source.push('foo'); source.push('bar'); @@ -9794,11 +9263,11 @@ export const readable_no_unneeded_readable = { // asynchronous call queueMicrotask(() => r.push(null)); } - } - }) + }, + }); await test(r); } - } + }, }; export const readable_next_no_null = { @@ -9808,55 +9277,43 @@ export const readable_next_no_null = { } const stream = Readable.from(generate()); const errored = deferredPromise(); - stream.on( - 'error', - function(err) { - strictEqual(err.code, 'ERR_STREAM_NULL_VALUES'); - errored.resolve(); - } - ) + stream.on('error', function (err) { + strictEqual(err.code, 'ERR_STREAM_NULL_VALUES'); + errored.resolve(); + }); stream.on('data', errored.reject); stream.on('end', errored.reject); await errored.promise; - } + }, }; export const readable_needreadable = { async test(ctrl, env, ctx) { const readable = new Readable({ - read: () => {} + read: () => {}, }); // Initialized to false. strictEqual(readable._readableState.needReadable, false); const readableCalled1 = deferredPromise(); const ended = deferredPromise(); - readable.on( - 'readable', - () => { - // When the readable event fires, needReadable is reset. - strictEqual(readable._readableState.needReadable, false, '1'); - readable.read(); - readableCalled1.resolve(); - } - ); + readable.on('readable', () => { + // When the readable event fires, needReadable is reset. + strictEqual(readable._readableState.needReadable, false, '1'); + readable.read(); + readableCalled1.resolve(); + }); // If a readable listener is attached, then a readable event is needed. strictEqual(readable._readableState.needReadable, true); readable.push('foo'); readable.push(null); - readable.on( - 'end', - () => { - // No need to emit readable anymore when the stream ends. - strictEqual(readable._readableState.needReadable, false, '2'); - ended.resolve(); - } - ) - await Promise.all([ - readableCalled1.promise, - ended.promise, - ]); + readable.on('end', () => { + // No need to emit readable anymore when the stream ends. + strictEqual(readable._readableState.needReadable, false, '2'); + ended.resolve(); + }); + await Promise.all([readableCalled1.promise, ended.promise]); const readableCalled2 = deferredPromise(); const ended2 = deferredPromise(); @@ -9864,59 +9321,45 @@ export const readable_needreadable = { let readableCount = 0; let dataCount = 0; const asyncReadable = new Readable({ - read: () => {} + read: () => {}, }); - asyncReadable.on( - 'readable', - () => { - if (asyncReadable.read() !== null) { - // After each read(), the buffer is empty. - // If the stream doesn't end now, - // then we need to notify the reader on future changes. - readableCalled2.resolve(); - } - } - ) - queueMicrotask( - () => { - asyncReadable.push('foooo'); + asyncReadable.on('readable', () => { + if (asyncReadable.read() !== null) { + // After each read(), the buffer is empty. + // If the stream doesn't end now, + // then we need to notify the reader on future changes. + readableCalled2.resolve(); } - ); - queueMicrotask( - () => { - asyncReadable.push('bar'); - } - ); - queueMicrotask( - () => { - asyncReadable.push(null); - strictEqual(asyncReadable._readableState.needReadable, false); - } - ) + }); + queueMicrotask(() => { + asyncReadable.push('foooo'); + }); + queueMicrotask(() => { + asyncReadable.push('bar'); + }); + queueMicrotask(() => { + asyncReadable.push(null); + strictEqual(asyncReadable._readableState.needReadable, false); + }); const flowing = new Readable({ - read: () => {} + read: () => {}, }); // Notice this must be above the on('data') call. flowing.push('foooo'); flowing.push('bar'); flowing.push('quo'); - queueMicrotask( - () => { - flowing.push(null); - } - ); + queueMicrotask(() => { + flowing.push(null); + }); // When the buffer already has enough data, and the stream is // in flowing mode, there is no need for the readable event. - flowing.on( - 'data', - function (data) { - strictEqual(flowing._readableState.needReadable, false); - if (++dataCount === 3) dataCalled.resolve(); - } - ); + flowing.on('data', function (data) { + strictEqual(flowing._readableState.needReadable, false); + if (++dataCount === 3) dataCalled.resolve(); + }); await Promise.all([ readableCalled2.promise, dataCalled.promise, @@ -9963,52 +9406,42 @@ export const readable_needreadable = { // ); // } // ); - } + }, }; export const readable_invalid_chunk = { async test(ctrl, env, ctx) { async function testPushArg(val) { const readable = new Readable({ - read: () => {} + read: () => {}, }); const errored = deferredPromise(); - readable.on( - 'error', - function(err) { - strictEqual(err.code, 'ERR_INVALID_ARG_TYPE'); - errored.resolve(); - } - ); + readable.on('error', function (err) { + strictEqual(err.code, 'ERR_INVALID_ARG_TYPE'); + errored.resolve(); + }); readable.push(val); await errored.promise; } - await Promise.all([ - testPushArg([]), - testPushArg({}), - testPushArg(0) - ]); + await Promise.all([testPushArg([]), testPushArg({}), testPushArg(0)]); async function testUnshiftArg(val) { const readable = new Readable({ - read: () => {} + read: () => {}, }); const errored = deferredPromise(); - readable.on( - 'error', - function(err) { - strictEqual(err.code, 'ERR_INVALID_ARG_TYPE'); - errored.resolve(); - } - ); + readable.on('error', function (err) { + strictEqual(err.code, 'ERR_INVALID_ARG_TYPE'); + errored.resolve(); + }); readable.unshift(val); await errored.promise; } await Promise.all([ testUnshiftArg([]), testUnshiftArg({}), - testUnshiftArg(0) + testUnshiftArg(0), ]); - } + }, }; export const readable_hwm_0 = { @@ -10019,19 +9452,16 @@ export const readable_hwm_0 = { const r = new Readable({ // Must be called only once upon setting 'readable' listener read: readCalled.resolve, - highWaterMark: 0 + highWaterMark: 0, }); let pushedNull = false; // This will trigger read(0) but must only be called after push(null) // because the we haven't pushed any data - r.on( - 'readable', - () => { - strictEqual(r.read(), null); - strictEqual(pushedNull, true); - readableCalled.resolve(); - } - ) + r.on('readable', () => { + strictEqual(r.read(), null); + strictEqual(pushedNull, true); + readableCalled.resolve(); + }); r.on('end', ended.resolve); queueMicrotask(() => { strictEqual(r.read(), null); @@ -10043,7 +9473,7 @@ export const readable_hwm_0 = { readCalled.promise, ended.promise, ]); - } + }, }; export const readable_hwm_0_async = { @@ -10057,26 +9487,20 @@ export const readable_hwm_0_async = { const r = new Readable({ // Called 6 times: First 5 return data, last one signals end of stream. read: () => { - queueMicrotask( - () => { - if (count--) r.push('a'); - else r.push(null); - } - ); + queueMicrotask(() => { + if (count--) r.push('a'); + else r.push(null); + }); if (++readCount === 6) readCalled.resolve(); }, - highWaterMark: 0 - }) + highWaterMark: 0, + }); r.on('end', ended.resolve); r.on('data', () => { if (++dataCount === 5) dataCalled.resolve(); }); - await Promise.all([ - readCalled.promise, - ended.promise, - dataCalled.promise, - ]); - } + await Promise.all([readCalled.promise, ended.promise, dataCalled.promise]); + }, }; export const readable_event = { @@ -10085,7 +9509,7 @@ export const readable_event = { // First test, not reading when the readable is added. // make sure that on('readable', ...) triggers a readable event. const r = new Readable({ - highWaterMark: 3 + highWaterMark: 3, }); const readableCalled = deferredPromise(); r._read = readableCalled.reject; @@ -10104,7 +9528,7 @@ export const readable_event = { // already a length, while it IS reading. const r = new Readable({ - highWaterMark: 3 + highWaterMark: 3, }); const readCalled = deferredPromise(); const readableCalled = deferredPromise(); @@ -10117,16 +9541,13 @@ export const readable_event = { ok(r._readableState.reading); r.on('readable', readableCalled.resolve); }, 1); - await Promise.all([ - readCalled.promise, - readableCalled.promise, - ]); + await Promise.all([readCalled.promise, readableCalled.promise]); } { // Third test, not reading when the stream has not passed // the highWaterMark but *has* reached EOF. const r = new Readable({ - highWaterMark: 30 + highWaterMark: 30, }); // This triggers a 'readable' event, which is lost. @@ -10148,7 +9569,7 @@ export const readable_event = { const expected = underlyingData.filter((data) => data); const result = []; const r = new Readable({ - encoding: 'utf8' + encoding: 'utf8', }); r._read = function () { queueMicrotask(() => { @@ -10158,19 +9579,16 @@ export const readable_event = { this.push(underlyingData.shift()); } }); - } + }; r.on('readable', () => { const data = r.read(); if (data !== null) result.push(data); }); const ended = deferredPromise(); - r.on( - 'end', - () => { - deepStrictEqual(result, expected); - ended.resolve(); - } - ); + r.on('end', () => { + deepStrictEqual(result, expected); + ended.resolve(); + }); await ended.promise; } { @@ -10178,18 +9596,18 @@ export const readable_event = { const r = new Readable(); r._read = function () { // Actually doing thing here - } + }; r.on('data', function () {}); r.removeAllListeners(); strictEqual(r.eventNames().length, 0); } - } + }, }; export const readable_error_end = { async test(ctrl, env, ctx) { const r = new Readable({ - read() {} + read() {}, }); const data = deferredPromise(); const errored = deferredPromise(); @@ -10199,11 +9617,8 @@ export const readable_error_end = { r.push('asd'); r.push(null); r.destroy(new Error('kaboom')); - await Promise.all([ - data.promise, - errored.promise, - ]); - } + await Promise.all([data.promise, errored.promise]); + }, }; export const readable_ended = { @@ -10223,34 +9638,25 @@ export const readable_ended = { strictEqual(readable.readableEnded, false); readable.push(null); strictEqual(readable.readableEnded, false); - } + }; const ended = deferredPromise(); const dataCalled = deferredPromise(); - readable.on( - 'end', - () => { - strictEqual(readable.readableEnded, true); - ended.resolve(); - } - ); - readable.on( - 'data', - () => { - strictEqual(readable.readableEnded, false); - dataCalled.resolve(); - } - ); - await Promise.all([ - ended.promise, - dataCalled.promise, - ]); + readable.on('end', () => { + strictEqual(readable.readableEnded, true); + ended.resolve(); + }); + readable.on('data', () => { + strictEqual(readable.readableEnded, false); + dataCalled.resolve(); + }); + await Promise.all([ended.promise, dataCalled.promise]); } // Verifies no `error` triggered on multiple .push(null) invocations { const readable = new Readable(); readable.on('readable', () => { - readable.read() + readable.read(); }); const ended = deferredPromise(); readable.on('error', ended.reject); @@ -10260,25 +9666,22 @@ export const readable_ended = { readable.push(null); await ended.promise; } - } + }, }; export const readable_end_destroyed = { async test(ctrl, env, ctx) { - const r = new Readable() + const r = new Readable(); const closed = deferredPromise(); r.on('end', fail); r.resume(); r.destroy(); - r.on( - 'close', - () => { - r.push(null); - closed.resolve(); - } - ); + r.on('close', () => { + r.push(null); + closed.resolve(); + }); await closed.promise; - } + }, }; export const readable_short_stream = { @@ -10294,8 +9697,8 @@ export const readable_short_stream = { this.push('content'); this.push(null); readCalled.resolve(); - } - }) + }, + }); const t = new Transform({ transform: function (chunk, encoding, callback) { transformCalled.resolve(); @@ -10305,20 +9708,17 @@ export const readable_short_stream = { flush: function (callback) { flushCalled.resolve(); return callback(); - } - }) + }, + }); r.pipe(t); - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read(); - if (!chunk) break; - strictEqual(chunk.toString(), 'content'); - } - if (++readableCount === 2) readableCalled.resolve(); + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); } - ); + if (++readableCount === 2) readableCalled.resolve(); + }); await Promise.all([ readCalled.promise, transformCalled.promise, @@ -10339,20 +9739,17 @@ export const readable_short_stream = { flush: function (callback) { flushCalled.resolve(); return callback(); - } + }, }); t.end('content'); - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read(); - if (!chunk) break; - strictEqual(chunk.toString(), 'content'); - } - readableCalled.resolve(); + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); } - ); + readableCalled.resolve(); + }); await Promise.all([ transformCalled.promise, flushCalled.promise, @@ -10372,21 +9769,18 @@ export const readable_short_stream = { flush: function (callback) { flushCalled.resolve(); return callback(); - } - }) + }, + }); t.write('content'); t.end(); - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read(); - if (!chunk) break; - strictEqual(chunk.toString(), 'content'); - readableCalled.resolve(); - } + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); + readableCalled.resolve(); } - ); + }); await Promise.all([ transformCalled.promise, flushCalled.promise, @@ -10395,41 +9789,35 @@ export const readable_short_stream = { } { const t = new Readable({ - read() {} + read() {}, }); const readableCalled = deferredPromise(); - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read(); - if (!chunk) break; - strictEqual(chunk.toString(), 'content'); - } - readableCalled.resolve(); + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); } - ) + readableCalled.resolve(); + }); t.push('content'); t.push(null); await readableCalled.promise; } { const t = new Readable({ - read() {} + read() {}, }); const readableCalled = deferredPromise(); let readableCount = 0; - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read() - if (!chunk) break - strictEqual(chunk.toString(), 'content') - } - if (++readableCount === 2) readableCalled.resolve(); + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); } - ) + if (++readableCount === 2) readableCalled.resolve(); + }); queueMicrotask(() => { t.push('content'); t.push(null); @@ -10450,19 +9838,16 @@ export const readable_short_stream = { flush: function (callback) { flushCalled.resolve(); return callback(); + }, + }); + t.on('readable', function () { + while (true) { + const chunk = t.read(); + if (!chunk) break; + strictEqual(chunk.toString(), 'content'); } - }) - t.on( - 'readable', - function () { - while (true) { - const chunk = t.read(); - if (!chunk) break; - strictEqual(chunk.toString(), 'content'); - } - if (++readableCount === 2) readableCalled.resolve(); - } - ); + if (++readableCount === 2) readableCalled.resolve(); + }); t.write('content'); t.end(); await Promise.all([ @@ -10471,7 +9856,7 @@ export const readable_short_stream = { readableCalled.promise, ]); } - } + }, }; export const readable_didread = { @@ -10483,18 +9868,15 @@ export const readable_didread = { strictEqual(isDisturbed(readable), false); strictEqual(isErrored(readable), false); if (data === -1) { - readable.on( - 'error', - () => { - strictEqual(isErrored(readable), true); - } - ) + readable.on('error', () => { + strictEqual(isErrored(readable), true); + }); readable.on('data', fail); readable.on('end', fail); } else { - readable.on('error', fail) + readable.on('error', fail); if (data === -2) { - readable.on('end', fail) + readable.on('end', fail); } else { readable.on('end', () => {}); } @@ -10518,8 +9900,8 @@ export const readable_didread = { const readable = new Readable({ read() { this.push(null); - } - }) + }, + }); await check(readable, 0, () => { readable.read(); }); @@ -10528,7 +9910,7 @@ export const readable_didread = { const readable = new Readable({ read() { this.push(null); - } + }, }); await check(readable, 0, () => { readable.resume(); @@ -10538,8 +9920,8 @@ export const readable_didread = { const readable = new Readable({ read() { this.push(null); - } - }) + }, + }); await check(readable, -2, () => { readable.destroy(); }); @@ -10548,7 +9930,7 @@ export const readable_didread = { const readable = new Readable({ read() { this.push(null); - } + }, }); await check(readable, -1, () => { readable.destroy(new Error()); @@ -10559,7 +9941,7 @@ export const readable_didread = { read() { this.push('data'); this.push(null); - } + }, }); await check(readable, 1, () => { readable.on('data', noop); @@ -10570,14 +9952,14 @@ export const readable_didread = { read() { this.push('data'); this.push(null); - } - }) + }, + }); await check(readable, 1, () => { readable.on('data', noop); readable.off('data', noop); }); } - } + }, }; export const readable_destroy = { @@ -10585,7 +9967,7 @@ export const readable_destroy = { { const closed = deferredPromise(); const read = new Readable({ - read() {} + read() {}, }); read.resume(); read.on('close', closed.resolve); @@ -10596,35 +9978,29 @@ export const readable_destroy = { } { const read = new Readable({ - read() {} - }) + read() {}, + }); const closed = deferredPromise(); const errored = deferredPromise(); read.resume(); const expected = new Error('kaboom'); read.on('end', closed.reject); read.on('close', closed.resolve); - read.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + read.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); read.destroy(expected); strictEqual(read.errored, expected); strictEqual(read.destroyed, true); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const destroyCalled = deferredPromise(); const closed = deferredPromise(); const errored = deferredPromise(); const read = new Readable({ - read() {} + read() {}, }); read._destroy = function (err, cb) { strictEqual(err, expected); @@ -10634,13 +10010,10 @@ export const readable_destroy = { const expected = new Error('kaboom'); read.on('end', closed.reject); read.on('close', closed.resolve); - read.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + read.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); read.destroy(expected); strictEqual(read.destroyed, true); await Promise.all([ @@ -10658,7 +10031,7 @@ export const readable_destroy = { strictEqual(err, expected); cb(); destroyCalled.resolve(); - } + }, }); const expected = new Error('kaboom'); read.on('end', closed.reject); @@ -10668,14 +10041,11 @@ export const readable_destroy = { read.on('close', closed.resolve); read.destroy(expected); strictEqual(read.destroyed, true); - await Promise.all([ - destroyCalled.promise, - closed.promise, - ]); + await Promise.all([destroyCalled.promise, closed.promise]); } { const read = new Readable({ - read() {} + read() {}, }); const destroyCalled = deferredPromise(); read._destroy = function (err, cb) { @@ -10689,7 +10059,7 @@ export const readable_destroy = { } { const read = new Readable({ - read() {} + read() {}, }); read.resume(); const closed = deferredPromise(); @@ -10708,14 +10078,11 @@ export const readable_destroy = { read.removeListener('end', fail); read.on('end', closed.reject); strictEqual(read.destroyed, true); - await Promise.all([ - closed.promise, - destroyCalled.promise, - ]); + await Promise.all([closed.promise, destroyCalled.promise]); } { const read = new Readable({ - read() {} + read() {}, }); const expected = new Error('kaboom'); const destroyCalled = deferredPromise(); @@ -10729,16 +10096,13 @@ export const readable_destroy = { let ticked = false; read.on('end', closed.reject); read.on('close', closed.resolve); - read.on( - 'error', - (err) => { - strictEqual(ticked, true); - strictEqual(read._readableState.errorEmitted, true); - strictEqual(read._readableState.errored, expected); - strictEqual(err, expected); - errored.resolve(); - } - ) + read.on('error', (err) => { + strictEqual(ticked, true); + strictEqual(read._readableState.errorEmitted, true); + strictEqual(read._readableState.errored, expected); + strictEqual(err, expected); + errored.resolve(); + }); read.destroy(); strictEqual(read._readableState.errorEmitted, false); strictEqual(read._readableState.errored, expected); @@ -10763,7 +10127,7 @@ export const readable_destroy = { { // Destroy and destroy callback const read = new Readable({ - read() {} + read() {}, }); read.resume(); const expected = new Error('kaboom'); @@ -10771,31 +10135,22 @@ export const readable_destroy = { const closed = deferredPromise(); const destroyCalled = deferredPromise(); const errored = deferredPromise(); - read.on( - 'close', - () => { - strictEqual(read._readableState.errorEmitted, true); - strictEqual(ticked, true); - closed.resolve(); - } - ) - read.on( - 'error', - (err) => { - strictEqual(err, expected); - errored.resolve(); - } - ) + read.on('close', () => { + strictEqual(read._readableState.errorEmitted, true); + strictEqual(ticked, true); + closed.resolve(); + }); + read.on('error', (err) => { + strictEqual(err, expected); + errored.resolve(); + }); strictEqual(read._readableState.errored, null); strictEqual(read._readableState.errorEmitted, false); - read.destroy( - expected, - function (err) { - strictEqual(read._readableState.errored, expected); - strictEqual(err, expected); - destroyCalled.resolve(); - } - ) + read.destroy(expected, function (err) { + strictEqual(read._readableState.errored, expected); + strictEqual(err, expected); + destroyCalled.resolve(); + }); strictEqual(read._readableState.errorEmitted, false); strictEqual(read._readableState.errored, expected); ticked = true; @@ -10814,26 +10169,20 @@ export const readable_destroy = { queueMicrotask(() => cb(new Error('kaboom 1'))); destroyCalled.resolve(); }, - read() {} + read() {}, }); let ticked = false; - readable.on( - 'close', - () => { - strictEqual(ticked, true); - strictEqual(readable._readableState.errorEmitted, true); - closed.resolve(); - } - ); - readable.on( - 'error', - (err) => { - strictEqual(ticked, true); - strictEqual(err.message, 'kaboom 1'); - strictEqual(readable._readableState.errorEmitted, true); - errored.resolve(); - } - ) + readable.on('close', () => { + strictEqual(ticked, true); + strictEqual(readable._readableState.errorEmitted, true); + closed.resolve(); + }); + readable.on('error', (err) => { + strictEqual(ticked, true); + strictEqual(err.message, 'kaboom 1'); + strictEqual(readable._readableState.errorEmitted, true); + errored.resolve(); + }); readable.destroy(); strictEqual(readable.destroyed, true); strictEqual(readable._readableState.errored, null); @@ -10854,7 +10203,7 @@ export const readable_destroy = { } { const read = new Readable({ - read() {} + read() {}, }); const closed = deferredPromise(); read.destroy(); @@ -10866,8 +10215,8 @@ export const readable_destroy = { { const closed = deferredPromise(); const read = new Readable({ - read: closed.reject - }) + read: closed.reject, + }); read.on('close', closed.resolve); read.destroy(); strictEqual(read.destroyed, true); @@ -10880,16 +10229,13 @@ export const readable_destroy = { read() { this.push(null); this.push('asd'); - } + }, }); const errored = deferredPromise(); - read.on( - 'error', - () => { - ok(read._readableState.errored); - errored.resolve(); - } - ) + read.on('error', () => { + ok(read._readableState.errored); + errored.resolve(); + }); read.resume(); await errored.promise; } @@ -10900,71 +10246,56 @@ export const readable_destroy = { new Readable({ read() { this.push('asd'); - } + }, }) ); const closed = deferredPromise(); const errored = deferredPromise(); - read.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - errored.resolve(); - } - ) + read.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + errored.resolve(); + }); controller.abort(); read.on('data', closed.reject); read.on('close', closed.resolve); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { - const controller = new AbortController() + const controller = new AbortController(); const read = new Readable({ signal: controller.signal, read() { - this.push('asd') - } - }) + this.push('asd'); + }, + }); const closed = deferredPromise(); const errored = deferredPromise(); - read.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - errored.resolve(); - } - ) + read.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + errored.resolve(); + }); controller.abort(); read.on('data', closed.reject); read.on('close', closed.resolve); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { - const controller = new AbortController() + const controller = new AbortController(); const read = addAbortSignal( controller.signal, new Readable({ objectMode: true, read() { - return false - } + return false; + }, }) - ) - read.push('asd') + ); + read.push('asd'); const errored = deferredPromise(); - read.on( - 'error', - (e) => { - strictEqual(e.name, 'AbortError'); - errored.resolve(); - } - ) + read.on('error', (e) => { + strictEqual(e.name, 'AbortError'); + errored.resolve(); + }); const rejected = rejects( (async () => { // eslint-disable-next-line no-unused-vars, no-empty @@ -10974,78 +10305,60 @@ export const readable_destroy = { /AbortError/ ); setTimeout(() => controller.abort(), 0); - await Promise.all([ - errored.promise, - rejected, - ]); + await Promise.all([errored.promise, rejected]); } { const read = new Readable({ - read() {} + read() {}, }); const closed = deferredPromise(); const errored = deferredPromise(); read.on('data', closed.reject); - read.on( - 'error', - (e) => { - read.push('asd'); - read.read(); - errored.resolve(); - } - ) - read.on( - 'close', - (e) => { - read.push('asd'); - read.read(); - closed.resolve(); - } - ) + read.on('error', (e) => { + read.push('asd'); + read.read(); + errored.resolve(); + }); + read.on('close', (e) => { + read.push('asd'); + read.read(); + closed.resolve(); + }); read.destroy(new Error('asd')); - await Promise.all([ - closed.promise, - errored.promise, - ]); + await Promise.all([closed.promise, errored.promise]); } { const read = new Readable({ - read() {} + read() {}, }); const closed = deferredPromise(); read.on('data', closed.reject); - read.on( - 'close', - (e) => { - read.push('asd'); - read.read(); - closed.resolve(); - } - ) + read.on('close', (e) => { + read.push('asd'); + read.read(); + closed.resolve(); + }); read.destroy(); await closed.promise; } { const read = new Readable({ - read() {} + read() {}, }); const closed = deferredPromise(); read.on('data', closed.reject); - read.on( - 'close', - (e) => { - read.push('asd'); - read.unshift('asd'); - closed.resolve(); - } - ) + read.on('close', (e) => { + read.push('asd'); + read.unshift('asd'); + closed.resolve(); + }); read.destroy(); await closed.promise; } { const read = new Readable({ - read() {} - }) + read() {}, + }); const closed = deferredPromise(); read.on('data', closed.reject); read.on('close', closed.resolve); @@ -11055,24 +10368,21 @@ export const readable_destroy = { } { const read = new Readable({ - read() {} + read() {}, }); read.resume(); const closed = deferredPromise(); read.on('data', closed.reject); - read.on( - 'close', - (e) => { - read.push('asd'); - closed.resolve(); - } - ) + read.on('close', (e) => { + read.push('asd'); + closed.resolve(); + }); read.destroy(); await closed.promise; } { const read = new Readable({ - read() {} + read() {}, }); const closed = deferredPromise(); read.on('data', closed.reject); @@ -11081,13 +10391,13 @@ export const readable_destroy = { read.push('asd'); await closed.promise; } - } + }, }; export const readable_data = { async test(ctrl, env, ctx) { const readable = new Readable({ - read() {} + read() {}, }); function read() {} readable.setEncoding('utf8'); @@ -11099,7 +10409,7 @@ export const readable_data = { readable.push('hello'); }); await dataCalled.promise; - } + }, }; export const readable_constructor_set_methods = { @@ -11108,13 +10418,13 @@ export const readable_constructor_set_methods = { const _read = function _read(n) { this.push(null); readCalled.resolve(); - } + }; const r = new Readable({ - read: _read + read: _read, }); r.resume(); await readCalled.promise; - } + }, }; export const readable_add_chunk_during_data = { @@ -11123,33 +10433,27 @@ export const readable_add_chunk_during_data = { let dataCount = 0; for (const method of ['push', 'unshift']) { const r = new Readable({ - read() {} - }); - r.once( - 'data', - (chunk) => { - strictEqual(r.readableLength, 0); - r[method](chunk); - strictEqual(r.readableLength, chunk.length); - r.on( - 'data', - (chunk) => { - strictEqual(chunk.toString(), 'Hello, world'); - if (++dataCount === 2) dataCalled.resolve(); - } - ) - } - ); + read() {}, + }); + r.once('data', (chunk) => { + strictEqual(r.readableLength, 0); + r[method](chunk); + strictEqual(r.readableLength, chunk.length); + r.on('data', (chunk) => { + strictEqual(chunk.toString(), 'Hello, world'); + if (++dataCount === 2) dataCalled.resolve(); + }); + }); r.push('Hello, world'); } - } + }, }; export const readable_aborted = { async test(ctrl, env, ctx) { { const readable = new Readable({ - read() {} + read() {}, }); strictEqual(readable.readableAborted, false); readable.destroy(); @@ -11157,7 +10461,7 @@ export const readable_aborted = { } { const readable = new Readable({ - read() {} + read() {}, }); strictEqual(readable.readableAborted, false); readable.push(null); @@ -11166,7 +10470,7 @@ export const readable_aborted = { } { const readable = new Readable({ - read() {} + read() {}, }); strictEqual(readable.readableAborted, false); readable.push('asd'); @@ -11175,37 +10479,34 @@ export const readable_aborted = { } { const readable = new Readable({ - read() {} + read() {}, }); strictEqual(readable.readableAborted, false); readable.push('asd'); readable.push(null); strictEqual(readable.readableAborted, false); const ended = deferredPromise(); - readable.on( - 'end', - () => { - strictEqual(readable.readableAborted, false); - readable.destroy(); + readable.on('end', () => { + strictEqual(readable.readableAborted, false); + readable.destroy(); + strictEqual(readable.readableAborted, false); + queueMicrotask(() => { strictEqual(readable.readableAborted, false); - queueMicrotask(() => { - strictEqual(readable.readableAborted, false); - ended.resolve(); - }); - } - ) + ended.resolve(); + }); + }); readable.resume(); await ended.promise; } { const duplex = new Duplex({ readable: false, - write() {} + write() {}, }); duplex.destroy(); strictEqual(duplex.readableAborted, false); } - } + }, }; export const push_strings = { @@ -11228,9 +10529,9 @@ export const push_strings = { case 3: return queueMicrotask(() => { this.push('first chunk'); - }) + }); default: - throw new Error('?') + throw new Error('?'); } } } @@ -11239,12 +10540,12 @@ export const push_strings = { ms.on('readable', function () { let chunk; while (null !== (chunk = ms.read())) results.push(String(chunk)); - }) + }); const expect = ['first chunksecond to last chunk', 'last chunk']; await promises.finished(ms); strictEqual(ms._chunks, -1); deepStrictEqual(results, expect); - } + }, }; export const filter = { @@ -11263,7 +10564,7 @@ export const filter = { const stream = Readable.from([1, 2, 3, 4, 5]).filter(async (x) => { await Promise.resolve(); return x > 3; - }) + }); const result = [4, 5]; for await (const item of stream) { strictEqual(item, result.shift()); @@ -11307,8 +10608,8 @@ export const filter = { this.push(Uint8Array.from([i])); i++; }, - highWaterMark: 0 - }).filter(async ([x]) => x !== 5) + highWaterMark: 0, + }).filter(async ([x]) => x !== 5); const result = (await stream.toArray()).map((x) => x[0]); const expected = [...Array(10).keys()].filter((x) => x !== 5); deepStrictEqual(result, expected); @@ -11320,7 +10621,7 @@ export const filter = { throw new Error('boom'); } return true; - }) + }); await rejects(stream.map((x) => x + x).toArray(), /boom/); } { @@ -11330,7 +10631,7 @@ export const filter = { throw new Error('boom'); } return true; - }) + }); await rejects(stream.filter(() => true).toArray(), /boom/); } { @@ -11349,31 +10650,31 @@ export const filter = { }, { signal: ac.signal, - concurrency: 2 + concurrency: 2, } ); queueMicrotask(() => ac.abort()); // pump await rejects( - async () => { - for await (const item of stream) { - // nope - } - }, - { - name: 'AbortError' + async () => { + for await (const item of stream) { + // nope } - ); + }, + { + name: 'AbortError', + } + ); } { // Concurrency result order const stream = Readable.from([1, 2]).filter( async (item, { signal }) => { await scheduler.wait(10 - item); - return true + return true; }, { - concurrency: 2 + concurrency: 2, } ); const expected = [1, 2]; @@ -11387,11 +10688,12 @@ export const filter = { throws( () => Readable.from([1]).filter((x) => x, { - concurrency: 'Foo' - }), { code: 'ERR_OUT_OF_RANGE' } + concurrency: 'Foo', + }), + { code: 'ERR_OUT_OF_RANGE' } ); throws(() => Readable.from([1]).filter((x) => x, 1), { - code: 'ERR_INVALID_ARG_TYPE' + code: 'ERR_INVALID_ARG_TYPE', }); } { @@ -11399,7 +10701,7 @@ export const filter = { const stream = Readable.from([1, 2, 3, 4, 5]).filter((x) => true); strictEqual(stream.readable, true); } - } + }, }; export const pipeWithoutListenerCount = { @@ -11417,23 +10719,20 @@ export const pipeWithoutListenerCount = { r.on('error', rErrored.resolve); w.on('error', wErrored.resolve); r.pipe(w); - await Promise.all([ - rErrored.promise, - wErrored.promise, - ]); - } + await Promise.all([rErrored.promise, wErrored.promise]); + }, }; export const pipeUnpipeStreams = { async test(ctrl, env, ctx) { const source = Readable({ - read: () => {} + read: () => {}, }); const dest1 = Writable({ - write: () => {} + write: () => {}, }); const dest2 = Writable({ - write: () => {} + write: () => {}, }); source.pipe(dest1); source.pipe(dest2); @@ -11459,24 +10758,34 @@ export const pipeUnpipeStreams = { { // Test `cleanup()` if we unpipe all streams. const source = Readable({ - read: () => {} + read: () => {}, }); const dest1 = Writable({ - write: () => {} + write: () => {}, }); const dest2 = Writable({ - write: () => {} + write: () => {}, }); let destCount = 0; const srcCheckEventNames = ['end', 'data']; - const destCheckEventNames = ['close', 'finish', 'drain', 'error', 'unpipe']; + const destCheckEventNames = [ + 'close', + 'finish', + 'drain', + 'error', + 'unpipe', + ]; const checkSrcCleanup = () => { strictEqual(source._readableState.pipes.length, 0); strictEqual(source._readableState.flowing, false); srcCheckEventNames.forEach((eventName) => { - strictEqual(source.listenerCount(eventName), 0, `source's '${eventName}' event listeners not removed`); - }) - } + strictEqual( + source.listenerCount(eventName), + 0, + `source's '${eventName}' event listeners not removed` + ); + }); + }; async function checkDestCleanup(dest) { const done = deferredPromise(); const currentDestId = ++destCount; @@ -11486,7 +10795,8 @@ export const pipeUnpipeStreams = { strictEqual( dest.listenerCount(eventName), 0, - `destination{${currentDestId}}'s '${eventName}' event ` + 'listeners not removed' + `destination{${currentDestId}}'s '${eventName}' event ` + + 'listeners not removed' ); }); if (--destCount === 0) checkSrcCleanup(); @@ -11498,30 +10808,25 @@ export const pipeUnpipeStreams = { const p1 = checkDestCleanup(dest1); const p2 = checkDestCleanup(dest2); source.unpipe(); - await Promise.all([ - p1, p2, unpipe1.promise, unpipe2.promise - ]); + await Promise.all([p1, p2, unpipe1.promise, unpipe2.promise]); } { const src = Readable({ - read: () => {} + read: () => {}, }); const dst = Writable({ - write: () => {} + write: () => {}, }); src.pipe(dst); const resumeCalled = deferredPromise(); - src.on( - 'resume', - () => { - src.on('pause', resumeCalled.resolve); - src.unpipe(dst); - } - ); + src.on('resume', () => { + src.on('pause', resumeCalled.resolve); + src.unpipe(dst); + }); await resumeCalled.promise; } - } -} + }, +}; export const pipeSameDestinationTwice = { async test(ctrl, env, ctx) { @@ -11536,7 +10841,7 @@ export const pipeSameDestinationTwice = { strictEqual(`${chunk}`, 'foobar'); cb(); writeCalled.resolve(); - } + }, }); passThrough.pipe(dest); passThrough.pipe(dest); @@ -11561,7 +10866,7 @@ export const pipeSameDestinationTwice = { strictEqual(`${chunk}`, 'foobar'); cb(); if (++writeCount == 2) writeCalled.resolve(); - } + }, }); passThrough.pipe(dest); passThrough.pipe(dest); @@ -11575,7 +10880,7 @@ export const pipeSameDestinationTwice = { { const passThrough = new PassThrough(); const dest = new Writable({ - write: fail + write: fail, }); passThrough.pipe(dest); passThrough.pipe(dest); @@ -11589,7 +10894,7 @@ export const pipeSameDestinationTwice = { strictEqual(passThrough._readableState.pipes.length, 0); passThrough.write('foobar'); } - } + }, }; export const pipeNeedDrain = { @@ -11599,7 +10904,7 @@ export const pipeNeedDrain = { write(buf, encoding, callback) { queueMicrotask(callback); }, - highWaterMark: 1 + highWaterMark: 1, }); while (w.write('asd')); strictEqual(w.writableNeedDrain, true); @@ -11607,7 +10912,7 @@ export const pipeNeedDrain = { read() { this.push('asd'); this.push(null); - } + }, }); const pauseCalled = deferredPromise(); const endCalled = deferredPromise(); @@ -11617,17 +10922,14 @@ export const pipeNeedDrain = { }); r.on('end', endCalled.resolve); r.pipe(w); - await Promise.all([ - pauseCalled.promise, - endCalled.promise, - ]); - } + await Promise.all([pauseCalled.promise, endCalled.promise]); + }, }; export const pipeMultiplePipes = { async test(ctrl, env, ctx) { const readable = new Readable({ - read: () => {} + read: () => {}, }); const writables = []; const promises = []; @@ -11639,7 +10941,7 @@ export const pipeMultiplePipes = { target.output.push(chunk); callback(); writeCalled.resolve(); - } + }, }); const pipeCalled = deferredPromise(); promises.push(pipeCalled.promise); @@ -11660,22 +10962,19 @@ export const pipeMultiplePipes = { deepStrictEqual(target.output, [input]); readable.unpipe(target); } - readable.push('something else') // This does not get through. - readable.push(null) - readable.resume() // Make sure the 'end' event gets emitted. + readable.push('something else'); // This does not get through. + readable.push(null); + readable.resume(); // Make sure the 'end' event gets emitted. const ended = deferredPromise(); - readable.on( - 'end', - () => { - for (const target of writables) { - deepStrictEqual(target.output, [input]) - } - ended.resolve(); + readable.on('end', () => { + for (const target of writables) { + deepStrictEqual(target.output, [input]); } - ); + ended.resolve(); + }); await ended.promise; - } + }, }; export const pipeManualResume = { @@ -11691,25 +10990,21 @@ export const pipeManualResume = { const rs = Readable({ objectMode: true, read: () => { - if (--counter >= 0) - rs.push({ counter }); + if (--counter >= 0) rs.push({ counter }); else rs.push(null); - } + }, }); const ws = Writable({ objectMode: true, write: (data, enc, cb) => { queueMicrotask(cb); - } + }, }); rs.on('close', rClosed.resolve); ws.on('close', wClosed.resolve); queueMicrotask(() => throwCodeInbetween(rs, ws)); rs.pipe(ws); - await Promise.all([ - rClosed.promise, - wClosed.promise, - ]); + await Promise.all([rClosed.promise, wClosed.promise]); } await Promise.all([ @@ -11717,7 +11012,7 @@ export const pipeManualResume = { test((rs) => rs.resume()), test(() => 0), ]); - } + }, }; export const pipeFlow = { @@ -11730,22 +11025,19 @@ export const pipeFlow = { if (ticks-- > 0) return queueMicrotask(() => rs.push({})); rs.push({}); rs.push(null); - } + }, }); const ws = new Writable({ highWaterMark: 0, objectMode: true, - write: (data, end, cb) => queueMicrotask(cb) - }) + write: (data, end, cb) => queueMicrotask(cb), + }); const ended = deferredPromise(); const finished = deferredPromise(); rs.on('end', ended.resolve); ws.on('finish', finished.resolve); rs.pipe(ws); - await Promise.all([ - ended.promise, - finished.promise, - ]); + await Promise.all([ended.promise, finished.promise]); } { let missing = 8; @@ -11754,19 +11046,19 @@ export const pipeFlow = { read: () => { if (missing--) rs.push({}); else rs.push(null); - } - }) + }, + }); const pt = rs .pipe( new PassThrough({ objectMode: true, - highWaterMark: 2 + highWaterMark: 2, }) ) .pipe( new PassThrough({ objectMode: true, - highWaterMark: 2 + highWaterMark: 2, }) ); pt.on('end', () => { @@ -11786,7 +11078,7 @@ export const pipeFlow = { wrapper.push(data); } }); - } + }, }); wrapper.resume(); const ended = deferredPromise(); @@ -11796,12 +11088,12 @@ export const pipeFlow = { { // Only register drain if there is backpressure. const rs = new Readable({ - read() {} + read() {}, }); const pt = rs.pipe( new PassThrough({ objectMode: true, - highWaterMark: 2 + highWaterMark: 2, }) ); strictEqual(pt.listenerCount('drain'), 0); @@ -11820,7 +11112,7 @@ export const pipeFlow = { }); await done.promise; } - } + }, }; export const pipeErrorHandling = { @@ -11852,22 +11144,19 @@ export const pipeErrorHandling = { } { const r = new Readable({ - autoDestroy: false + autoDestroy: false, }); const w = new Writable({ - autoDestroy: false + autoDestroy: false, }); let removed = false; r._read = function () { - setTimeout( - function () { - ok(removed); - throws(function () { - w.emit('error', new Error('fail')); - }, /^Error: fail$/) - }, - 1 - ) + setTimeout(function () { + ok(removed); + throws(function () { + w.emit('error', new Error('fail')); + }, /^Error: fail$/); + }, 1); }; w.on('error', myOnError); r.pipe(w); @@ -11882,13 +11171,10 @@ export const pipeErrorHandling = { const w = new Writable(); let removed = false; r._read = function () { - setTimeout( - function () { - ok(removed); - w.emit('error', new Error('fail')); - }, - 1 - ); + setTimeout(function () { + ok(removed); + w.emit('error', new Error('fail')); + }, 1); }; const errored = deferredPromise(); w.on('error', errored.resolve); @@ -11903,19 +11189,16 @@ export const pipeErrorHandling = { const _err = new Error('this should be handled'); const destination = new PassThrough(); const errored = deferredPromise(); - destination.once( - 'error', - (err) => { - strictEqual(err, _err); - errored.resolve(); - } - ); + destination.once('error', (err) => { + strictEqual(err, _err); + errored.resolve(); + }); const stream = new Stream(); stream.pipe(destination); destination.destroy(_err); await errored.promise; } - } + }, }; export const pipeCleanup = { @@ -12004,7 +11287,7 @@ export const pipeCleanup = { strictEqual(d.listeners('close').length, 0); strictEqual(w.listeners('end').length, 0); strictEqual(w.listeners('close').length, 0); - } + }, }; export const pipeCleanupPause = { @@ -12022,7 +11305,7 @@ export const pipeCleanupPause = { writer1._write = function (chunk, encoding, cb) { this.emit('chunk-received'); cb(); - } + }; writer1.once('chunk-received', function () { reader.unpipe(writer1); reader.pipe(writer2); @@ -12041,7 +11324,7 @@ export const pipeCleanupPause = { reader.pipe(writer1); reader.push(buffer); await done.promise; - } + }, }; export const writableAdapter = { @@ -12055,14 +11338,11 @@ export const writableAdapter = { write(chunk, encoding, callback) { strictEqual(dec.decode(chunk), 'ok'); p.resolve(); - } + }, }); const ws = Writable.toWeb(w); const writer = ws.getWriter(); - await Promise.all([ - writer.write(enc.encode('ok')), - p.promise - ]); + await Promise.all([writer.write(enc.encode('ok')), p.promise]); } // fromWeb @@ -12072,14 +11352,14 @@ export const writableAdapter = { write(chunk) { strictEqual(dec.decode(chunk), 'ok'); p.resolve(); - } + }, }); const w = Writable.fromWeb(ws); const p2 = deferredPromise(); w.write(enc.encode('ok'), p2.resolve); await Promise.all([p.promise, p2.promise]); } - } + }, }; export const readableAdapter = { @@ -12091,7 +11371,7 @@ export const readableAdapter = { const r = new Readable({ read() { this.push(enc.encode('ok')); - } + }, }); const rs = Readable.toWeb(r); const reader = rs.getReader(); @@ -12103,7 +11383,7 @@ export const readableAdapter = { // Using a Node.js stream to feed into a Response... const r = new Readable({ highWaterMark: 2, - read() {} + read() {}, }); setTimeout(() => r.push(enc.encode('ok')), 10); setTimeout(() => r.push(enc.encode(' there')), 20); @@ -12120,7 +11400,7 @@ export const readableAdapter = { pull(c) { c.enqueue(enc.encode('ok')); c.close(); - } + }, }); const r = Readable.fromWeb(rs); const p = deferredPromise(); @@ -12130,5 +11410,5 @@ export const readableAdapter = { }); await p.promise; } - } + }, }; diff --git a/src/workerd/api/node/tests/string-decoder-test.js b/src/workerd/api/node/tests/string-decoder-test.js index 44a7fd0c68a..0067611cf4d 100644 --- a/src/workerd/api/node/tests/string-decoder-test.js +++ b/src/workerd/api/node/tests/string-decoder-test.js @@ -1,4 +1,3 @@ - // Copyright (c) 2017-2022 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 @@ -24,20 +23,11 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -import { - ok, - fail, - strictEqual, - throws, -} from 'node:assert'; +import { ok, fail, strictEqual, throws } from 'node:assert'; -import { - Buffer, -} from 'node:buffer'; +import { Buffer } from 'node:buffer'; -import { - StringDecoder, -} from 'node:string_decoder'; +import { StringDecoder } from 'node:string_decoder'; import * as string_decoder from 'node:string_decoder'; @@ -143,7 +133,6 @@ function unicodeEscape(str) { export const stringDecoder = { test(ctrl, env, ctx) { - // Test default encoding let decoder = new StringDecoder(); strictEqual(decoder.encoding, 'utf8'); @@ -168,7 +157,7 @@ export const stringDecoder = { test_( 'utf-8', - Buffer.from([0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30, 0xE3, 0x81, 0x85]), + Buffer.from([0xcb, 0xa4, 0x64, 0xe1, 0x8b, 0xa4, 0x30, 0xe3, 0x81, 0x85]), '\u02e4\u0064\u12e4\u0030\u3045' ); @@ -197,8 +186,11 @@ export const stringDecoder = { // V8 has changed their invalid UTF-8 handling, see // https://chromium-review.googlesource.com/c/v8/v8/+/671020 for more info. - test_('utf-8', Buffer.from('EDA0B5EDB08D', 'hex'), - '\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd'); + test_( + 'utf-8', + Buffer.from('EDA0B5EDB08D', 'hex'), + '\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd' + ); // UCS-2 test_('ucs2', Buffer.from('ababc', 'ucs2'), 'ababc'); @@ -221,10 +213,7 @@ export const stringDecoder = { const arrayBufferViewStr = 'String for ArrayBufferView tests\n'; const inputBuffer = Buffer.from(arrayBufferViewStr.repeat(8), 'utf8'); for (const expectView of getArrayBufferViews(inputBuffer)) { - strictEqual( - decoder.write(expectView), - inputBuffer.toString('utf8') - ); + strictEqual(decoder.write(expectView), inputBuffer.toString('utf8')); strictEqual(decoder.end(), ''); } @@ -237,8 +226,10 @@ export const stringDecoder = { strictEqual(decoder.end(), ''); decoder = new StringDecoder('utf8'); - strictEqual(decoder.write(Buffer.from('\ufffd\ufffd\ufffd')), - '\ufffd\ufffd\ufffd'); + strictEqual( + decoder.write(Buffer.from('\ufffd\ufffd\ufffd')), + '\ufffd\ufffd\ufffd' + ); strictEqual(decoder.end(), ''); decoder = new StringDecoder('utf8'); @@ -293,31 +284,22 @@ export const stringDecoder = { strictEqual(decoder.write(Buffer.from('bde5', 'hex')), '\ufffd\ufffd'); strictEqual(decoder.end(), '\ufffd'); - throws( - () => new StringDecoder(1), - { - code: 'ERR_UNKNOWN_ENCODING', - name: 'TypeError', - message: 'Unknown encoding: 1' - } - ); + throws(() => new StringDecoder(1), { + code: 'ERR_UNKNOWN_ENCODING', + name: 'TypeError', + message: 'Unknown encoding: 1', + }); - throws( - () => new StringDecoder('test'), - { - code: 'ERR_UNKNOWN_ENCODING', - name: 'TypeError', - message: 'Unknown encoding: test' - } - ); + throws(() => new StringDecoder('test'), { + code: 'ERR_UNKNOWN_ENCODING', + name: 'TypeError', + message: 'Unknown encoding: test', + }); - throws( - () => new StringDecoder('utf8').write(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - } - ); + throws(() => new StringDecoder('utf8').write(null), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); throws( () => new StringDecoder('utf8').__proto__.write(Buffer.from('abc')), @@ -325,51 +307,54 @@ export const stringDecoder = { code: 'ERR_INVALID_THIS', } ); - } + }, }; export const stringDecoderEnd = { test(ctrl, env, ctx) { const encodings = ['base64', 'base64url', 'hex', 'utf8', 'utf16le', 'ucs2']; - const bufs = [ '☃💩', 'asdf' ].map((b) => Buffer.from(b)); + const bufs = ['☃💩', 'asdf'].map((b) => Buffer.from(b)); // Also test just arbitrary bytes from 0-15. for (let i = 1; i <= 16; i++) { - const bytes = '.'.repeat(i - 1).split('.').map((_, j) => j + 0x78); + const bytes = '.' + .repeat(i - 1) + .split('.') + .map((_, j) => j + 0x78); bufs.push(Buffer.from(bytes)); } encodings.forEach(testEncoding); - testEnd('utf8', Buffer.of(0xE2), Buffer.of(0x61), '\uFFFDa'); - testEnd('utf8', Buffer.of(0xE2), Buffer.of(0x82), '\uFFFD\uFFFD'); - testEnd('utf8', Buffer.of(0xE2), Buffer.of(0xE2), '\uFFFD\uFFFD'); - testEnd('utf8', Buffer.of(0xE2, 0x82), Buffer.of(0x61), '\uFFFDa'); - testEnd('utf8', Buffer.of(0xE2, 0x82), Buffer.of(0xAC), '\uFFFD\uFFFD'); - testEnd('utf8', Buffer.of(0xE2, 0x82), Buffer.of(0xE2), '\uFFFD\uFFFD'); - testEnd('utf8', Buffer.of(0xE2, 0x82, 0xAC), Buffer.of(0x61), '€a'); - - testEnd('utf16le', Buffer.of(0x3D), Buffer.of(0x61, 0x00), 'a'); - testEnd('utf16le', Buffer.of(0x3D), Buffer.of(0xD8, 0x4D, 0xDC), '\u4DD8'); - testEnd('utf16le', Buffer.of(0x3D, 0xD8), Buffer.of(), '\uD83D'); - testEnd('utf16le', Buffer.of(0x3D, 0xD8), Buffer.of(0x61, 0x00), '\uD83Da'); + testEnd('utf8', Buffer.of(0xe2), Buffer.of(0x61), '\uFFFDa'); + testEnd('utf8', Buffer.of(0xe2), Buffer.of(0x82), '\uFFFD\uFFFD'); + testEnd('utf8', Buffer.of(0xe2), Buffer.of(0xe2), '\uFFFD\uFFFD'); + testEnd('utf8', Buffer.of(0xe2, 0x82), Buffer.of(0x61), '\uFFFDa'); + testEnd('utf8', Buffer.of(0xe2, 0x82), Buffer.of(0xac), '\uFFFD\uFFFD'); + testEnd('utf8', Buffer.of(0xe2, 0x82), Buffer.of(0xe2), '\uFFFD\uFFFD'); + testEnd('utf8', Buffer.of(0xe2, 0x82, 0xac), Buffer.of(0x61), '€a'); + + testEnd('utf16le', Buffer.of(0x3d), Buffer.of(0x61, 0x00), 'a'); + testEnd('utf16le', Buffer.of(0x3d), Buffer.of(0xd8, 0x4d, 0xdc), '\u4DD8'); + testEnd('utf16le', Buffer.of(0x3d, 0xd8), Buffer.of(), '\uD83D'); + testEnd('utf16le', Buffer.of(0x3d, 0xd8), Buffer.of(0x61, 0x00), '\uD83Da'); testEnd( 'utf16le', - Buffer.of(0x3D, 0xD8), - Buffer.of(0x4D, 0xDC), + Buffer.of(0x3d, 0xd8), + Buffer.of(0x4d, 0xdc), '\uD83D\uDC4D' ); - testEnd('utf16le', Buffer.of(0x3D, 0xD8, 0x4D), Buffer.of(), '\uD83D'); + testEnd('utf16le', Buffer.of(0x3d, 0xd8, 0x4d), Buffer.of(), '\uD83D'); testEnd( 'utf16le', - Buffer.of(0x3D, 0xD8, 0x4D), + Buffer.of(0x3d, 0xd8, 0x4d), Buffer.of(0x61, 0x00), '\uD83Da' ); - testEnd('utf16le', Buffer.of(0x3D, 0xD8, 0x4D), Buffer.of(0xDC), '\uD83D'); + testEnd('utf16le', Buffer.of(0x3d, 0xd8, 0x4d), Buffer.of(0xdc), '\uD83D'); testEnd( 'utf16le', - Buffer.of(0x3D, 0xD8, 0x4D, 0xDC), + Buffer.of(0x3d, 0xd8, 0x4d, 0xdc), Buffer.of(0x61, 0x00), '👍a' ); @@ -386,7 +371,12 @@ export const stringDecoderEnd = { testEnd('base64url', Buffer.of(0x61, 0x61), Buffer.of(), 'YWE'); testEnd('base64url', Buffer.of(0x61, 0x61), Buffer.of(0x61), 'YWEYQ'); testEnd('base64url', Buffer.of(0x61, 0x61, 0x61), Buffer.of(), 'YWFh'); - testEnd('base64url', Buffer.of(0x61, 0x61, 0x61), Buffer.of(0x61), 'YWFhYQ'); + testEnd( + 'base64url', + Buffer.of(0x61, 0x61, 0x61), + Buffer.of(0x61), + 'YWFhYQ' + ); function testEncoding(encoding) { bufs.forEach((buf) => { @@ -428,7 +418,7 @@ export const stringDecoderEnd = { strictEqual(res, expected); } - } + }, }; export const stringDecoderFuzz = { @@ -439,13 +429,18 @@ export const stringDecoderFuzz = { function randBuf(maxLen) { const buf = Buffer.allocUnsafe(rand(maxLen)); - for (let i = 0; i < buf.length; i++) - buf[i] = rand(256); + for (let i = 0; i < buf.length; i++) buf[i] = rand(256); return buf; } const encodings = [ - 'utf16le', 'utf8', 'ascii', 'hex', 'base64', 'latin1', 'base64url', + 'utf16le', + 'utf8', + 'ascii', + 'hex', + 'base64', + 'latin1', + 'base64url', ]; function runSingleFuzzTest() { @@ -462,91 +457,113 @@ export const stringDecoderFuzz = { } strings.push(sd.end()); - strictEqual(strings.join(''), Buffer.concat(bufs).toString(enc), - `Mismatch:\n${strings}\n` + - bufs.map((buf) => buf.toString('hex')) + - `\nfor encoding ${enc}`); + strictEqual( + strings.join(''), + Buffer.concat(bufs).toString(enc), + `Mismatch:\n${strings}\n` + + bufs.map((buf) => buf.toString('hex')) + + `\nfor encoding ${enc}` + ); } const start = Date.now(); - while (Date.now() - start < 100) - runSingleFuzzTest(); - } + while (Date.now() - start < 100) runSingleFuzzTest(); + }, }; export const stringDecoderHacking = { test(ctrl, env, ctx) { - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym] = "not a buffer"; - sd.write(Buffer.from("this shouldn't crash")); - }, { - name: 'TypeError' - }); - - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym] = Buffer.alloc(1); - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Invalid StringDecoder' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym] = 'not a buffer'; + sd.write(Buffer.from("this shouldn't crash")); + }, + { + name: 'TypeError', + } + ); - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym] = Buffer.alloc(9); - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Invalid StringDecoder' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym] = Buffer.alloc(1); + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Invalid StringDecoder', + } + ); - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym][5] = 100; - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Buffered bytes cannot exceed 4' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym] = Buffer.alloc(9); + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Invalid StringDecoder', + } + ); - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym][4] = 100; - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Missing bytes cannot exceed 4' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym][5] = 100; + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Buffered bytes cannot exceed 4', + } + ); - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym][6] = 100; - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Invalid StringDecoder state' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym][4] = 100; + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Missing bytes cannot exceed 4', + } + ); - throws(() => { - const sd = new StringDecoder(); - const sym = Object.getOwnPropertySymbols(sd)[0]; - sd[sym][4] = 3; - sd[sym][5] = 2; - sd.write(Buffer.from("this shouldn't crash")); - }, { - message: 'Invalid StringDecoder state' - }); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym][6] = 100; + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Invalid StringDecoder state', + } + ); + throws( + () => { + const sd = new StringDecoder(); + const sym = Object.getOwnPropertySymbols(sd)[0]; + sd[sym][4] = 3; + sd[sym][5] = 2; + sd.write(Buffer.from("this shouldn't crash")); + }, + { + message: 'Invalid StringDecoder state', + } + ); { // fuzz a bit with random values const messages = [ - "Invalid StringDecoder state", - "Missing bytes cannot exceed 4", - "Buffered bytes cannot exceed 4", + 'Invalid StringDecoder state', + 'Missing bytes cannot exceed 4', + 'Buffered bytes cannot exceed 4', ]; for (let n = 0; n < 255; n++) { try { @@ -561,5 +578,5 @@ export const stringDecoderHacking = { } } } - } + }, }; diff --git a/src/workerd/api/node/tests/util-nodejs-test.js b/src/workerd/api/node/tests/util-nodejs-test.js index 1c2d5d4a97f..f9757cb3a4a 100644 --- a/src/workerd/api/node/tests/util-nodejs-test.js +++ b/src/workerd/api/node/tests/util-nodejs-test.js @@ -29,12 +29,12 @@ import util, { inspect } from 'node:util'; const remainingMustCallErrors = new Set(); function commonMustCall(f) { - const error = new Error("Expected function to be called"); + const error = new Error('Expected function to be called'); remainingMustCallErrors.add(error); return (...args) => { remainingMustCallErrors.delete(error); return f(...args); - } + }; } function assertCalledMustCalls() { try { @@ -51,26 +51,35 @@ export const utilInspect = { assert.strictEqual(util.inspect(false), 'false'); assert.strictEqual(util.inspect(''), "''"); assert.strictEqual(util.inspect('hello'), "'hello'"); - assert.strictEqual(util.inspect(function abc() {}), '[Function: abc]'); - assert.strictEqual(util.inspect(() => {}), '[Function (anonymous)]'); assert.strictEqual( - util.inspect(async function() {}), + util.inspect(function abc() {}), + '[Function: abc]' + ); + assert.strictEqual( + util.inspect(() => {}), + '[Function (anonymous)]' + ); + assert.strictEqual( + util.inspect(async function () {}), + '[AsyncFunction (anonymous)]' + ); + assert.strictEqual( + util.inspect(async () => {}), '[AsyncFunction (anonymous)]' ); - assert.strictEqual(util.inspect(async () => {}), '[AsyncFunction (anonymous)]'); // Special function inspection. { - const fn = (() => function*() {})(); - assert.strictEqual( - util.inspect(fn), - '[GeneratorFunction (anonymous)]' - ); + const fn = (() => function* () {})(); + assert.strictEqual(util.inspect(fn), '[GeneratorFunction (anonymous)]'); assert.strictEqual( util.inspect(async function* abc() {}), '[AsyncGeneratorFunction: abc]' ); - Object.setPrototypeOf(fn, Object.getPrototypeOf(async () => {})); + Object.setPrototypeOf( + fn, + Object.getPrototypeOf(async () => {}) + ); assert.strictEqual( util.inspect(fn), '[GeneratorFunction (anonymous)] AsyncFunction' @@ -82,7 +91,7 @@ export const utilInspect = { ); Object.defineProperty(fn, Symbol.toStringTag, { value: 'Foobar', - configurable: true + configurable: true, }); assert.strictEqual( util.inspect({ ['5']: fn }), @@ -107,7 +116,7 @@ export const utilInspect = { util.inspect(new Date('Sun, 14 Feb 2010 11:48:40 GMT')), new Date('2010-02-14T12:48:40+01:00').toISOString() ); - assert.strictEqual(util.inspect(new Date('')), (new Date('')).toString()); + assert.strictEqual(util.inspect(new Date('')), new Date('').toString()); assert.strictEqual(util.inspect('\n\x01'), "'\\n\\x01'"); assert.strictEqual( util.inspect(`${Array(75).fill(1)}'\n\x1d\n\x03\x85\x7f\x7e\x9f\xa0`), @@ -120,32 +129,55 @@ export const utilInspect = { assert.strictEqual(util.inspect([1, [2, 3]]), '[ 1, [ 2, 3 ] ]'); assert.strictEqual(util.inspect({}), '{}'); assert.strictEqual(util.inspect({ a: 1 }), '{ a: 1 }'); - assert.strictEqual(util.inspect({ a: function() {} }), '{ a: [Function: a] }'); + assert.strictEqual( + util.inspect({ a: function () {} }), + '{ a: [Function: a] }' + ); assert.strictEqual(util.inspect({ a: () => {} }), '{ a: [Function: a] }'); // eslint-disable-next-line func-name-matching - assert.strictEqual(util.inspect({ a: async function abc() {} }), - '{ a: [AsyncFunction: abc] }'); - assert.strictEqual(util.inspect({ a: async () => {} }), - '{ a: [AsyncFunction: a] }'); - assert.strictEqual(util.inspect({ a: function*() {} }), - '{ a: [GeneratorFunction: a] }'); + assert.strictEqual( + util.inspect({ a: async function abc() {} }), + '{ a: [AsyncFunction: abc] }' + ); + assert.strictEqual( + util.inspect({ a: async () => {} }), + '{ a: [AsyncFunction: a] }' + ); + assert.strictEqual( + util.inspect({ a: function* () {} }), + '{ a: [GeneratorFunction: a] }' + ); assert.strictEqual(util.inspect({ a: 1, b: 2 }), '{ a: 1, b: 2 }'); - assert.strictEqual(util.inspect({ 'a': {} }), '{ a: {} }'); - assert.strictEqual(util.inspect({ 'a': { 'b': 2 } }), '{ a: { b: 2 } }'); - assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }), - '{ a: { b: { c: [Object] } } }'); + assert.strictEqual(util.inspect({ a: {} }), '{ a: {} }'); + assert.strictEqual(util.inspect({ a: { b: 2 } }), '{ a: { b: 2 } }'); + assert.strictEqual( + util.inspect({ a: { b: { c: { d: 2 } } } }), + '{ a: { b: { c: [Object] } } }' + ); assert.strictEqual( - util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }, false, null), - '{\n a: { b: { c: { d: 2 } } }\n}'); - assert.strictEqual(util.inspect([1, 2, 3], true), '[ 1, 2, 3, [length]: 3 ]'); - assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 0), - '{ a: [Object] }'); - assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 1), - '{ a: { b: [Object] } }'); - assert.strictEqual(util.inspect({ 'a': { 'b': ['c'] } }, false, 1), - '{ a: { b: [Array] } }'); + util.inspect({ a: { b: { c: { d: 2 } } } }, false, null), + '{\n a: { b: { c: { d: 2 } } }\n}' + ); + assert.strictEqual( + util.inspect([1, 2, 3], true), + '[ 1, 2, 3, [length]: 3 ]' + ); + assert.strictEqual( + util.inspect({ a: { b: { c: 2 } } }, false, 0), + '{ a: [Object] }' + ); + assert.strictEqual( + util.inspect({ a: { b: { c: 2 } } }, false, 1), + '{ a: { b: [Object] } }' + ); + assert.strictEqual( + util.inspect({ a: { b: ['c'] } }, false, 1), + '{ a: { b: [Array] } }' + ); assert.strictEqual(util.inspect(new Uint8Array(0)), 'Uint8Array(0) []'); - assert(inspect(new Uint8Array(0), { showHidden: true }).includes('[buffer]')); + assert( + inspect(new Uint8Array(0), { showHidden: true }).includes('[buffer]') + ); assert.strictEqual( util.inspect( Object.create( @@ -166,7 +198,10 @@ export const utilInspect = { { const regexp = /regexp/; regexp.aprop = 42; - assert.strictEqual(util.inspect({ a: regexp }, false, 0), '{ a: /regexp/ }'); + assert.strictEqual( + util.inspect({ a: regexp }, false, 0), + '{ a: /regexp/ }' + ); } assert.match( @@ -186,34 +221,42 @@ export const utilInspect = { util.inspect(ab, showHidden), 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }' ); - assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + - ' buffer: ArrayBuffer {' + - ' [Uint8Contents]: <01 02 03 04>, byteLength: 4 }\n}'); + assert.strictEqual( + util.inspect(new DataView(ab, 1, 2), showHidden), + 'DataView {\n' + + ' byteLength: 2,\n' + + ' byteOffset: 1,\n' + + ' buffer: ArrayBuffer {' + + ' [Uint8Contents]: <01 02 03 04>, byteLength: 4 }\n}' + ); assert.strictEqual( util.inspect(ab, showHidden), 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }' ); - assert.strictEqual(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + - ' buffer: ArrayBuffer { [Uint8Contents]: ' + - '<01 02 03 04>, byteLength: 4 }\n}'); + assert.strictEqual( + util.inspect(dv, showHidden), + 'DataView {\n' + + ' byteLength: 2,\n' + + ' byteOffset: 1,\n' + + ' buffer: ArrayBuffer { [Uint8Contents]: ' + + '<01 02 03 04>, byteLength: 4 }\n}' + ); ab.x = 42; dv.y = 1337; - assert.strictEqual(util.inspect(ab, showHidden), - 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' + - 'byteLength: 4, x: 42 }'); - assert.strictEqual(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + - ' buffer: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' + - ' byteLength: 4, x: 42 },\n' + - ' y: 1337\n}'); + assert.strictEqual( + util.inspect(ab, showHidden), + 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' + + 'byteLength: 4, x: 42 }' + ); + assert.strictEqual( + util.inspect(dv, showHidden), + 'DataView {\n' + + ' byteLength: 2,\n' + + ' byteOffset: 1,\n' + + ' buffer: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' + + ' byteLength: 4, x: 42 },\n' + + ' y: 1337\n}' + ); } { @@ -221,22 +264,29 @@ export const utilInspect = { assert.strictEqual(ab.byteLength, 42); structuredClone(ab, { transfer: [ab] }); assert.strictEqual(ab.byteLength, 0); - assert.strictEqual(util.inspect(ab), - 'ArrayBuffer { (detached), byteLength: 0 }'); + assert.strictEqual( + util.inspect(ab), + 'ArrayBuffer { (detached), byteLength: 0 }' + ); } // Truncate output for ArrayBuffers using plural or singular bytes { const ab = new ArrayBuffer(3); - assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 2 }), - 'ArrayBuffer { [Uint8Contents]' + - ': <00 00 ... 1 more byte>, byteLength: 3 }'); - assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 1 }), - 'ArrayBuffer { [Uint8Contents]' + - ': <00 ... 2 more bytes>, byteLength: 3 }'); + assert.strictEqual( + util.inspect(ab, { showHidden: true, maxArrayLength: 2 }), + 'ArrayBuffer { [Uint8Contents]' + + ': <00 00 ... 1 more byte>, byteLength: 3 }' + ); + assert.strictEqual( + util.inspect(ab, { showHidden: true, maxArrayLength: 1 }), + 'ArrayBuffer { [Uint8Contents]' + + ': <00 ... 2 more bytes>, byteLength: 3 }' + ); } - [ Float32Array, + [ + Float32Array, Float64Array, Int16Array, Int32Array, @@ -244,7 +294,8 @@ export const utilInspect = { Uint16Array, Uint32Array, Uint8Array, - Uint8ClampedArray ].forEach((constructor) => { + Uint8ClampedArray, + ].forEach((constructor) => { const length = 2; const byteLength = length * constructor.BYTES_PER_ELEMENT; const array = new constructor(new ArrayBuffer(byteLength), 0, length); @@ -259,7 +310,8 @@ export const utilInspect = { ` [length]: ${length},\n` + ` [byteLength]: ${byteLength},\n` + ' [byteOffset]: 0,\n' + - ` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`); + ` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]` + ); assert.strictEqual( util.inspect(array, false), `${constructor.name}(${length}) [ 65, 97 ]` @@ -273,43 +325,66 @@ export const utilInspect = { } assert.strictEqual( - util.inspect(Object.create({}, { - visible: { value: 1, enumerable: true }, - hidden: { value: 2 } - }), { showHidden: true }), + util.inspect( + Object.create( + {}, + { + visible: { value: 1, enumerable: true }, + hidden: { value: 2 }, + } + ), + { showHidden: true } + ), '{ visible: 1, [hidden]: 2 }' ); // Objects without prototype. assert.strictEqual( - util.inspect(Object.create(null, { - name: { value: 'Tim', enumerable: true }, - hidden: { value: 'secret' } - }), { showHidden: true }), + util.inspect( + Object.create(null, { + name: { value: 'Tim', enumerable: true }, + hidden: { value: 'secret' }, + }), + { showHidden: true } + ), "[Object: null prototype] { name: 'Tim', [hidden]: 'secret' }" ); assert.strictEqual( - util.inspect(Object.create(null, { - name: { value: 'Tim', enumerable: true }, - hidden: { value: 'secret' } - })), + util.inspect( + Object.create(null, { + name: { value: 'Tim', enumerable: true }, + hidden: { value: 'secret' }, + }) + ), "[Object: null prototype] { name: 'Tim' }" ); // Dynamic properties. { assert.strictEqual( - util.inspect({ get readonly() { return 1; } }), - '{ readonly: [Getter] }'); + util.inspect({ + get readonly() { + return 1; + }, + }), + '{ readonly: [Getter] }' + ); assert.strictEqual( - util.inspect({ get readwrite() { return 1; }, set readwrite(val) {} }), - '{ readwrite: [Getter/Setter] }'); + util.inspect({ + get readwrite() { + return 1; + }, + set readwrite(val) {}, + }), + '{ readwrite: [Getter/Setter] }' + ); assert.strictEqual( // eslint-disable-next-line accessor-pairs util.inspect({ set writeonly(val) {} }), - '{ writeonly: [Setter] }'); + '{ writeonly: [Setter] }' + ); const value = {}; value.a = value; @@ -317,7 +392,7 @@ export const utilInspect = { const getterFn = { get one() { return null; - } + }, }; assert.strictEqual( util.inspect(getterFn, { getters: true }), @@ -328,24 +403,21 @@ export const utilInspect = { // Array with dynamic properties. { const value = [1, 2, 3]; - Object.defineProperty( - value, - 'growingLength', - { - enumerable: true, - get: function() { this.push(true); return this.length; } - } - ); - Object.defineProperty( - value, - '-1', - { - enumerable: true, - value: -1 - } + Object.defineProperty(value, 'growingLength', { + enumerable: true, + get: function () { + this.push(true); + return this.length; + }, + }); + Object.defineProperty(value, '-1', { + enumerable: true, + value: -1, + }); + assert.strictEqual( + util.inspect(value), + "[ 1, 2, 3, growingLength: [Getter], '-1': -1 ]" ); - assert.strictEqual(util.inspect(value), - "[ 1, 2, 3, growingLength: [Getter], '-1': -1 ]"); } // Array with inherited number properties. @@ -363,47 +435,63 @@ export const utilInspect = { assert.strictEqual( util.inspect(arr, { showHidden: true }), 'CustomArray(50) [\n' + - ' <49 empty items>,\n' + - " 'I win',\n" + - ' [length]: 50,\n' + - " '5': 'foo',\n" + - ' foo: true\n' + - ']' + ' <49 empty items>,\n' + + " 'I win',\n" + + ' [length]: 50,\n' + + " '5': 'foo',\n" + + ' foo: true\n' + + ']' ); } // Array with extra properties. { - const arr = [1, 2, 3, , ]; // eslint-disable-line no-sparse-arrays + const arr = [1, 2, 3, ,]; // eslint-disable-line no-sparse-arrays arr.foo = 'bar'; - assert.strictEqual(util.inspect(arr), - "[ 1, 2, 3, <1 empty item>, foo: 'bar' ]"); + assert.strictEqual( + util.inspect(arr), + "[ 1, 2, 3, <1 empty item>, foo: 'bar' ]" + ); const arr2 = []; - assert.strictEqual(util.inspect([], { showHidden: true }), '[ [length]: 0 ]'); + assert.strictEqual( + util.inspect([], { showHidden: true }), + '[ [length]: 0 ]' + ); arr2['00'] = 1; assert.strictEqual(util.inspect(arr2), "[ '00': 1 ]"); - assert.strictEqual(util.inspect(arr2, { showHidden: true }), - "[ [length]: 0, '00': 1 ]"); + assert.strictEqual( + util.inspect(arr2, { showHidden: true }), + "[ [length]: 0, '00': 1 ]" + ); arr2[1] = 0; assert.strictEqual(util.inspect(arr2), "[ <1 empty item>, 0, '00': 1 ]"); - assert.strictEqual(util.inspect(arr2, { showHidden: true }), - "[ <1 empty item>, 0, [length]: 2, '00': 1 ]"); + assert.strictEqual( + util.inspect(arr2, { showHidden: true }), + "[ <1 empty item>, 0, [length]: 2, '00': 1 ]" + ); delete arr2[1]; assert.strictEqual(util.inspect(arr2), "[ <2 empty items>, '00': 1 ]"); - assert.strictEqual(util.inspect(arr2, { showHidden: true }), - "[ <2 empty items>, [length]: 2, '00': 1 ]"); + assert.strictEqual( + util.inspect(arr2, { showHidden: true }), + "[ <2 empty items>, [length]: 2, '00': 1 ]" + ); arr2['01'] = 2; - assert.strictEqual(util.inspect(arr2), - "[ <2 empty items>, '00': 1, '01': 2 ]"); - assert.strictEqual(util.inspect(arr2, { showHidden: true }), - "[ <2 empty items>, [length]: 2, '00': 1, '01': 2 ]"); + assert.strictEqual( + util.inspect(arr2), + "[ <2 empty items>, '00': 1, '01': 2 ]" + ); + assert.strictEqual( + util.inspect(arr2, { showHidden: true }), + "[ <2 empty items>, [length]: 2, '00': 1, '01': 2 ]" + ); delete arr2['00']; arr2[0] = 0; - assert.strictEqual(util.inspect(arr2), - "[ 0, <1 empty item>, '01': 2 ]"); - assert.strictEqual(util.inspect(arr2, { showHidden: true }), - "[ 0, <1 empty item>, [length]: 2, '01': 2 ]"); + assert.strictEqual(util.inspect(arr2), "[ 0, <1 empty item>, '01': 2 ]"); + assert.strictEqual( + util.inspect(arr2, { showHidden: true }), + "[ 0, <1 empty item>, [length]: 2, '01': 2 ]" + ); delete arr2['01']; arr2[2 ** 32 - 2] = 'max'; arr2[2 ** 32 - 1] = 'too far'; @@ -424,33 +512,41 @@ export const utilInspect = { assert.strictEqual(util.inspect(arr), "[ '4294967296': true ]"); arr[0] = true; arr[10] = true; - assert.strictEqual(util.inspect(arr), - "[ true, <9 empty items>, true, '4294967296': true ]"); + assert.strictEqual( + util.inspect(arr), + "[ true, <9 empty items>, true, '4294967296': true ]" + ); arr[2 ** 32 - 2] = true; arr[2 ** 32 - 1] = true; arr[2 ** 32 + 1] = true; delete arr[0]; delete arr[10]; - assert.strictEqual(util.inspect(arr), - ['[', - '<4294967294 empty items>,', - 'true,', - "'4294967296': true,", - "'4294967295': true,", - "'4294967297': true\n]", - ].join('\n ')); + assert.strictEqual( + util.inspect(arr), + [ + '[', + '<4294967294 empty items>,', + 'true,', + "'4294967296': true,", + "'4294967295': true,", + "'4294967297': true\n]", + ].join('\n ') + ); } // Function with properties. { const value = () => {}; value.aprop = 42; - assert.strictEqual(util.inspect(value), '[Function: value] { aprop: 42 }'); + assert.strictEqual( + util.inspect(value), + '[Function: value] { aprop: 42 }' + ); } // Anonymous function with properties. { - const value = (() => function() {})(); + const value = (() => function () {})(); value.aprop = 42; assert.strictEqual( util.inspect(value), @@ -460,7 +556,7 @@ export const utilInspect = { // Regular expressions with properties. { - const value = /123/ig; + const value = /123/gi; value.aprop = 42; assert.strictEqual(util.inspect(value), '/123/gi { aprop: 42 }'); } @@ -469,8 +565,10 @@ export const utilInspect = { { const value = new Date('Sun, 14 Feb 2010 11:48:40 GMT'); value.aprop = 42; - assert.strictEqual(util.inspect(value), - '2010-02-14T11:48:40.000Z { aprop: 42 }'); + assert.strictEqual( + util.inspect(value), + '2010-02-14T11:48:40.000Z { aprop: 42 }' + ); } // Test positive/negative zero. @@ -502,28 +600,36 @@ export const utilInspect = { "[ 'foo', <1 empty item>, 'baz', <97 empty items>, ... 1 more item ]" ); // test 4 special case - assert.strictEqual(util.inspect(a, { - maxArrayLength: 2 - }), "[ 'foo', <1 empty item>, ... 99 more items ]"); + assert.strictEqual( + util.inspect(a, { + maxArrayLength: 2, + }), + "[ 'foo', <1 empty item>, ... 99 more items ]" + ); } // Test for property descriptors. { const getter = Object.create(null, { a: { - get: function() { return 'aaa'; } - } + get: function () { + return 'aaa'; + }, + }, }); const setter = Object.create(null, { - b: { // eslint-disable-line accessor-pairs - set: function() {} - } + b: { + // eslint-disable-line accessor-pairs + set: function () {}, + }, }); const getterAndSetter = Object.create(null, { c: { - get: function() { return 'ccc'; }, - set: function() {} - } + get: function () { + return 'ccc'; + }, + set: function () {}, + }, }); assert.strictEqual( util.inspect(getter, true), @@ -571,8 +677,14 @@ export const utilInspect = { const undefinedCause = new Error('', { cause: undefined }); undefinedCause.stack = ''; - assert.strictEqual(util.inspect(falsyCause1), '[Error] { [cause]: false }'); - assert.strictEqual(util.inspect(falsyCause2), '[Error] { [cause]: null }'); + assert.strictEqual( + util.inspect(falsyCause1), + '[Error] { [cause]: false }' + ); + assert.strictEqual( + util.inspect(falsyCause2), + '[Error] { [cause]: null }' + ); assert.strictEqual( util.inspect(undefinedCause), '[Error] { [cause]: undefined }' @@ -647,7 +759,10 @@ export const utilInspect = { // Reset the error, the stack is otherwise not recreated. err = new Error('foobar'); err.name = 'Unique'; - Object.defineProperty(err, 'stack', { value: err.stack, enumerable: true }); + Object.defineProperty(err, 'stack', { + value: err.stack, + enumerable: true, + }); out = util.inspect(err).split('\n'); assert.strictEqual(out[0], 'Unique: foobar'); assert(out[1].startsWith(' at ')); @@ -662,10 +777,14 @@ export const utilInspect = { { function BadCustomError(msg) { Error.call(this); - Object.defineProperty(this, 'message', - { value: msg, enumerable: false }); - Object.defineProperty(this, 'name', - { value: 'BadCustomError', enumerable: false }); + Object.defineProperty(this, 'message', { + value: msg, + enumerable: false, + }); + Object.defineProperty(this, 'name', { + value: 'BadCustomError', + enumerable: false, + }); } Object.setPrototypeOf(BadCustomError.prototype, Error.prototype); Object.setPrototypeOf(BadCustomError, Error); @@ -731,8 +850,13 @@ export const utilInspect = { // See https://github.com/nodejs/node-v0.x-archive/issues/2225 { const x = { [util.inspect.custom]: util.inspect }; - assert(util.inspect(x).includes( - '[Symbol(nodejs.util.inspect.custom)]: [Function: inspect] {\n')); + assert( + util + .inspect(x) + .includes( + '[Symbol(nodejs.util.inspect.custom)]: [Function: inspect] {\n' + ) + ); } // `util.inspect` should display the escaped value of a key. @@ -743,7 +867,7 @@ export const utilInspect = { '\\\\\\': 3, '\\\\\\\\': 4, '\n': 5, - '\r': 6 + '\r': 6, }; const y = ['a', 'b', 'c']; @@ -754,12 +878,11 @@ export const utilInspect = { assert.strictEqual( util.inspect(w), "{ '\\\\': 1, '\\\\\\\\': 2, '\\\\\\\\\\\\': 3, " + - "'\\\\\\\\\\\\\\\\': 4, '\\n': 5, '\\r': 6 }" + "'\\\\\\\\\\\\\\\\': 4, '\\n': 5, '\\r': 6 }" ); assert.strictEqual( util.inspect(y), - "[ 'a', 'b', 'c', '\\\\\\\\': 'd', " + - "'\\n': 'e', '\\r': 'f' ]" + "[ 'a', 'b', 'c', '\\\\\\\\': 'd', " + "'\\n': 'e', '\\r': 'f' ]" ); } @@ -767,7 +890,7 @@ export const utilInspect = { { const edgeChar = String.fromCharCode(0xd799); - for (let charCode = 0xD800; charCode < 0xDFFF; charCode++) { + for (let charCode = 0xd800; charCode < 0xdfff; charCode++) { const surrogate = String.fromCharCode(charCode); assert.strictEqual( @@ -786,14 +909,16 @@ export const utilInspect = { const highSurrogate = surrogate; const lowSurrogate = String.fromCharCode(charCode + 1024); assert( - !util.inspect( - `${edgeChar}${highSurrogate}${lowSurrogate}${edgeChar}` - ).includes('\\u') + !util + .inspect(`${edgeChar}${highSurrogate}${lowSurrogate}${edgeChar}`) + .includes('\\u') ); assert.strictEqual( - (util.inspect( - `${highSurrogate}${highSurrogate}${lowSurrogate}` - ).match(/\\u/g) ?? []).length, + ( + util + .inspect(`${highSurrogate}${highSurrogate}${lowSurrogate}`) + .match(/\\u/g) ?? [] + ).length, 1 ); } else { @@ -819,10 +944,11 @@ export const utilInspect = { assert.strictEqual( withColor, expect, - `util.inspect color for style ${style}`); + `util.inspect color for style ${style}` + ); } - testColorStyle('special', function() {}); + testColorStyle('special', function () {}); testColorStyle('number', 123.456); testColorStyle('boolean', true); testColorStyle('undefined', undefined); @@ -838,7 +964,10 @@ export const utilInspect = { // New API, accepts an "options" object. { const subject = { foo: 'bar', hello: 31, a: { b: { c: { d: 0 } } } }; - Object.defineProperty(subject, 'hidden', { enumerable: false, value: null }); + Object.defineProperty(subject, 'hidden', { + enumerable: false, + value: null, + }); assert.strictEqual( util.inspect(subject, { showHidden: false }).includes('hidden'), @@ -916,9 +1045,11 @@ export const utilInspect = { new Set(Object.keys(opts)) ); opts.showHidden = true; - return { [inspect.custom]: commonMustCall((depth, opts2) => { - assert.deepStrictEqual(clone, opts2); - }) }; + return { + [inspect.custom]: commonMustCall((depth, opts2) => { + assert.deepStrictEqual(clone, opts2); + }), + }; }); util.inspect(subject); @@ -929,7 +1060,7 @@ export const utilInspect = { subject[inspect] = () => ({ baz: 'quux' }); - assert.strictEqual(util.inspect(subject), '{ baz: \'quux\' }'); + assert.strictEqual(util.inspect(subject), "{ baz: 'quux' }"); subject[inspect] = (depth, opts) => { assert.strictEqual(opts.customInspectOptions, true); @@ -941,16 +1072,23 @@ export const utilInspect = { } { - const subject = { [util.inspect.custom]: commonMustCall((depth, opts) => { - assert.strictEqual(depth, null); - assert.strictEqual(opts.compact, true); - }) }; + const subject = { + [util.inspect.custom]: commonMustCall((depth, opts) => { + assert.strictEqual(depth, null); + assert.strictEqual(opts.compact, true); + }), + }; util.inspect(subject, { depth: null, compact: true }); } { // Returning `this` from a custom inspection function works. - const subject = { a: 123, [util.inspect.custom]() { return this; } }; + const subject = { + a: 123, + [util.inspect.custom]() { + return this; + }, + }; const UIC = 'nodejs.util.inspect.custom'; assert.strictEqual( util.inspect(subject), @@ -960,7 +1098,11 @@ export const utilInspect = { // Verify that it's possible to use the stylize function to manipulate input. assert.strictEqual( - util.inspect([1, 2, 3], { stylize() { return 'x'; } }), + util.inspect([1, 2, 3], { + stylize() { + return 'x'; + }, + }), '[ x, x, x ]' ); @@ -979,13 +1121,16 @@ export const utilInspect = { testLines([1, 2, 3, 4, 5, 6, 7]); testLines(bigArray); testLines({ foo: 'bar', baz: 35, b: { a: 35 } }); - testLines({ a: { a: 3, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1 }, b: 1 }); + testLines({ + a: { a: 3, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1 }, + b: 1, + }); testLines({ foo: 'bar', baz: 35, b: { a: 35 }, veryLongKey: 'very long value', - evenLongerKey: ['with even longer value in array'] + evenLongerKey: ['with even longer value in array'], }); } @@ -1034,7 +1179,10 @@ export const utilInspect = { const sym = Object(Symbol('foo')); sym.foo = 'bar'; - assert.strictEqual(util.inspect(sym), "[Symbol: Symbol(foo)] { foo: 'bar' }"); + assert.strictEqual( + util.inspect(sym), + "[Symbol: Symbol(foo)] { foo: 'bar' }" + ); const big = Object(BigInt(55)); big.foo = 'bar'; @@ -1060,10 +1208,10 @@ export const utilInspect = { '{ [Symbol(sym\\nbol)]: 42 }' ); - Object.defineProperty( - subject, - Symbol(), - { enumerable: false, value: 'non-enum' }); + Object.defineProperty(subject, Symbol(), { + enumerable: false, + value: 'non-enum', + }); assert.strictEqual(util.inspect(subject), '{ [Symbol(sym\\nbol)]: 42 }'); assert.strictEqual( util.inspect(subject, options), @@ -1073,15 +1221,23 @@ export const utilInspect = { subject = [1, 2, 3]; subject[Symbol('symbol')] = 42; - assert.strictEqual(util.inspect(subject), - '[ 1, 2, 3, [Symbol(symbol)]: 42 ]'); + assert.strictEqual( + util.inspect(subject), + '[ 1, 2, 3, [Symbol(symbol)]: 42 ]' + ); } // Test Set. { assert.strictEqual(util.inspect(new Set()), 'Set(0) {}'); - assert.strictEqual(util.inspect(new Set([1, 2, 3])), 'Set(3) { 1, 2, 3 }'); - assert.strictEqual(util.inspect(new Set([1, 2, 3]), { maxArrayLength: 1 }), 'Set(3) { 1, ... 2 more items }'); + assert.strictEqual( + util.inspect(new Set([1, 2, 3])), + 'Set(3) { 1, 2, 3 }' + ); + assert.strictEqual( + util.inspect(new Set([1, 2, 3]), { maxArrayLength: 1 }), + 'Set(3) { 1, ... 2 more items }' + ); const set = new Set(['foo']); set.bar = 42; assert.strictEqual( @@ -1094,20 +1250,42 @@ export const utilInspect = { { const set = new Set(); set.add(set); - assert.strictEqual(util.inspect(set), ' Set(1) { [Circular *1] }'); + assert.strictEqual( + util.inspect(set), + ' Set(1) { [Circular *1] }' + ); } // Test Map. { assert.strictEqual(util.inspect(new Map()), 'Map(0) {}'); - assert.strictEqual(util.inspect(new Map([[1, 'a'], [2, 'b'], [3, 'c']])), - "Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }"); - assert.strictEqual(util.inspect(new Map([[1, 'a'], [2, 'b'], [3, 'c']]), { maxArrayLength: 1 }), - "Map(3) { 1 => 'a', ... 2 more items }"); + assert.strictEqual( + util.inspect( + new Map([ + [1, 'a'], + [2, 'b'], + [3, 'c'], + ]) + ), + "Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }" + ); + assert.strictEqual( + util.inspect( + new Map([ + [1, 'a'], + [2, 'b'], + [3, 'c'], + ]), + { maxArrayLength: 1 } + ), + "Map(3) { 1 => 'a', ... 2 more items }" + ); const map = new Map([['foo', null]]); map.bar = 42; - assert.strictEqual(util.inspect(map, true), - "Map(1) { 'foo' => null, bar: 42 }"); + assert.strictEqual( + util.inspect(map, true), + "Map(1) { 'foo' => null, bar: 42 }" + ); } // Test circular Map. @@ -1142,9 +1320,9 @@ export const utilInspect = { assert.strictEqual( inspect(obj), ' {\n' + - ' a: [ [Circular *1] ],\n' + - ' b: { inner: [Circular *2], obj: [Circular *1] }\n' + - '}' + ' a: [ [Circular *1] ],\n' + + ' b: { inner: [Circular *2], obj: [Circular *1] }\n' + + '}' ); } @@ -1163,8 +1341,10 @@ export const utilInspect = { const promiseWithProperty = Promise.resolve('foo'); promiseWithProperty.bar = 42; - assert.strictEqual(util.inspect(promiseWithProperty), - "Promise { 'foo', bar: 42 }"); + assert.strictEqual( + util.inspect(promiseWithProperty), + "Promise { 'foo', bar: 42 }" + ); } // Make sure it doesn't choke on polyfills. Unlike Set/Map, there is no standard @@ -1172,7 +1352,9 @@ export const utilInspect = { // a bonafide native Promise. { const oldPromise = Promise; - globalThis.Promise = function() { this.bar = 42; }; + globalThis.Promise = function () { + this.bar = 42; + }; assert.strictEqual(util.inspect(new Promise()), '{ bar: 42 }'); globalThis.Promise = oldPromise; } @@ -1180,16 +1362,18 @@ export const utilInspect = { // Test Map iterators. { const map = new Map([['foo', 'bar']]); - assert.strictEqual(util.inspect(map.keys()), '[Map Iterator] { \'foo\' }'); + assert.strictEqual(util.inspect(map.keys()), "[Map Iterator] { 'foo' }"); const mapValues = map.values(); Object.defineProperty(mapValues, Symbol.toStringTag, { value: 'Foo' }); assert.strictEqual( util.inspect(mapValues), - '[Foo] [Map Iterator] { \'bar\' }' + "[Foo] [Map Iterator] { 'bar' }" ); map.set('A', 'B!'); - assert.strictEqual(util.inspect(map.entries(), { maxArrayLength: 1 }), - "[Map Entries] { [ 'foo', 'bar' ], ... 1 more item }"); + assert.strictEqual( + util.inspect(map.entries(), { maxArrayLength: 1 }), + "[Map Entries] { [ 'foo', 'bar' ], ... 1 more item }" + ); // Make sure the iterator doesn't get consumed. const keys = map.keys(); assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }"); @@ -1197,21 +1381,29 @@ export const utilInspect = { keys.extra = true; assert.strictEqual( util.inspect(keys, { maxArrayLength: 0 }), - '[Map Iterator] { ... 2 more items, extra: true }'); + '[Map Iterator] { ... 2 more items, extra: true }' + ); } // Test Set iterators. { const aSet = new Set([1]); - assert.strictEqual(util.inspect(aSet.entries(), { compact: false }), - '[Set Entries] {\n [\n 1,\n 1\n ]\n}'); + assert.strictEqual( + util.inspect(aSet.entries(), { compact: false }), + '[Set Entries] {\n [\n 1,\n 1\n ]\n}' + ); aSet.add(3); assert.strictEqual(util.inspect(aSet.keys()), '[Set Iterator] { 1, 3 }'); - assert.strictEqual(util.inspect(aSet.values()), '[Set Iterator] { 1, 3 }'); + assert.strictEqual( + util.inspect(aSet.values()), + '[Set Iterator] { 1, 3 }' + ); const setEntries = aSet.entries(); Object.defineProperty(setEntries, Symbol.toStringTag, { value: 'Foo' }); - assert.strictEqual(util.inspect(setEntries), - '[Foo] [Set Entries] { [ 1, 1 ], [ 3, 3 ] }'); + assert.strictEqual( + util.inspect(setEntries), + '[Foo] [Set Entries] { [ 1, 1 ], [ 3, 3 ] }' + ); // Make sure the iterator doesn't get consumed. const keys = aSet.keys(); Object.defineProperty(keys, Symbol.toStringTag, { value: null }); @@ -1220,7 +1412,8 @@ export const utilInspect = { keys.extra = true; assert.strictEqual( util.inspect(keys, { maxArrayLength: 1 }), - '[Set Iterator] { 1, ... 1 more item, extra: true }'); + '[Set Iterator] { 1, ... 1 more item, extra: true }' + ); } // Minimal inspection should still return as much information as possible about @@ -1238,7 +1431,7 @@ export const utilInspect = { Object.defineProperty(a, Symbol.toStringTag, { value: 'Foo', configurable: true, - writable: true + writable: true, }); assert.strictEqual(inspect(a, { depth: -1 }), '[Foo]'); delete a[Symbol.toStringTag]; @@ -1248,7 +1441,7 @@ export const utilInspect = { assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype] {}'); Object.defineProperty(a, Symbol.toStringTag, { value: 'ABC', - configurable: true + configurable: true, }); assert.strictEqual( inspect(a, { depth: -1 }), @@ -1256,7 +1449,7 @@ export const utilInspect = { ); Object.defineProperty(a, Symbol.toStringTag, { value: 'Foo', - configurable: true + configurable: true, }); assert.strictEqual( inspect(a, { depth: -1 }), @@ -1276,8 +1469,7 @@ export const utilInspect = { assert.strictEqual(line, end); } else { let expected = lineX.replace('X', i - 1); - if (i !== lines.length - 2) - expected += ','; + if (i !== lines.length - 2) expected += ','; assert.strictEqual(line, expected); } }); @@ -1297,11 +1489,12 @@ export const utilInspect = { checkAlignment(new Set(bigArray), 'Set(100) {', ' X', '}'); checkAlignment( new Map(bigArray.map((number) => [number, null])), - 'Map(100) {', ' X => null', '}' + 'Map(100) {', + ' X => null', + '}' ); } - // Test display of constructors. { class ObjectSubclass {} @@ -1315,20 +1508,32 @@ export const utilInspect = { const x = new ObjectSubclass(); x.foo = 42; - assert.strictEqual(util.inspect(x), - 'ObjectSubclass { foo: 42 }'); - assert.strictEqual(util.inspect(new ArraySubclass(1, 2, 3)), - 'ArraySubclass(3) [ 1, 2, 3 ]'); - assert.strictEqual(util.inspect(new SetSubclass([1, 2, 3])), - 'SetSubclass(3) [Set] { 1, 2, 3 }'); - assert.strictEqual(util.inspect(new MapSubclass([['foo', 42]])), - "MapSubclass(1) [Map] { 'foo' => 42 }"); - assert.strictEqual(util.inspect(new PromiseSubclass(() => {})), - 'PromiseSubclass [Promise] { }'); - assert.strictEqual(util.inspect(new SymbolNameClass()), - 'Symbol(name) {}'); - assert.strictEqual( - util.inspect({ a: { b: new ArraySubclass([1, [2], 3]) } }, { depth: 1 }), + assert.strictEqual(util.inspect(x), 'ObjectSubclass { foo: 42 }'); + assert.strictEqual( + util.inspect(new ArraySubclass(1, 2, 3)), + 'ArraySubclass(3) [ 1, 2, 3 ]' + ); + assert.strictEqual( + util.inspect(new SetSubclass([1, 2, 3])), + 'SetSubclass(3) [Set] { 1, 2, 3 }' + ); + assert.strictEqual( + util.inspect(new MapSubclass([['foo', 42]])), + "MapSubclass(1) [Map] { 'foo' => 42 }" + ); + assert.strictEqual( + util.inspect(new PromiseSubclass(() => {})), + 'PromiseSubclass [Promise] { }' + ); + assert.strictEqual( + util.inspect(new SymbolNameClass()), + 'Symbol(name) {}' + ); + assert.strictEqual( + util.inspect( + { a: { b: new ArraySubclass([1, [2], 3]) } }, + { depth: 1 } + ), '{ a: { b: [ArraySubclass] } }' ); assert.strictEqual( @@ -1348,9 +1553,15 @@ export const utilInspect = { arr[0][0][0] = { a: 2 }; assert.strictEqual(util.inspect(arr), '[ [ [ [Object] ] ] ]'); arr[0][0][0] = arr; - assert.strictEqual(util.inspect(arr), ' [ [ [ [Circular *1] ] ] ]'); + assert.strictEqual( + util.inspect(arr), + ' [ [ [ [Circular *1] ] ] ]' + ); arr[0][0][0] = arr[0][0]; - assert.strictEqual(util.inspect(arr), '[ [ [ [Circular *1] ] ] ]'); + assert.strictEqual( + util.inspect(arr), + '[ [ [ [Circular *1] ] ] ]' + ); } // Corner cases. @@ -1362,16 +1573,16 @@ export const utilInspect = { { const x = {}; Object.defineProperty(x, 'constructor', { - get: function() { + get: function () { throw new Error('should not access constructor'); }, - enumerable: true + enumerable: true, }); assert.strictEqual(util.inspect(x), '{ constructor: [Getter] }'); } { - const x = new function() {}; // eslint-disable-line new-parens + const x = new (function () {})(); // eslint-disable-line new-parens assert.strictEqual(util.inspect(x), '{}'); } @@ -1392,33 +1603,47 @@ export const utilInspect = { { const x = new Array(101).fill(); assert(util.inspect(x).endsWith('1 more item\n]')); - assert(!util.inspect(x, { maxArrayLength: 101 }).endsWith('1 more item\n]')); + assert( + !util.inspect(x, { maxArrayLength: 101 }).endsWith('1 more item\n]') + ); assert.strictEqual( util.inspect(x, { maxArrayLength: -1 }), '[ ... 101 more items ]' ); - assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }), - '[ ... 101 more items ]'); + assert.strictEqual( + util.inspect(x, { maxArrayLength: 0 }), + '[ ... 101 more items ]' + ); } { const x = Array(101); - assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }), - '[ ... 101 more items ]'); - assert(!util.inspect(x, { maxArrayLength: null }).endsWith('1 more item\n]')); - assert(!util.inspect( - x, { maxArrayLength: Infinity } - ).endsWith('1 more item ]')); + assert.strictEqual( + util.inspect(x, { maxArrayLength: 0 }), + '[ ... 101 more items ]' + ); + assert( + !util.inspect(x, { maxArrayLength: null }).endsWith('1 more item\n]') + ); + assert( + !util.inspect(x, { maxArrayLength: Infinity }).endsWith('1 more item ]') + ); } { const x = new Uint8Array(101); assert(util.inspect(x).endsWith('1 more item\n]')); assert(!util.inspect(x, { maxArrayLength: 101 }).includes('1 more item')); - assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }), - 'Uint8Array(101) [ ... 101 more items ]'); - assert(!util.inspect(x, { maxArrayLength: null }).includes('1 more item')); - assert(util.inspect(x, { maxArrayLength: Infinity }).endsWith(' 0, 0\n]')); + assert.strictEqual( + util.inspect(x, { maxArrayLength: 0 }), + 'Uint8Array(101) [ ... 101 more items ]' + ); + assert( + !util.inspect(x, { maxArrayLength: null }).includes('1 more item') + ); + assert( + util.inspect(x, { maxArrayLength: Infinity }).endsWith(' 0, 0\n]') + ); } { @@ -1470,24 +1695,29 @@ export const utilInspect = { JSON.stringify(oldOptions) ); - assert.throws(() => { - util.inspect.defaultOptions = null; - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "options" argument must be of type object. ' + - 'Received null' - } + assert.throws( + () => { + util.inspect.defaultOptions = null; + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "options" argument must be of type object. ' + 'Received null', + } ); - assert.throws(() => { - util.inspect.defaultOptions = 'bad'; - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "options" argument must be of type object. ' + - "Received type string ('bad')" - } + assert.throws( + () => { + util.inspect.defaultOptions = 'bad'; + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "options" argument must be of type object. ' + + "Received type string ('bad')", + } ); } @@ -1509,7 +1739,7 @@ export const utilInspect = { ); Object.defineProperty(obj, Symbol.toStringTag, { value: 'a', - enumerable: false + enumerable: false, }); assert.strictEqual(util.inspect(obj), 'Object [a] {}'); assert.strictEqual( @@ -1527,21 +1757,31 @@ export const utilInspect = { } } - assert.strictEqual(util.inspect( - Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } })), - '[Object: null prototype] [foo] {}'); + assert.strictEqual( + util.inspect( + Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } }) + ), + '[Object: null prototype] [foo] {}' + ); assert.strictEqual(util.inspect(new Foo()), "Foo [bar] { foo: 'bar' }"); assert.strictEqual( util.inspect(new (class extends Foo {})()), - "Foo [bar] { foo: 'bar' }"); + "Foo [bar] { foo: 'bar' }" + ); assert.strictEqual( - util.inspect(Object.create({ __proto__: Foo.prototype }, { - foo: { value: 'bar', enumerable: true } - })), - "Foo [bar] { foo: 'bar' }"); + util.inspect( + Object.create( + { __proto__: Foo.prototype }, + { + foo: { value: 'bar', enumerable: true }, + } + ) + ), + "Foo [bar] { foo: 'bar' }" + ); class ThrowingClass { get [Symbol.toStringTag]() { @@ -1549,7 +1789,10 @@ export const utilInspect = { } } - assert.throws(() => util.inspect(new ThrowingClass()), /toStringTag error/); + assert.throws( + () => util.inspect(new ThrowingClass()), + /toStringTag error/ + ); class NotStringClass { get [Symbol.toStringTag]() { @@ -1557,18 +1800,31 @@ export const utilInspect = { } } - assert.strictEqual(util.inspect(new NotStringClass()), - 'NotStringClass {}'); + assert.strictEqual( + util.inspect(new NotStringClass()), + 'NotStringClass {}' + ); } { const o = { - a: [1, 2, [[ - 'Lorem ipsum dolor\nsit amet,\tconsectetur adipiscing elit, sed do ' + - 'eiusmod tempor incididunt ut labore et dolore magna aliqua.', - 'test', - 'foo']], 4], - b: new Map([['za', 1], ['zb', 'test']]) + a: [ + 1, + 2, + [ + [ + 'Lorem ipsum dolor\nsit amet,\tconsectetur adipiscing elit, sed do ' + + 'eiusmod tempor incididunt ut labore et dolore magna aliqua.', + 'test', + 'foo', + ], + ], + 4, + ], + b: new Map([ + ['za', 1], + ['zb', 'test'], + ]), }; let out = util.inspect(o, { compact: true, depth: 5, breakLength: 80 }); @@ -1618,15 +1874,17 @@ export const utilInspect = { ].join('\n'); assert.strictEqual(out, expect); - out = util.inspect( - '12345678901234567890123456789012345678901234567890', - { compact: false, breakLength: 3 }); + out = util.inspect('12345678901234567890123456789012345678901234567890', { + compact: false, + breakLength: 3, + }); expect = "'12345678901234567890123456789012345678901234567890'"; assert.strictEqual(out, expect); out = util.inspect( '12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890', - { compact: false, breakLength: 3 }); + { compact: false, breakLength: 3 } + ); expect = [ "'12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890'", ].join('\n'); @@ -1643,7 +1901,11 @@ export const utilInspect = { ].join('\n'); assert.strictEqual(out, expect); - out = util.inspect(o, { compact: false, breakLength: 3, showHidden: true }); + out = util.inspect(o, { + compact: false, + breakLength: 3, + showHidden: true, + }); expect = [ '{', ' a: [Function (anonymous)] {', @@ -1680,7 +1942,11 @@ export const utilInspect = { const map = new Map([[promise, typed]]); map.set(set.values(), map.values()); - let out = util.inspect(map, { compact: false, showHidden: true, depth: 9 }); + let out = util.inspect(map, { + compact: false, + showHidden: true, + depth: 9, + }); let expected = [ 'Map(2) {', ' Promise {', @@ -1774,7 +2040,10 @@ export const utilInspect = { assert.strict.equal(out, expected); out = util.inspect(map, { - showHidden: true, depth: 9, breakLength: 4, compact: true + showHidden: true, + depth: 9, + breakLength: 4, + compact: true, }); expected = [ 'Map(2) {', @@ -1815,10 +2084,14 @@ export const utilInspect = { assert.strict.equal(out, expected); } - { // Test WeakMap && WeakSet + { + // Test WeakMap && WeakSet const obj = {}; const arr = []; - const weakMap = new WeakMap([[obj, arr], [arr, obj]]); + const weakMap = new WeakMap([ + [obj, arr], + [arr, obj], + ]); let out = util.inspect(weakMap, { showHidden: true }); let expect = 'WeakMap { [ [length]: 0 ] => {}, {} => [ [length]: 0 ] }'; assert.strictEqual(out, expect); @@ -1834,11 +2107,14 @@ export const utilInspect = { weakMap.extra = true; out = util.inspect(weakMap, { maxArrayLength: 1, showHidden: true }); // It is not possible to determine the output reliable. - expect = 'WeakMap { [ [length]: 0 ] => {}, ... 1 more item, extra: true }'; - let expectAlt = 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' + - 'extra: true }'; - assert(out === expect || out === expectAlt, - `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`); + expect = + 'WeakMap { [ [length]: 0 ] => {}, ... 1 more item, extra: true }'; + let expectAlt = + 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' + 'extra: true }'; + assert( + out === expect || out === expectAlt, + `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"` + ); // Test WeakSet arr.push(1); @@ -1859,16 +2135,22 @@ export const utilInspect = { out = util.inspect(weakSet, { maxArrayLength: 1, showHidden: true }); // It is not possible to determine the output reliable. expect = 'WeakSet { {}, ... 1 more item, extra: true }'; - expectAlt = 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, extra: true }'; - assert(out === expect || out === expectAlt, - `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`); + expectAlt = + 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, extra: true }'; + assert( + out === expect || out === expectAlt, + `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"` + ); // Keep references to the WeakMap entries, otherwise they could be GCed too // early. assert(obj && arr); } - { // Test argument objects. - const args = (function() { return arguments; })('a'); + { + // Test argument objects. + const args = (function () { + return arguments; + })('a'); assert.strictEqual(util.inspect(args), "[Arguments] { '0': 'a' }"); } @@ -1878,8 +2160,7 @@ export const utilInspect = { let head = list; // A linked list of length 100k should be inspectable in some way, even though // the real cutoff value is much lower than 100k. - for (let i = 0; i < 100000; i++) - head = head.next = {}; + for (let i = 0; i < 100000; i++) head = head.next = {}; assert.strictEqual( util.inspect(list), '{ next: { next: { next: [Object] } } }' @@ -1887,8 +2168,12 @@ export const utilInspect = { const longList = util.inspect(list, { depth: Infinity }); const match = longList.match(/next/g); assert(match.length > 500 && match.length < 10000); - assert(longList.includes('[Object: Inspection interrupted ' + - 'prematurely. Maximum call stack size exceeded.]')); + assert( + longList.includes( + '[Object: Inspection interrupted ' + + 'prematurely. Maximum call stack size exceeded.]' + ) + ); } // Do not escape single quotes if no double quote or backtick is present. @@ -1903,50 +2188,61 @@ export const utilInspect = { [class Foo extends TypeError {}, 'test'], [class Foo extends TypeError {}, undefined], [class BarError extends Error {}, 'test'], - [class BazError extends Error { - get name() { - return 'BazError'; - } - }, undefined], + [ + class BazError extends Error { + get name() { + return 'BazError'; + } + }, + undefined, + ], ].forEach(([Class, message], i) => { console.log('Test %i', i); const foo = new Class(message); const name = foo.name; const extra = Class.name.includes('Error') ? '' : ` [${foo.name}]`; assert( - util.inspect(foo).startsWith( - `${Class.name}${extra}${message ? `: ${message}` : '\n'}`), + util + .inspect(foo) + .startsWith( + `${Class.name}${extra}${message ? `: ${message}` : '\n'}` + ), util.inspect(foo) ); Object.defineProperty(foo, Symbol.toStringTag, { value: 'WOW', writable: true, - configurable: true + configurable: true, }); const stack = foo.stack; foo.stack = 'This is a stack'; - assert.strictEqual( - util.inspect(foo), - '[This is a stack]' - ); + assert.strictEqual(util.inspect(foo), '[This is a stack]'); foo.stack = stack; assert( - util.inspect(foo).startsWith( - `${Class.name} [WOW]${extra}${message ? `: ${message}` : '\n'}`), + util + .inspect(foo) + .startsWith( + `${Class.name} [WOW]${extra}${message ? `: ${message}` : '\n'}` + ), util.inspect(foo) ); Object.setPrototypeOf(foo, null); assert( - util.inspect(foo).startsWith( - `[${name}: null prototype] [WOW]${message ? `: ${message}` : '\n'}` - ), + util + .inspect(foo) + .startsWith( + `[${name}: null prototype] [WOW]${message ? `: ${message}` : '\n'}` + ), util.inspect(foo) ); foo.bar = true; delete foo[Symbol.toStringTag]; assert( - util.inspect(foo).startsWith( - `[${name}: null prototype]${message ? `: ${message}` : '\n'}`), + util + .inspect(foo) + .startsWith( + `[${name}: null prototype]${message ? `: ${message}` : '\n'}` + ), util.inspect(foo) ); foo.stack = 'This is a stack'; @@ -1965,25 +2261,45 @@ export const utilInspect = { [ /* eslint-disable spaced-comment, no-multi-spaces, brace-style */ // The whitespace is intentional. - [class { }, '[class (anonymous)]'], - [class extends Error { log() {} }, '[class (anonymous) extends Error]'], - [class A { constructor(a) { this.a = a; } log() { return this.a; } }, - '[class A]'], - [class - // Random { // comments /* */ are part of the toString() result - /* eslint-disable-next-line space-before-blocks */ - äß/**/extends/*{*/TypeError{}, '[class äß extends TypeError]'], + [class {}, '[class (anonymous)]'], + [ + class extends Error { + log() {} + }, + '[class (anonymous) extends Error]', + ], + [ + class A { + constructor(a) { + this.a = a; + } + log() { + return this.a; + } + }, + '[class A]', + ], + [ + class // Random { // comments /* */ are part of the toString() result + /* eslint-disable-next-line space-before-blocks */ + äß /**/ + extends /*{*/ TypeError {}, + '[class äß extends TypeError]', + ], /* The whitespace and new line is intended! */ // Foobar !!! - [class X extends /****/ Error - // More comments - {}, '[class X extends Error]'], + [ + class X extends /****/ Error { + // More comments + }, + '[class X extends Error]', + ], /* eslint-enable spaced-comment, no-multi-spaces, brace-style */ ].forEach(([clazz, string]) => { const inspected = util.inspect(clazz); assert.strictEqual(inspected, string); Object.defineProperty(clazz, Symbol.toStringTag, { - value: 'Woohoo' + value: 'Woohoo', }); const parts = inspected.slice(0, -1).split(' '); const [, name, ...rest] = parts; @@ -2010,7 +2326,9 @@ export const utilInspect = { ['[class', name, ...rest, 'extends [null prototype]]'].join(' ') ); Object.defineProperty(clazz, 'name', { value: 'Foo' }); - const res = ['[class', 'Foo', ...rest, 'extends [null prototype]]'].join(' '); + const res = ['[class', 'Foo', ...rest, 'extends [null prototype]]'].join( + ' ' + ); assert.strictEqual(util.inspect(clazz), res); clazz.foo = true; assert.strictEqual(util.inspect(clazz), `${res} { foo: true }`); @@ -2019,16 +2337,10 @@ export const utilInspect = { // "class" properties should not be detected as "class". { // eslint-disable-next-line space-before-function-paren - let obj = { class () {} }; - assert.strictEqual( - util.inspect(obj), - '{ class: [Function: class] }' - ); + let obj = { class() {} }; + assert.strictEqual(util.inspect(obj), '{ class: [Function: class] }'); obj = { class: () => {} }; - assert.strictEqual( - util.inspect(obj), - '{ class: [Function: class] }' - ); + assert.strictEqual(util.inspect(obj), '{ class: [Function: class] }'); obj = { ['class Foo {}']() {} }; assert.strictEqual( util.inspect(obj), @@ -2036,16 +2348,10 @@ export const utilInspect = { ); function Foo() {} Object.defineProperty(Foo, 'toString', { value: () => 'class Foo {}' }); - assert.strictEqual( - util.inspect(Foo), - '[Function: Foo]' - ); + assert.strictEqual(util.inspect(Foo), '[Function: Foo]'); function fn() {} Object.defineProperty(fn, 'name', { value: 'class Foo {}' }); - assert.strictEqual( - util.inspect(fn), - '[Function: class Foo {}]' - ); + assert.strictEqual(util.inspect(fn), '[Function: class Foo {}]'); } // Verify that throwing in valueOf and toString still produces nice results. @@ -2055,11 +2361,11 @@ export const utilInspect = { [new Number(55), '[Number: 55]'], [Object(BigInt(55)), '[BigInt: 55n]'], [Object(Symbol('foo')), '[Symbol: Symbol(foo)]'], - [function() {}, '[Function (anonymous)]'], + [function () {}, '[Function (anonymous)]'], [() => {}, '[Function (anonymous)]'], [[1, 2], '[ 1, 2 ]'], // eslint-disable-next-line no-sparse-arrays - [[, , 5, , , , ], '[ <2 empty items>, 5, <3 empty items> ]'], + [[, , 5, , , ,], '[ <2 empty items>, 5, <3 empty items> ]'], [{ a: 5 }, '{ a: 5 }'], [new Set([1, 2]), 'Set(2) { 1, 2 }'], [new Map([[1, 2]]), 'Map(1) { 1 => 2 }'], @@ -2067,7 +2373,10 @@ export const utilInspect = { [new Map([[1, 2]]).keys(), '[Map Iterator] { 1 }'], [new Date(2000), '1970-01-01T00:00:02.000Z'], [new Uint8Array(2), 'Uint8Array(2) [ 0, 0 ]'], - [new Promise((resolve) => setTimeout(resolve, 10)), 'Promise { }'], + [ + new Promise((resolve) => setTimeout(resolve, 10)), + 'Promise { }', + ], [new WeakSet(), 'WeakSet { }'], [new WeakMap(), 'WeakMap { }'], [/foobar/g, '/foobar/g'], @@ -2075,12 +2384,12 @@ export const utilInspect = { Object.defineProperty(value, 'valueOf', { get() { throw new Error('valueOf'); - } + }, }); Object.defineProperty(value, 'toString', { get() { throw new Error('toString'); - } + }, }); assert.strictEqual(util.inspect(value), expected); value.foo = 'bar'; @@ -2095,8 +2404,10 @@ export const utilInspect = { [[1, 3, 4], '[Array(3): null prototype] [ 1, 3, 4 ]'], [new Set([1, 2]), '[Set(2): null prototype] { 1, 2 }'], [new Map([[1, 2]]), '[Map(1): null prototype] { 1 => 2 }'], - [new Promise((resolve) => setTimeout(resolve, 10)), - '[Promise: null prototype] { }'], + [ + new Promise((resolve) => setTimeout(resolve, 10)), + '[Promise: null prototype] { }', + ], [new WeakSet(), '[WeakSet: null prototype] { }'], [new WeakMap(), '[WeakMap: null prototype] { }'], [new Uint8Array(2), '[Uint8Array(2): null prototype] [ 0, 0 ]'], @@ -2109,17 +2420,27 @@ export const utilInspect = { [new Float64Array(2), '[Float64Array(2): null prototype] [ 0, 0 ]'], [new BigInt64Array(2), '[BigInt64Array(2): null prototype] [ 0n, 0n ]'], [new BigUint64Array(2), '[BigUint64Array(2): null prototype] [ 0n, 0n ]'], - [new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' + - ' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' + - ' byteLength: undefined\n}'], - [new DataView(new ArrayBuffer(16)), - '[DataView: null prototype] {\n byteLength: undefined,\n ' + - 'byteOffset: undefined,\n buffer: undefined\n}'], - [new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' + - '{\n [Uint8Contents]: <00 00>,\n byteLength: undefined\n}'], + [ + new ArrayBuffer(16), + '[ArrayBuffer: null prototype] {\n' + + ' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' + + ' byteLength: undefined\n}', + ], + [ + new DataView(new ArrayBuffer(16)), + '[DataView: null prototype] {\n byteLength: undefined,\n ' + + 'byteOffset: undefined,\n buffer: undefined\n}', + ], + [ + new SharedArrayBuffer(2), + '[SharedArrayBuffer: null prototype] ' + + '{\n [Uint8Contents]: <00 00>,\n byteLength: undefined\n}', + ], [/foobar/, '[RegExp: null prototype] /foobar/'], - [new Date('Sun, 14 Feb 2010 11:48:40 GMT'), - '[Date: null prototype] 2010-02-14T11:48:40.000Z'], + [ + new Date('Sun, 14 Feb 2010 11:48:40 GMT'), + '[Date: null prototype] 2010-02-14T11:48:40.000Z', + ], ].forEach(([value, expected]) => { assert.strictEqual( util.inspect(Object.setPrototypeOf(value, null)), @@ -2137,9 +2458,11 @@ export const utilInspect = { [RegExp, ['foobar', 'g'], '/foobar/g'], [WeakSet, [[{}]], '{ }'], [WeakMap, [[[{}, {}]]], '{ }'], - [BigInt64Array, - [10], - '[\n 0n, 0n, 0n, 0n, 0n,\n 0n, 0n, 0n, 0n, 0n\n]'], + [ + BigInt64Array, + [10], + '[\n 0n, 0n, 0n, 0n, 0n,\n 0n, 0n, 0n, 0n, 0n\n]', + ], [Date, ['Sun, 14 Feb 2010 11:48:40 GMT'], '2010-02-14T11:48:40.000Z'], [Date, ['invalid_date'], 'Invalid Date'], ].forEach(([base, input, rawExpected]) => { @@ -2148,8 +2471,7 @@ export const utilInspect = { const symbol = value[Symbol.toStringTag]; const size = base.name.includes('Array') ? `(${input[0]})` : ''; const expected = `Foo${size} ${symbol ? `[${symbol}] ` : ''}${rawExpected}`; - const expectedWithoutProto = - `[${base.name}${size}: null prototype] ${rawExpected}`; + const expectedWithoutProto = `[${base.name}${size}: null prototype] ${rawExpected}`; assert.strictEqual(util.inspect(value), expected); value.foo = 'bar'; assert.notStrictEqual(util.inspect(value), expected); @@ -2172,9 +2494,14 @@ export const utilInspect = { assert.strictEqual(inspect(1n), '1n'); assert.strictEqual(inspect(Object(-1n)), '[BigInt: -1n]'); assert.strictEqual(inspect(Object(13n)), '[BigInt: 13n]'); - assert.strictEqual(inspect(new BigInt64Array([0n])), 'BigInt64Array(1) [ 0n ]'); assert.strictEqual( - inspect(new BigUint64Array([0n])), 'BigUint64Array(1) [ 0n ]'); + inspect(new BigInt64Array([0n])), + 'BigInt64Array(1) [ 0n ]' + ); + assert.strictEqual( + inspect(new BigUint64Array([0n])), + 'BigUint64Array(1) [ 0n ]' + ); // Verify non-enumerable keys get escaped. { @@ -2208,14 +2535,15 @@ export const utilInspect = { assert.strictEqual( inspect(rejection, { colors: true }), `Promise { \u001b[${special[0]}m\u001b[${special[1]}m ` + - `\u001b[${string[0]}m'Oh no!'\u001b[${string[1]}m }` + `\u001b[${string[0]}m'Oh no!'\u001b[${string[1]}m }` ); rejection.catch(() => {}); // Verify that aliases do not show up as key while checking `inspect.colors`. const colors = Object.keys(inspect.colors); - const aliases = Object.getOwnPropertyNames(inspect.colors) - .filter((c) => !colors.includes(c)); + const aliases = Object.getOwnPropertyNames(inspect.colors).filter( + (c) => !colors.includes(c) + ); assert(!colors.includes('grey')); assert(colors.includes('gray')); // Verify that all aliases are correctly mapped. @@ -2237,7 +2565,10 @@ export const utilInspect = { assert.deepStrictEqual(inspect.colors[`${color}Bright`], [90 + i, 39]); const bgColor = `bg${color[0].toUpperCase()}${color.slice(1)}`; assert.deepStrictEqual(inspect.colors[bgColor], [40 + i, 49]); - assert.deepStrictEqual(inspect.colors[`${bgColor}Bright`], [100 + i, 49]); + assert.deepStrictEqual(inspect.colors[`${bgColor}Bright`], [ + 100 + i, + 49, + ]); }); // Unknown colors are handled gracefully: @@ -2258,7 +2589,11 @@ export const utilInspect = { assert.strictEqual( inspect( { a200: 4, a100: 1, a102: 3, a101: 2 }, - { sorted(a, b) { return b.localeCompare(a); } } + { + sorted(a, b) { + return b.localeCompare(a); + }, + } ), '{ a200: 4, a102: 3, a101: 2, a100: 1 }' ); @@ -2280,7 +2615,9 @@ export const utilInspect = { // Manipulate the prototype in weird ways. { let obj = { a: true }; - let value = (function() { return function() {}; })(); + let value = (function () { + return function () {}; + })(); Object.setPrototypeOf(value, null); Object.setPrototypeOf(obj, value); assert.strictEqual( @@ -2321,10 +2658,9 @@ export const utilInspect = { StorageObject.prototype = { __proto__: null }; Object.setPrototypeOf(StorageObject.prototype, { __proto__: null }); - Object.setPrototypeOf( - Object.getPrototypeOf(StorageObject.prototype), - { __proto__: null } - ); + Object.setPrototypeOf(Object.getPrototypeOf(StorageObject.prototype), { + __proto__: null, + }); assert.strictEqual( util.inspect(new StorageObject()), 'StorageObject >> {}' @@ -2342,17 +2678,20 @@ export const utilInspect = { Object.setPrototypeOf(obj, null); Object.defineProperty(obj, Symbol.iterator, { value: iterator, - configurable: true + configurable: true, }); - assert.strictEqual(util.inspect(obj), '[Set(2): null prototype] { 1, 2 }'); + assert.strictEqual( + util.inspect(obj), + '[Set(2): null prototype] { 1, 2 }' + ); Object.defineProperty(obj, Symbol.iterator, { value: true, - configurable: true + configurable: true, }); Object.defineProperty(obj, 'size', { value: NaN, configurable: true, - enumerable: true + enumerable: true, }); assert.strictEqual( util.inspect(obj), @@ -2363,34 +2702,54 @@ export const utilInspect = { // Check the getter option. { let foo = 1; - const get = { get foo() { return foo; } }; + const get = { + get foo() { + return foo; + }, + }; const getset = { - get foo() { return foo; }, - set foo(val) { foo = val; }, - get inc() { return ++foo; } + get foo() { + return foo; + }, + set foo(val) { + foo = val; + }, + get inc() { + return ++foo; + }, + }; + const thrower = { + get foo() { + throw new Error('Oops'); + }, }; - const thrower = { get foo() { throw new Error('Oops'); } }; assert.strictEqual( inspect(get, { getters: true, colors: true }), '{ foo: \u001b[36m[Getter:\u001b[39m ' + - '\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }'); + '\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }' + ); assert.strictEqual( inspect(thrower, { getters: true }), - '{ foo: [Getter: ] }'); + '{ foo: [Getter: ] }' + ); assert.strictEqual( inspect(getset, { getters: true }), - '{ foo: [Getter/Setter: 1], inc: [Getter: 2] }'); + '{ foo: [Getter/Setter: 1], inc: [Getter: 2] }' + ); assert.strictEqual( inspect(getset, { getters: 'get' }), - '{ foo: [Getter/Setter], inc: [Getter: 3] }'); + '{ foo: [Getter/Setter], inc: [Getter: 3] }' + ); assert.strictEqual( inspect(getset, { getters: 'set' }), - '{ foo: [Getter/Setter: 3], inc: [Getter] }'); + '{ foo: [Getter/Setter: 3], inc: [Getter] }' + ); getset.foo = new Set([[{ a: true }, 2, {}], 'foobar', { x: 1 }]); assert.strictEqual( inspect(getset, { getters: true }), '{\n foo: [Getter/Setter] Set(3) { [ [Object], 2, {} ], ' + - "'foobar', { x: 1 } },\n inc: [Getter: NaN]\n}"); + "'foobar', { x: 1 } },\n inc: [Getter: NaN]\n}" + ); } // Check compact number mode. @@ -2402,15 +2761,11 @@ export const utilInspect = { c: { x: '10000000000000000 00000000000000000 '.repeat(1e1), d: 2, - e: 3 - } - } + e: 3, + }, + }, }, - b: [ - 1, - 2, - [ 1, 2, { a: 1, b: 2, c: 3 } ], - ], + b: [1, 2, [1, 2, { a: 1, b: 2, c: 3 }]], c: ['foo', 4, 444444], d: Array.from({ length: 101 }).map((e, i) => { return i % 2 === 0 ? i * i : i; @@ -2418,8 +2773,8 @@ export const utilInspect = { e: Array(6).fill('foobar'), f: Array(9).fill('foobar'), g: Array(21).fill('foobar baz'), - h: [100].concat(Array.from({ length: 9 }).map((e, n) => (n))), - long: Array(9).fill('This text is too long for grouping!') + h: [100].concat(Array.from({ length: 9 }).map((e, n) => n)), + long: Array(9).fill('This text is too long for grouping!'), }; let out = util.inspect(obj, { compact: 3, depth: 10, breakLength: 60 }); @@ -2507,9 +2862,8 @@ export const utilInspect = { assert.strictEqual(out, expected); obj = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 123456789, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 123456789, ]; out = util.inspect(obj, { compact: 3 }); @@ -2530,8 +2884,16 @@ export const utilInspect = { // Unicode support. あ has a length of one and a width of two. obj = [ - '123', '123', '123', '123', 'あああ', - '123', '123', '123', '123', 'あああ', + '123', + '123', + '123', + '123', + 'あああ', + '123', + '123', + '123', + '123', + 'あああ', ]; out = util.inspect(obj, { compact: 3 }); @@ -2573,16 +2935,20 @@ export const utilInspect = { x: 5, c: { d: 2, - e: 3 - } - } + e: 3, + }, + }, }, b: Array.from({ length: 9 }).map((e, n) => { return n % 2 === 0 ? 'foobar' : 'baz'; - }) + }), }; - out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true }); + out = util.inspect(obj, { + compact: 1, + breakLength: Infinity, + colors: true, + }); expected = [ '{', @@ -2602,7 +2968,11 @@ export const utilInspect = { assert.strictEqual(out, expected); obj = Array.from({ length: 60 }).map((e, i) => i); - out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true }); + out = util.inspect(obj, { + compact: 1, + breakLength: Infinity, + colors: true, + }); expected = [ '[', @@ -2627,55 +2997,131 @@ export const utilInspect = { assert.strictEqual(out, expected); out = util.inspect([1, 2, 3, 4], { compact: 1, colors: true }); - expected = '[ \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, ' + + expected = + '[ \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, ' + '\u001b[33m3\u001b[39m, \u001b[33m4\u001b[39m ]'; assert.strictEqual(out, expected); obj = [ - 'Object', 'Function', 'Array', - 'Number', 'parseFloat', 'parseInt', - 'Infinity', 'NaN', 'undefined', - 'Boolean', 'String', 'Symbol', - 'Date', 'Promise', 'RegExp', - 'Error', 'EvalError', 'RangeError', - 'ReferenceError', 'SyntaxError', 'TypeError', - 'URIError', 'JSON', 'Math', - 'console', 'Intl', 'ArrayBuffer', - 'Uint8Array', 'Int8Array', 'Uint16Array', - 'Int16Array', 'Uint32Array', 'Int32Array', - 'Float32Array', 'Float64Array', 'Uint8ClampedArray', - 'BigUint64Array', 'BigInt64Array', 'DataView', - 'Map', 'BigInt', 'Set', - 'WeakMap', 'WeakSet', 'Proxy', - 'Reflect', 'decodeURI', 'decodeURIComponent', - 'encodeURI', 'encodeURIComponent', 'escape', - 'unescape', 'eval', 'isFinite', - 'isNaN', 'SharedArrayBuffer', 'Atomics', - 'globalThis', 'WebAssembly', 'global', - 'process', 'Buffer', 'URL', - 'URLSearchParams', 'TextEncoder', 'TextDecoder', - 'clearInterval', 'clearTimeout', 'setInterval', - 'setTimeout', 'queueMicrotask', 'clearImmediate', - 'setImmediate', 'module', 'require', - 'assert', 'async_hooks', 'buffer', - 'child_process', 'cluster', 'crypto', - 'dgram', 'dns', 'domain', - 'events', 'fs', 'http', - 'http2', 'https', 'inspector', - 'net', 'os', 'path', - 'perf_hooks', 'punycode', 'querystring', - 'readline', 'repl', 'stream', - 'string_decoder', 'tls', 'trace_events', - 'tty', 'url', 'v8', - 'vm', 'worker_threads', 'zlib', - '_', '_error', 'util', + 'Object', + 'Function', + 'Array', + 'Number', + 'parseFloat', + 'parseInt', + 'Infinity', + 'NaN', + 'undefined', + 'Boolean', + 'String', + 'Symbol', + 'Date', + 'Promise', + 'RegExp', + 'Error', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + 'JSON', + 'Math', + 'console', + 'Intl', + 'ArrayBuffer', + 'Uint8Array', + 'Int8Array', + 'Uint16Array', + 'Int16Array', + 'Uint32Array', + 'Int32Array', + 'Float32Array', + 'Float64Array', + 'Uint8ClampedArray', + 'BigUint64Array', + 'BigInt64Array', + 'DataView', + 'Map', + 'BigInt', + 'Set', + 'WeakMap', + 'WeakSet', + 'Proxy', + 'Reflect', + 'decodeURI', + 'decodeURIComponent', + 'encodeURI', + 'encodeURIComponent', + 'escape', + 'unescape', + 'eval', + 'isFinite', + 'isNaN', + 'SharedArrayBuffer', + 'Atomics', + 'globalThis', + 'WebAssembly', + 'global', + 'process', + 'Buffer', + 'URL', + 'URLSearchParams', + 'TextEncoder', + 'TextDecoder', + 'clearInterval', + 'clearTimeout', + 'setInterval', + 'setTimeout', + 'queueMicrotask', + 'clearImmediate', + 'setImmediate', + 'module', + 'require', + 'assert', + 'async_hooks', + 'buffer', + 'child_process', + 'cluster', + 'crypto', + 'dgram', + 'dns', + 'domain', + 'events', + 'fs', + 'http', + 'http2', + 'https', + 'inspector', + 'net', + 'os', + 'path', + 'perf_hooks', + 'punycode', + 'querystring', + 'readline', + 'repl', + 'stream', + 'string_decoder', + 'tls', + 'trace_events', + 'tty', + 'url', + 'v8', + 'vm', + 'worker_threads', + 'zlib', + '_', + '_error', + 'util', ]; - out = util.inspect( - obj, - { compact: 3, breakLength: 80, maxArrayLength: 250 } - ); + out = util.inspect(obj, { + compact: 3, + breakLength: 80, + maxArrayLength: 250, + }); expected = [ '[', " 'Object', 'Function', 'Array',", @@ -2724,9 +3170,12 @@ export const utilInspect = { { // Cross platform checks. const err = new Error('foo'); - util.inspect(err, { colors: true }).split('\n').forEach((line, i) => { - assert(i < 2 || line.startsWith('\u001b[90m')); - }); + util + .inspect(err, { colors: true }) + .split('\n') + .forEach((line, i) => { + assert(i < 2 || line.startsWith('\u001b[90m')); + }); } // Inspect prototype properties. @@ -2770,22 +3219,22 @@ export const utilInspect = { assert.strictEqual( inspect(bar, { showHidden: true, getters: true, colors: false }), 'Bar(0) [Map] {\n' + - ' prop: true,\n' + - ' prop2: true,\n' + - ' abc: true,\n' + - " [xyz]: [Getter: 'YES!'],\n" + - ' [def]: [Getter/Setter: false]\n' + - '}' + ' prop: true,\n' + + ' prop2: true,\n' + + ' abc: true,\n' + + " [xyz]: [Getter: 'YES!'],\n" + + ' [def]: [Getter/Setter: false]\n' + + '}' ); assert.strictEqual( inspect(bar, { showHidden: true, getters: false, colors: true }), 'Bar(0) [Map] {\n' + - ' prop: \x1B[33mtrue\x1B[39m,\n' + - ' prop2: \x1B[33mtrue\x1B[39m,\n' + - ' abc: \x1B[33mtrue\x1B[39m,\n' + - ' \x1B[2m[xyz]: \x1B[36m[Getter]\x1B[39m\x1B[22m,\n' + - ' \x1B[2m[def]: \x1B[36m[Getter/Setter]\x1B[39m\x1B[22m\n' + - '}' + ' prop: \x1B[33mtrue\x1B[39m,\n' + + ' prop2: \x1B[33mtrue\x1B[39m,\n' + + ' abc: \x1B[33mtrue\x1B[39m,\n' + + ' \x1B[2m[xyz]: \x1B[36m[Getter]\x1B[39m\x1B[22m,\n' + + ' \x1B[2m[def]: \x1B[36m[Getter/Setter]\x1B[39m\x1B[22m\n' + + '}' ); const obj = { __proto__: { abc: true, def: 5, toString() {} } }; @@ -2796,35 +3245,32 @@ export const utilInspect = { ); assert.strictEqual( - inspect(Object.getPrototypeOf(bar), { showHidden: true, getters: true }), + inspect(Object.getPrototypeOf(bar), { + showHidden: true, + getters: true, + }), ' Foo [Map] {\n' + - ' [constructor]: [class Bar extends Foo] {\n' + - ' [length]: 0,\n' + - " [name]: 'Bar',\n" + - ' [prototype]: [Circular *1],\n' + - ' [Symbol(Symbol.species)]: [Getter: ]\n" + - ' },\n' + - " [xyz]: [Getter: 'YES!'],\n" + - ' [Symbol(nodejs.util.inspect.custom)]: ' + + ' },\n' + + " [xyz]: [Getter: 'YES!'],\n" + + ' [Symbol(nodejs.util.inspect.custom)]: ' + '[Function: [nodejs.util.inspect.custom]] {\n' + - ' [length]: 0,\n' + - " [name]: '[nodejs.util.inspect.custom]'\n" + - ' },\n' + - ' [abc]: [Getter: true],\n' + - ' [def]: [Getter/Setter: false]\n' + - ' }' + ' [length]: 0,\n' + + " [name]: '[nodejs.util.inspect.custom]'\n" + + ' },\n' + + ' [abc]: [Getter: true],\n' + + ' [def]: [Getter/Setter: false]\n' + + ' }' ); - assert.strictEqual( - inspect(Object.getPrototypeOf(bar)), - 'Foo [Map] {}' - ); + assert.strictEqual(inspect(Object.getPrototypeOf(bar)), 'Foo [Map] {}'); - assert.strictEqual( - inspect(Object.getPrototypeOf(new Foo())), - 'Map {}' - ); + assert.strictEqual(inspect(Object.getPrototypeOf(new Foo())), 'Map {}'); } // Check that prototypes with a null prototype are inspectable. @@ -2835,7 +3281,10 @@ export const utilInspect = { const object = {}; object.constructor = Func; - assert.strictEqual(util.inspect(object), '{ constructor: [Function: Func] }'); + assert.strictEqual( + util.inspect(object), + '{ constructor: [Function: Func] }' + ); } // Test changing util.inspect.colors colors and aliases. @@ -2865,8 +3314,10 @@ export const utilInspect = { // Truncate output for Primitives with 1 character left { - assert.strictEqual(util.inspect('bl', { maxStringLength: 1 }), - "'b'... 1 more character"); + assert.strictEqual( + util.inspect('bl', { maxStringLength: 1 }), + "'b'... 1 more character" + ); } { @@ -2932,7 +3383,7 @@ export const utilInspect = { " [Symbol(Symbol.toStringTag)]: 'GeneratorFunction'\n" + '}'; const actual = util.inspect(generator, { showHidden: true }); - assert.ok((actual == expected1) || (actual == expected2)); + assert.ok(actual == expected1 || actual == expected2); // Reset so we don't pollute other tests Object.setPrototypeOf(generatorPrototype, originalProtoOfProto); @@ -2945,16 +3396,16 @@ export const utilInspect = { assert.strictEqual( util.inspect(obj, { breakLength: 256 }), '[\n' + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + - " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf'\n" + - ']' + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" + + " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf'\n" + + ']' ); } @@ -2998,14 +3449,8 @@ export const utilInspect = { 'BigInt64Array(1) [ 9_100_000_100n ]' ); - assert.strictEqual( - util.inspect(123456789), - '123_456_789' - ); - assert.strictEqual( - util.inspect(123456789n), - '123_456_789n' - ); + assert.strictEqual(util.inspect(123456789), '123_456_789'); + assert.strictEqual(util.inspect(123456789n), '123_456_789n'); util.inspect.defaultOptions.numericSeparator = numericSeparator; @@ -3022,15 +3467,18 @@ export const utilInspect = { // Regression test for https://github.com/nodejs/node/issues/41244 { - assert.strictEqual(util.inspect({ - get [Symbol.iterator]() { - throw new Error(); - } - }), '{ [Symbol(Symbol.iterator)]: [Getter] }'); + assert.strictEqual( + util.inspect({ + get [Symbol.iterator]() { + throw new Error(); + }, + }), + '{ [Symbol(Symbol.iterator)]: [Getter] }' + ); } assertCalledMustCalls(); - } + }, }; export const utilInspectProxy = { @@ -3049,22 +3497,48 @@ export const utilInspectProxy = { } } return [1, 2, 3]; - } + }, }; const handler = { - getPrototypeOf() { throw new Error('getPrototypeOf'); }, - setPrototypeOf() { throw new Error('setPrototypeOf'); }, - isExtensible() { throw new Error('isExtensible'); }, - preventExtensions() { throw new Error('preventExtensions'); }, - getOwnPropertyDescriptor() { throw new Error('getOwnPropertyDescriptor'); }, - defineProperty() { throw new Error('defineProperty'); }, - has() { throw new Error('has'); }, - get() { throw new Error('get'); }, - set() { throw new Error('set'); }, - deleteProperty() { throw new Error('deleteProperty'); }, - ownKeys() { throw new Error('ownKeys'); }, - apply() { throw new Error('apply'); }, - construct() { throw new Error('construct'); } + getPrototypeOf() { + throw new Error('getPrototypeOf'); + }, + setPrototypeOf() { + throw new Error('setPrototypeOf'); + }, + isExtensible() { + throw new Error('isExtensible'); + }, + preventExtensions() { + throw new Error('preventExtensions'); + }, + getOwnPropertyDescriptor() { + throw new Error('getOwnPropertyDescriptor'); + }, + defineProperty() { + throw new Error('defineProperty'); + }, + has() { + throw new Error('has'); + }, + get() { + throw new Error('get'); + }, + set() { + throw new Error('set'); + }, + deleteProperty() { + throw new Error('deleteProperty'); + }, + ownKeys() { + throw new Error('ownKeys'); + }, + apply() { + throw new Error('apply'); + }, + construct() { + throw new Error('construct'); + }, }; proxyObj = new Proxy(target, handler); @@ -3080,7 +3554,7 @@ export const utilInspectProxy = { assert.strictEqual(util.inspect(r.proxy), ''); assert.strictEqual( util.inspect(r, { showProxy: true }), - '{ proxy: , revoke: [Function (anonymous)] }', + '{ proxy: , revoke: [Function (anonymous)] }' ); assert.strictEqual(util.format('%s', r.proxy), ''); @@ -3088,23 +3562,23 @@ export const utilInspectProxy = { assert.strictEqual( util.inspect(proxyObj, opts), 'Proxy [\n' + - ' [ 1, 2, 3 ],\n' + - ' {\n' + - ' getPrototypeOf: [Function: getPrototypeOf],\n' + - ' setPrototypeOf: [Function: setPrototypeOf],\n' + - ' isExtensible: [Function: isExtensible],\n' + - ' preventExtensions: [Function: preventExtensions],\n' + - ' getOwnPropertyDescriptor: [Function: getOwnPropertyDescriptor],\n' + - ' defineProperty: [Function: defineProperty],\n' + - ' has: [Function: has],\n' + - ' get: [Function: get],\n' + - ' set: [Function: set],\n' + - ' deleteProperty: [Function: deleteProperty],\n' + - ' ownKeys: [Function: ownKeys],\n' + - ' apply: [Function: apply],\n' + - ' construct: [Function: construct]\n' + - ' }\n' + - ']' + ' [ 1, 2, 3 ],\n' + + ' {\n' + + ' getPrototypeOf: [Function: getPrototypeOf],\n' + + ' setPrototypeOf: [Function: setPrototypeOf],\n' + + ' isExtensible: [Function: isExtensible],\n' + + ' preventExtensions: [Function: preventExtensions],\n' + + ' getOwnPropertyDescriptor: [Function: getOwnPropertyDescriptor],\n' + + ' defineProperty: [Function: defineProperty],\n' + + ' has: [Function: has],\n' + + ' get: [Function: get],\n' + + ' set: [Function: set],\n' + + ' deleteProperty: [Function: deleteProperty],\n' + + ' ownKeys: [Function: ownKeys],\n' + + ' apply: [Function: apply],\n' + + ' construct: [Function: construct]\n' + + ' }\n' + + ']' ); // Inspecting a proxy without the showProxy option set to true should not @@ -3123,25 +3597,30 @@ export const utilInspectProxy = { const expected0 = '{}'; const expected1 = 'Proxy [ {}, {} ]'; const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]'; - const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]'; - const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]'; - const expected5 = 'Proxy [\n ' + - 'Proxy [ Proxy [ Proxy [Array], {} ], Proxy [ {}, {} ] ],\n' + - ' Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [Array], {} ] ]' + - '\n]'; - const expected6 = 'Proxy [\n' + - ' Proxy [\n' + - ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + - ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + - ' ],\n' + - ' Proxy [\n' + - ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + - ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + - ' ]\n' + - ']'; + const expected3 = + 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]'; + const expected4 = + 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]'; + const expected5 = + 'Proxy [\n ' + + 'Proxy [ Proxy [ Proxy [Array], {} ], Proxy [ {}, {} ] ],\n' + + ' Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [Array], {} ] ]' + + '\n]'; + const expected6 = + 'Proxy [\n' + + ' Proxy [\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + + ' ],\n' + + ' Proxy [\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + + ' ]\n' + + ']'; assert.strictEqual( util.inspect(proxy1, { showProxy: 1, depth: null }), - expected1); + expected1 + ); assert.strictEqual(util.inspect(proxy2, opts), expected2); assert.strictEqual(util.inspect(proxy3, opts), expected3); assert.strictEqual(util.inspect(proxy4, opts), expected4); @@ -3177,13 +3656,13 @@ export const utilInspectProxy = { }, apply() { return proxy11; - } + }, }); const expected10 = '[Function (anonymous)]'; const expected11 = '[Function (anonymous)]'; assert.strictEqual(util.inspect(proxy10), expected10); assert.strictEqual(util.inspect(proxy11), expected11); - } + }, }; export const utilInspectGettersAccessingThis = { @@ -3202,13 +3681,10 @@ export const utilInspectGettersAccessingThis = { const result = inspect(new X(), { getters: true, - showHidden: true + showHidden: true, }); - assert.strictEqual( - result, - 'X { _y: 123, [y]: [Getter: 123] }' - ); + assert.strictEqual(result, 'X { _y: 123, [y]: [Getter: 123] }'); } // Regression test for https://github.com/nodejs/node/issues/37054 @@ -3234,21 +3710,20 @@ export const utilInspectGettersAccessingThis = { const result = inspect(new B(), { depth: 1, getters: true, - showHidden: true + showHidden: true, }); assert.strictEqual( result, ' B {\n' + - ' A: A { B: [Circular *1], [b]: [Getter] [Circular *1] },\n' + - ' [a]: [Getter] A { B: [Circular *1], [b]: [Getter] [Circular *1] }\n' + - '}', + ' A: A { B: [Circular *1], [b]: [Getter] [Circular *1] },\n' + + ' [a]: [Getter] A { B: [Circular *1], [b]: [Getter] [Circular *1] }\n' + + '}' ); } - } + }, }; - export const utilFormat = { // test-util-format.js async test(ctrl, env, ctx) { @@ -3315,7 +3790,11 @@ export const utilFormat = { assert.strictEqual( util.format( // eslint-disable-next-line no-loss-of-precision - '%d %s %i', 118059162071741130342, 118059162071741130342, 123_123_123), + '%d %s %i', + 118059162071741130342, + 118059162071741130342, + 123_123_123 + ), '118_059_162_071_741_140_000 118_059_162_071_741_140_000 123_123_123' ); @@ -3349,10 +3828,7 @@ export const utilFormat = { assert.strictEqual(util.format('%i', Symbol()), 'NaN'); assert.strictEqual(util.format('%i %i', 42, 43), '42 43'); assert.strictEqual(util.format('%i %i', 42), '42 %i'); - assert.strictEqual( - util.format('%i', 1180591620717411303424), - '1' - ); + assert.strictEqual(util.format('%i', 1180591620717411303424), '1'); assert.strictEqual( util.format('%i', 1180591620717411303424n), '1180591620717411303424n' @@ -3375,7 +3851,10 @@ export const utilFormat = { assert.strictEqual( util.formatWithOptions( { numericSeparator: true }, - '%i %d', 1180591620717411303424n, 12345678901234567890123n), + '%i %d', + 1180591620717411303424n, + 12345678901234567890123n + ), '1_180_591_620_717_411_303_424n 12_345_678_901_234_567_890_123n' ); @@ -3412,15 +3891,29 @@ export const utilFormat = { assert.strictEqual(util.format('%s', Symbol('foo')), 'Symbol(foo)'); assert.strictEqual(util.format('%s', true), 'true'); assert.strictEqual(util.format('%s', { a: [1, 2, 3] }), '{ a: [Array] }'); - assert.strictEqual(util.format('%s', { toString() { return 'Foo'; } }), 'Foo'); + assert.strictEqual( + util.format('%s', { + toString() { + return 'Foo'; + }, + }), + 'Foo' + ); assert.strictEqual(util.format('%s', { toString: 5 }), '{ toString: 5 }'); - assert.strictEqual(util.format('%s', () => 5), '() => 5'); + assert.strictEqual( + util.format('%s', () => 5), + '() => 5' + ); assert.strictEqual(util.format('%s', Infinity), 'Infinity'); assert.strictEqual(util.format('%s', -Infinity), '-Infinity'); // String format specifier including `toString` properties on the prototype. { - class Foo { toString() { return 'Bar'; } } + class Foo { + toString() { + return 'Bar'; + } + } assert.strictEqual(util.format('%s', new Foo()), 'Bar'); assert.strictEqual( util.format('%s', Object.setPrototypeOf(new Foo(), null)), @@ -3429,9 +3922,13 @@ export const utilFormat = { globalThis.Foo = Foo; assert.strictEqual(util.format('%s', new Foo()), 'Bar'); delete globalThis.Foo; - class Bar { abc = true; } + class Bar { + abc = true; + } assert.strictEqual(util.format('%s', new Bar()), 'Bar { abc: true }'); - class Foobar extends Array { aaa = true; } + class Foobar extends Array { + aaa = true; + } assert.strictEqual( util.format('%s', new Foobar(5)), 'Foobar(5) [ <5 empty items>, aaa: true ]' @@ -3441,7 +3938,7 @@ export const utilFormat = { class B extends Foo {} function C() {} - C.prototype.toString = function() { + C.prototype.toString = function () { return 'Custom'; }; @@ -3450,47 +3947,26 @@ export const utilFormat = { } D.prototype = { __proto__: C.prototype }; - assert.strictEqual( - util.format('%s', new B()), - 'Bar' - ); - assert.strictEqual( - util.format('%s', new C()), - 'Custom' - ); - assert.strictEqual( - util.format('%s', new D()), - 'Custom' - ); + assert.strictEqual(util.format('%s', new B()), 'Bar'); + assert.strictEqual(util.format('%s', new C()), 'Custom'); + assert.strictEqual(util.format('%s', new D()), 'Custom'); D.prototype.constructor = D; - assert.strictEqual( - util.format('%s', new D()), - 'Custom' - ); + assert.strictEqual(util.format('%s', new D()), 'Custom'); D.prototype.constructor = null; - assert.strictEqual( - util.format('%s', new D()), - 'Custom' - ); + assert.strictEqual(util.format('%s', new D()), 'Custom'); D.prototype.constructor = { name: 'Foobar' }; - assert.strictEqual( - util.format('%s', new D()), - 'Custom' - ); + assert.strictEqual(util.format('%s', new D()), 'Custom'); Object.defineProperty(D.prototype, 'constructor', { get() { throw new Error(); }, - configurable: true + configurable: true, }); - assert.strictEqual( - util.format('%s', new D()), - 'Custom' - ); + assert.strictEqual(util.format('%s', new D()), 'Custom'); assert.strictEqual( util.format('%s', { __proto__: null }), @@ -3509,110 +3985,119 @@ export const utilFormat = { const obj = { foo: 'bar', foobar: 1, - func: function() {} + func: function () {}, }; const nestedObj = { foo: 'bar', foobar: { foo: 'bar', - func: function() {} - } + func: function () {}, + }, }; const nestedObj2 = { foo: 'bar', foobar: 1, - func: [{ a: function() {} }] + func: [{ a: function () {} }], }; assert.strictEqual(util.format('%o'), '%o'); assert.strictEqual(util.format('%o', 42), '42'); - assert.strictEqual(util.format('%o', 'foo'), '\'foo\''); + assert.strictEqual(util.format('%o', 'foo'), "'foo'"); assert.strictEqual( util.format('%o', obj), '{\n' + - ' foo: \'bar\',\n' + - ' foobar: 1,\n' + - ' func: [Function: func] {\n' + - ' [length]: 0,\n' + - ' [name]: \'func\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - '}'); + " foo: 'bar',\n" + + ' foobar: 1,\n' + + ' func: [Function: func] {\n' + + ' [length]: 0,\n' + + " [name]: 'func',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + '}' + ); assert.strictEqual( util.format('%o', nestedObj2), '{\n' + - ' foo: \'bar\',\n' + - ' foobar: 1,\n' + - ' func: [\n' + - ' {\n' + - ' a: [Function: a] {\n' + - ' [length]: 0,\n' + - ' [name]: \'a\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - ' },\n' + - ' [length]: 1\n' + - ' ]\n' + - '}'); + " foo: 'bar',\n" + + ' foobar: 1,\n' + + ' func: [\n' + + ' {\n' + + ' a: [Function: a] {\n' + + ' [length]: 0,\n' + + " [name]: 'a',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + ' },\n' + + ' [length]: 1\n' + + ' ]\n' + + '}' + ); assert.strictEqual( util.format('%o', nestedObj), '{\n' + - ' foo: \'bar\',\n' + - ' foobar: {\n' + - ' foo: \'bar\',\n' + - ' func: [Function: func] {\n' + - ' [length]: 0,\n' + - ' [name]: \'func\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - ' }\n' + - '}'); + " foo: 'bar',\n" + + ' foobar: {\n' + + " foo: 'bar',\n" + + ' func: [Function: func] {\n' + + ' [length]: 0,\n' + + " [name]: 'func',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + ' }\n' + + '}' + ); assert.strictEqual( util.format('%o %o', obj, obj), '{\n' + - ' foo: \'bar\',\n' + - ' foobar: 1,\n' + - ' func: [Function: func] {\n' + - ' [length]: 0,\n' + - ' [name]: \'func\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - '} {\n' + - ' foo: \'bar\',\n' + - ' foobar: 1,\n' + - ' func: [Function: func] {\n' + - ' [length]: 0,\n' + - ' [name]: \'func\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - '}'); + " foo: 'bar',\n" + + ' foobar: 1,\n' + + ' func: [Function: func] {\n' + + ' [length]: 0,\n' + + " [name]: 'func',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + '} {\n' + + " foo: 'bar',\n" + + ' foobar: 1,\n' + + ' func: [Function: func] {\n' + + ' [length]: 0,\n' + + " [name]: 'func',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + '}' + ); assert.strictEqual( util.format('%o %o', obj), '{\n' + - ' foo: \'bar\',\n' + - ' foobar: 1,\n' + - ' func: [Function: func] {\n' + - ' [length]: 0,\n' + - ' [name]: \'func\',\n' + - ' [prototype]: { [constructor]: [Circular *1] }\n' + - ' }\n' + - '} %o'); + " foo: 'bar',\n" + + ' foobar: 1,\n' + + ' func: [Function: func] {\n' + + ' [length]: 0,\n' + + " [name]: 'func',\n" + + ' [prototype]: { [constructor]: [Circular *1] }\n' + + ' }\n' + + '} %o' + ); assert.strictEqual(util.format('%O'), '%O'); assert.strictEqual(util.format('%O', 42), '42'); - assert.strictEqual(util.format('%O', 'foo'), '\'foo\''); + assert.strictEqual(util.format('%O', 'foo'), "'foo'"); assert.strictEqual( util.format('%O', obj), - '{ foo: \'bar\', foobar: 1, func: [Function: func] }'); + "{ foo: 'bar', foobar: 1, func: [Function: func] }" + ); assert.strictEqual( util.format('%O', nestedObj), - '{ foo: \'bar\', foobar: { foo: \'bar\', func: [Function: func] } }'); + "{ foo: 'bar', foobar: { foo: 'bar', func: [Function: func] } }" + ); assert.strictEqual( util.format('%O %O', obj, obj), - '{ foo: \'bar\', foobar: 1, func: [Function: func] } ' + - '{ foo: \'bar\', foobar: 1, func: [Function: func] }'); + "{ foo: 'bar', foobar: 1, func: [Function: func] } " + + "{ foo: 'bar', foobar: 1, func: [Function: func] }" + ); assert.strictEqual( util.format('%O %O', obj), - '{ foo: \'bar\', foobar: 1, func: [Function: func] } %O'); + "{ foo: 'bar', foobar: 1, func: [Function: func] } %O" + ); // Various format specifiers assert.strictEqual(util.format('%%s%s', 'foo'), '%sfoo'); @@ -3622,7 +4107,10 @@ export const utilFormat = { assert.strictEqual(util.format('%s:%i', 'foo'), 'foo:%i'); assert.strictEqual(util.format('%s:%f', 'foo'), 'foo:%f'); assert.strictEqual(util.format('%s:%s', 'foo', 'bar'), 'foo:bar'); - assert.strictEqual(util.format('%s:%s', 'foo', 'bar', 'baz'), 'foo:bar baz'); + assert.strictEqual( + util.format('%s:%s', 'foo', 'bar', 'baz'), + 'foo:bar baz' + ); assert.strictEqual(util.format('%%%s%%', 'hi'), '%hi%'); assert.strictEqual(util.format('%%%s%%%%', 'hi'), '%hi%%'); assert.strictEqual(util.format('%sbc%%def', 'a'), 'abc%def'); @@ -3642,16 +4130,20 @@ export const utilFormat = { assert.strictEqual(util.format('o: %o, a: %o', {}), 'o: {}, a: %o'); assert.strictEqual(util.format('o: %O, a: %O'), 'o: %O, a: %O'); - // Invalid format specifiers assert.strictEqual(util.format('a% b', 'x'), 'a% b x'); - assert.strictEqual(util.format('percent: %d%, fraction: %d', 10, 0.1), - 'percent: 10%, fraction: 0.1'); + assert.strictEqual( + util.format('percent: %d%, fraction: %d', 10, 0.1), + 'percent: 10%, fraction: 0.1' + ); assert.strictEqual(util.format('abc%', 1), 'abc% 1'); // Additional arguments after format specifiers assert.strictEqual(util.format('%i', 1, 'number'), '1 number'); - assert.strictEqual(util.format('%i', 1, () => {}), '1 [Function (anonymous)]'); + assert.strictEqual( + util.format('%i', 1, () => {}), + '1 [Function (anonymous)]' + ); // %c from https://console.spec.whatwg.org/ assert.strictEqual(util.format('%c'), '%c'); @@ -3669,10 +4161,12 @@ export const utilFormat = { const o = { toJSON() { throw new Error('Not a circular object but still not serializable'); - } + }, }; - assert.throws(() => util.format('%j', o), - /^Error: Not a circular object but still not serializable$/); + assert.throws( + () => util.format('%j', o), + /^Error: Not a circular object but still not serializable$/ + ); } // Errors @@ -3681,10 +4175,14 @@ export const utilFormat = { class CustomError extends Error { constructor(msg) { super(); - Object.defineProperty(this, 'message', - { value: msg, enumerable: false }); - Object.defineProperty(this, 'name', - { value: 'CustomError', enumerable: false }); + Object.defineProperty(this, 'message', { + value: msg, + enumerable: false, + }); + Object.defineProperty(this, 'name', { + value: 'CustomError', + enumerable: false, + }); Error.captureStackTrace(this, CustomError); } } @@ -3693,23 +4191,32 @@ export const utilFormat = { // Doesn't capture stack trace function BadCustomError(msg) { Error.call(this); - Object.defineProperty(this, 'message', - { value: msg, enumerable: false }); - Object.defineProperty(this, 'name', - { value: 'BadCustomError', enumerable: false }); + Object.defineProperty(this, 'message', { value: msg, enumerable: false }); + Object.defineProperty(this, 'name', { + value: 'BadCustomError', + enumerable: false, + }); } Object.setPrototypeOf(BadCustomError.prototype, Error.prototype); Object.setPrototypeOf(BadCustomError, Error); - assert.strictEqual(util.format(new BadCustomError('foo')), - '[BadCustomError: foo]'); + assert.strictEqual( + util.format(new BadCustomError('foo')), + '[BadCustomError: foo]' + ); // The format of arguments should not depend on type of the first argument assert.strictEqual(util.format('1', '1'), '1 1'); assert.strictEqual(util.format(1, '1'), '1 1'); assert.strictEqual(util.format('1', 1), '1 1'); assert.strictEqual(util.format(1, -0), '1 -0'); - assert.strictEqual(util.format('1', () => {}), '1 [Function (anonymous)]'); - assert.strictEqual(util.format(1, () => {}), '1 [Function (anonymous)]'); + assert.strictEqual( + util.format('1', () => {}), + '1 [Function (anonymous)]' + ); + assert.strictEqual( + util.format(1, () => {}), + '1 [Function (anonymous)]' + ); assert.strictEqual(util.format('1', "'"), "1 '"); assert.strictEqual(util.format(1, "'"), "1 '"); assert.strictEqual(util.format('1', 'number'), '1 number'); @@ -3721,7 +4228,13 @@ export const utilFormat = { assert.strictEqual( util.formatWithOptions( { colors: true }, - true, undefined, Symbol(), 1, 5n, null, 'foobar' + true, + undefined, + Symbol(), + 1, + 5n, + null, + 'foobar' ), '\u001b[33mtrue\u001b[39m ' + '\u001b[90mundefined\u001b[39m ' + @@ -3738,30 +4251,27 @@ export const utilFormat = { ); assert.strictEqual( - util.formatWithOptions( - { colors: true, compact: 3 }, - '%s', [ 1, { a: true }] - ), + util.formatWithOptions({ colors: true, compact: 3 }, '%s', [ + 1, + { a: true }, + ]), '[ 1, [Object] ]' ); - [ - undefined, - null, - false, - 5n, - 5, - 'test', - Symbol(), - ].forEach((invalidOptions) => { - assert.throws(() => { - util.formatWithOptions(invalidOptions, { a: true }); - }, { - code: 'ERR_INVALID_ARG_TYPE', - message: /"inspectOptions".+object/ - }); - }); - } + [undefined, null, false, 5n, 5, 'test', Symbol()].forEach( + (invalidOptions) => { + assert.throws( + () => { + util.formatWithOptions(invalidOptions, { a: true }); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + message: /"inspectOptions".+object/, + } + ); + } + ); + }, }; export const utilInspectError = { @@ -3783,7 +4293,7 @@ export const utilInspectError = { util.inspect(err, { compact: true, breakLength: 5 }), /{ Error: foo\nbar\n at .+\n foo: 'bar' }/ ); - } + }, }; export const logTest = { @@ -3801,7 +4311,7 @@ export const logTest = { assert.strictEqual(args[2], 'test'); console.log = original; - } + }, }; export const aborted = { @@ -3810,10 +4320,11 @@ export const aborted = { await util.aborted(signal, {}); await assert.rejects(util.aborted({}, {}), { - message: 'The "signal" argument must be an instance of AbortSignal. ' + - 'Received an instance of Object' + message: + 'The "signal" argument must be an instance of AbortSignal. ' + + 'Received an instance of Object', }); - } + }, }; export const debuglog = { @@ -3829,5 +4340,5 @@ export const debuglog = { assert.strictEqual(args[0], 'TEST: hello\n'); console.log = original; - } + }, }; diff --git a/src/workerd/api/node/tests/zlib-nodejs-test.js b/src/workerd/api/node/tests/zlib-nodejs-test.js index 69c5a48533c..e9ac7714a66 100644 --- a/src/workerd/api/node/tests/zlib-nodejs-test.js +++ b/src/workerd/api/node/tests/zlib-nodejs-test.js @@ -1,12 +1,7 @@ -import { - strictEqual, - throws, - deepStrictEqual -} from 'node:assert'; +import { strictEqual, throws, deepStrictEqual } from 'node:assert'; import { Buffer } from 'node:buffer'; import { crc32, constants } from 'node:zlib'; - // The following test data comes from // https://github.com/zlib-ng/zlib-ng/blob/5401b24/test/test_crc32.cc // test_crc32.cc -- crc32 unit test @@ -19,7 +14,7 @@ export const crc32Test = { const tests = [ [0x0, 0x0, 0, 0x0], [0xffffffff, 0x0, 0, 0x0], - [0x0, 0x0, 255, 0x0], /* BZ 174799. */ + [0x0, 0x0, 255, 0x0] /* BZ 174799. */, [0x0, 0x0, 256, 0x0], [0x0, 0x0, 257, 0x0], [0x0, 0x0, 32767, 0x0], @@ -94,15 +89,24 @@ export const crc32Test = { [0x0, ':(_*&%/[[}+,?#$&*+#[([*-/#;%(]', 30, 0x6c80c388], [0x0, '{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:', 30, 0xd54d977d], [0x0, '_{$*,}(&,@.)):=!/%(&(,,-?$}}}!', 30, 0xe3966ad5], - [0x0, - 'e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL', - 100, 0xe7c71db9], - [0x0, - 'r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)', - 100, 0xeaa52777], - [0x0, - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&', - 100, 0xcd472048], + [ + 0x0, + 'e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL', + 100, + 0xe7c71db9, + ], + [ + 0x0, + 'r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)', + 100, + 0xeaa52777, + ], + [ + 0x0, + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&', + 100, + 0xcd472048, + ], [0x7a30360d, 'abacus', 6, 0xf8655a84], [0x6fd767ee, 'backlog', 7, 0x1ed834b1], [0xefeb7589, 'campfire', 8, 0x686cfca], @@ -168,163 +172,197 @@ export const crc32Test = { [0x569e613c, ':(_*&%/[[}+,?#$&*+#[([*-/#;%(]', 30, 0x7e2b0a66], [0x36aa61da, '{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:', 30, 0xb3430dc7], [0xf67222df, '_{$*,}(&,@.)):=!/%(&(,,-?$}}}!', 30, 0x626c17a], - [0x74b34fd3, - 'e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL', - 100, 0xccf98060], - [0x351fd770, - 'r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)', - 100, 0xd8b95312], - [0xc45aef77, - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&', - 100, 0xbb1c9912], - [0xc45aef77, - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + - 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + [ + 0x74b34fd3, + 'e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL', + 100, + 0xccf98060, + ], + [ + 0x351fd770, + 'r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)', + 100, + 0xd8b95312, + ], + [ + 0xc45aef77, 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&', - 600, 0x888AFA5B], + 100, + 0xbb1c9912, + ], + [ + 0xc45aef77, + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&' + + 'h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&', + 600, + 0x888afa5b, + ], ]; - for (const [ crc, data, len, expected ] of tests) { + for (const [crc, data, len, expected] of tests) { if (data === 0) { continue; } const buf = Buffer.from(data, 'utf8'); strictEqual(buf.length, len); - strictEqual(crc32(buf, crc), expected, - `crc32('${data}', ${crc}) in buffer is not ${expected}`); - strictEqual(crc32(buf.toString(), crc), expected, - `crc32('${data}', ${crc}) in string is not ${expected}`); + strictEqual( + crc32(buf, crc), + expected, + `crc32('${data}', ${crc}) in buffer is not ${expected}` + ); + strictEqual( + crc32(buf.toString(), crc), + expected, + `crc32('${data}', ${crc}) in string is not ${expected}` + ); if (crc === 0) { - strictEqual(crc32(buf), expected, - `crc32('${data}') in buffer is not ${expected}`); - strictEqual(crc32(buf.toString()), expected, - `crc32('${data}') in string is not ${expected}`); + strictEqual( + crc32(buf), + expected, + `crc32('${data}') in buffer is not ${expected}` + ); + strictEqual( + crc32(buf.toString()), + expected, + `crc32('${data}') in string is not ${expected}` + ); } } [undefined, null, true, 1, () => {}, {}].forEach((invalid) => { - throws(() => { crc32(invalid); }, { code: 'ERR_INVALID_ARG_TYPE' }); + throws( + () => { + crc32(invalid); + }, + { code: 'ERR_INVALID_ARG_TYPE' } + ); }); [null, true, () => {}, {}].forEach((invalid) => { - throws(() => { crc32('test', invalid); }, { code: 'ERR_INVALID_ARG_TYPE' }); + throws( + () => { + crc32('test', invalid); + }, + { code: 'ERR_INVALID_ARG_TYPE' } + ); }); - } -} + }, +}; export const constantsTest = { test() { deepStrictEqual(Object.keys(constants).sort(), [ - "BROTLI_DECODE", - "BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES", - "BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP", - "BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES", - "BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1", - "BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2", - "BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS", - "BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET", - "BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1", - "BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2", - "BROTLI_DECODER_ERROR_FORMAT_CL_SPACE", - "BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT", - "BROTLI_DECODER_ERROR_FORMAT_DICTIONARY", - "BROTLI_DECODER_ERROR_FORMAT_DISTANCE", - "BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE", - "BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE", - "BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE", - "BROTLI_DECODER_ERROR_FORMAT_PADDING_1", - "BROTLI_DECODER_ERROR_FORMAT_PADDING_2", - "BROTLI_DECODER_ERROR_FORMAT_RESERVED", - "BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET", - "BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME", - "BROTLI_DECODER_ERROR_FORMAT_TRANSFORM", - "BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS", - "BROTLI_DECODER_ERROR_INVALID_ARGUMENTS", - "BROTLI_DECODER_ERROR_UNREACHABLE", - "BROTLI_DECODER_NEEDS_MORE_INPUT", - "BROTLI_DECODER_NEEDS_MORE_OUTPUT", - "BROTLI_DECODER_NO_ERROR", - "BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION", - "BROTLI_DECODER_PARAM_LARGE_WINDOW", - "BROTLI_DECODER_RESULT_ERROR", - "BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT", - "BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT", - "BROTLI_DECODER_RESULT_SUCCESS", - "BROTLI_DECODER_SUCCESS", - "BROTLI_DEFAULT_MODE", - "BROTLI_DEFAULT_QUALITY", - "BROTLI_DEFAULT_WINDOW", - "BROTLI_ENCODE", - "BROTLI_LARGE_MAX_WINDOW_BITS", - "BROTLI_MAX_INPUT_BLOCK_BITS", - "BROTLI_MAX_QUALITY", - "BROTLI_MAX_WINDOW_BITS", - "BROTLI_MIN_INPUT_BLOCK_BITS", - "BROTLI_MIN_QUALITY", - "BROTLI_MIN_WINDOW_BITS", - "BROTLI_MODE_FONT", - "BROTLI_MODE_GENERIC", - "BROTLI_MODE_TEXT", - "BROTLI_OPERATION_EMIT_METADATA", - "BROTLI_OPERATION_FINISH", - "BROTLI_OPERATION_FLUSH", - "BROTLI_OPERATION_PROCESS", - "BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING", - "BROTLI_PARAM_LARGE_WINDOW", - "BROTLI_PARAM_LGBLOCK", - "BROTLI_PARAM_LGWIN", - "BROTLI_PARAM_MODE", - "BROTLI_PARAM_NDIRECT", - "BROTLI_PARAM_NPOSTFIX", - "BROTLI_PARAM_QUALITY", - "BROTLI_PARAM_SIZE_HINT", - "DEFLATE", - "DEFLATERAW", - "GUNZIP", - "GZIP", - "INFLATE", - "INFLATERAW", - "UNZIP", - "ZLIB_VERNUM", - "Z_BEST_COMPRESSION", - "Z_BEST_SPEED", - "Z_BLOCK", - "Z_BUF_ERROR", - "Z_DATA_ERROR", - "Z_DEFAULT_CHUNK", - "Z_DEFAULT_COMPRESSION", - "Z_DEFAULT_LEVEL", - "Z_DEFAULT_MEMLEVEL", - "Z_DEFAULT_STRATEGY", - "Z_DEFAULT_WINDOWBITS", - "Z_ERRNO", - "Z_FILTERED", - "Z_FINISH", - "Z_FIXED", - "Z_FULL_FLUSH", - "Z_HUFFMAN_ONLY", - "Z_MAX_CHUNK", - "Z_MAX_LEVEL", - "Z_MAX_MEMLEVEL", - "Z_MAX_WINDOWBITS", - "Z_MEM_ERROR", - "Z_MIN_CHUNK", - "Z_MIN_LEVEL", - "Z_MIN_MEMLEVEL", - "Z_MIN_WINDOWBITS", - "Z_NEED_DICT", - "Z_NO_COMPRESSION", - "Z_NO_FLUSH", - "Z_OK", - "Z_PARTIAL_FLUSH", - "Z_RLE", - "Z_STREAM_END", - "Z_STREAM_ERROR", - "Z_SYNC_FLUSH", - "Z_VERSION_ERROR" + 'BROTLI_DECODE', + 'BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES', + 'BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP', + 'BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES', + 'BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1', + 'BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2', + 'BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS', + 'BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET', + 'BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1', + 'BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2', + 'BROTLI_DECODER_ERROR_FORMAT_CL_SPACE', + 'BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT', + 'BROTLI_DECODER_ERROR_FORMAT_DICTIONARY', + 'BROTLI_DECODER_ERROR_FORMAT_DISTANCE', + 'BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE', + 'BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE', + 'BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE', + 'BROTLI_DECODER_ERROR_FORMAT_PADDING_1', + 'BROTLI_DECODER_ERROR_FORMAT_PADDING_2', + 'BROTLI_DECODER_ERROR_FORMAT_RESERVED', + 'BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET', + 'BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME', + 'BROTLI_DECODER_ERROR_FORMAT_TRANSFORM', + 'BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS', + 'BROTLI_DECODER_ERROR_INVALID_ARGUMENTS', + 'BROTLI_DECODER_ERROR_UNREACHABLE', + 'BROTLI_DECODER_NEEDS_MORE_INPUT', + 'BROTLI_DECODER_NEEDS_MORE_OUTPUT', + 'BROTLI_DECODER_NO_ERROR', + 'BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION', + 'BROTLI_DECODER_PARAM_LARGE_WINDOW', + 'BROTLI_DECODER_RESULT_ERROR', + 'BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT', + 'BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT', + 'BROTLI_DECODER_RESULT_SUCCESS', + 'BROTLI_DECODER_SUCCESS', + 'BROTLI_DEFAULT_MODE', + 'BROTLI_DEFAULT_QUALITY', + 'BROTLI_DEFAULT_WINDOW', + 'BROTLI_ENCODE', + 'BROTLI_LARGE_MAX_WINDOW_BITS', + 'BROTLI_MAX_INPUT_BLOCK_BITS', + 'BROTLI_MAX_QUALITY', + 'BROTLI_MAX_WINDOW_BITS', + 'BROTLI_MIN_INPUT_BLOCK_BITS', + 'BROTLI_MIN_QUALITY', + 'BROTLI_MIN_WINDOW_BITS', + 'BROTLI_MODE_FONT', + 'BROTLI_MODE_GENERIC', + 'BROTLI_MODE_TEXT', + 'BROTLI_OPERATION_EMIT_METADATA', + 'BROTLI_OPERATION_FINISH', + 'BROTLI_OPERATION_FLUSH', + 'BROTLI_OPERATION_PROCESS', + 'BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING', + 'BROTLI_PARAM_LARGE_WINDOW', + 'BROTLI_PARAM_LGBLOCK', + 'BROTLI_PARAM_LGWIN', + 'BROTLI_PARAM_MODE', + 'BROTLI_PARAM_NDIRECT', + 'BROTLI_PARAM_NPOSTFIX', + 'BROTLI_PARAM_QUALITY', + 'BROTLI_PARAM_SIZE_HINT', + 'DEFLATE', + 'DEFLATERAW', + 'GUNZIP', + 'GZIP', + 'INFLATE', + 'INFLATERAW', + 'UNZIP', + 'ZLIB_VERNUM', + 'Z_BEST_COMPRESSION', + 'Z_BEST_SPEED', + 'Z_BLOCK', + 'Z_BUF_ERROR', + 'Z_DATA_ERROR', + 'Z_DEFAULT_CHUNK', + 'Z_DEFAULT_COMPRESSION', + 'Z_DEFAULT_LEVEL', + 'Z_DEFAULT_MEMLEVEL', + 'Z_DEFAULT_STRATEGY', + 'Z_DEFAULT_WINDOWBITS', + 'Z_ERRNO', + 'Z_FILTERED', + 'Z_FINISH', + 'Z_FIXED', + 'Z_FULL_FLUSH', + 'Z_HUFFMAN_ONLY', + 'Z_MAX_CHUNK', + 'Z_MAX_LEVEL', + 'Z_MAX_MEMLEVEL', + 'Z_MAX_WINDOWBITS', + 'Z_MEM_ERROR', + 'Z_MIN_CHUNK', + 'Z_MIN_LEVEL', + 'Z_MIN_MEMLEVEL', + 'Z_MIN_WINDOWBITS', + 'Z_NEED_DICT', + 'Z_NO_COMPRESSION', + 'Z_NO_FLUSH', + 'Z_OK', + 'Z_PARTIAL_FLUSH', + 'Z_RLE', + 'Z_STREAM_END', + 'Z_STREAM_ERROR', + 'Z_SYNC_FLUSH', + 'Z_VERSION_ERROR', ]); - } -} + }, +}; diff --git a/src/workerd/api/queue-test.js b/src/workerd/api/queue-test.js index 55f81aedca3..96b4e1cb179 100644 --- a/src/workerd/api/queue-test.js +++ b/src/workerd/api/queue-test.js @@ -1,131 +1,150 @@ -// Copyright (c) 2023 Cloudflare, Inc. -// Licensed under the Apache 2.0 license found in the LICENSE file or at: -// https://opensource.org/licenses/Apache-2.0 - -import assert from "node:assert"; -import { Buffer } from "node:buffer"; - -let serializedBody; - -export default { - // Producer receiver (from `env.QUEUE`) - async fetch(request, env, ctx) { - assert.strictEqual(request.method, "POST"); - const { pathname } = new URL(request.url); - if (pathname === "/message") { - const format = request.headers.get("X-Msg-Fmt") ?? "v8"; - if (format === "text") { - assert.strictEqual(request.headers.get("X-Msg-Delay-Secs"), "2") - assert.strictEqual(await request.text(), "abc"); - } else if (format === "bytes") { - const array = new Uint16Array(await request.arrayBuffer()); - assert.deepStrictEqual(array, new Uint16Array([1, 2, 3])); - } else if (format === "json") { - assert.deepStrictEqual(await request.json(), { a: 1 }); - } else if (format === "v8") { - // workerd doesn't provide V8 deserialization APIs, so just look for expected strings - const buffer = Buffer.from(await request.arrayBuffer()); - assert(buffer.includes("key")); - assert(buffer.includes("value")); - serializedBody = buffer; - } else { - assert.fail(`Unexpected format: ${JSON.stringify(format)}`); - } - } else if (pathname === "/batch") { - assert.strictEqual(request.headers.get("X-Msg-Delay-Secs"), "2") - - const body = await request.json(); - - assert.strictEqual(typeof body, "object"); - assert(Array.isArray(body?.messages)); - assert.strictEqual(body.messages.length, 4); - - assert.strictEqual(body.messages[0].contentType, "text"); - assert.strictEqual(Buffer.from(body.messages[0].body, "base64").toString(), "def"); - - assert.strictEqual(body.messages[1].contentType, "bytes"); - assert.deepStrictEqual(Buffer.from(body.messages[1].body, "base64"), Buffer.from([4, 5, 6])); - - assert.strictEqual(body.messages[2].contentType, "json"); - assert.deepStrictEqual(JSON.parse(Buffer.from(body.messages[2].body, "base64")), [7, 8, { b: 9 }]); - - assert.strictEqual(body.messages[3].contentType, "v8"); - assert(Buffer.from(body.messages[3].body, "base64").includes("value")); - assert.strictEqual(body.messages[3].delaySecs, 1); - } else { - assert.fail(`Unexpected pathname: ${JSON.stringify(pathname)}`); - } - return new Response(); - }, - - // Consumer receiver (from `env.SERVICE`) - async queue(batch, env, ctx) { - assert.strictEqual(batch.queue, "test-queue"); - assert.strictEqual(batch.messages.length, 5); - - assert.strictEqual(batch.messages[0].id, "#0"); - assert.strictEqual(batch.messages[0].body, "ghi"); - assert.strictEqual(batch.messages[0].attempts, 1); - - assert.strictEqual(batch.messages[1].id, "#1"); - assert.deepStrictEqual(batch.messages[1].body, new Uint8Array([7, 8, 9])); - assert.strictEqual(batch.messages[1].attempts, 2); - - assert.strictEqual(batch.messages[2].id, "#2"); - assert.deepStrictEqual(batch.messages[2].body, { c: { d: 10 } }); - assert.strictEqual(batch.messages[2].attempts, 3); - batch.messages[2].retry(); - - assert.strictEqual(batch.messages[3].id, "#3"); - assert.deepStrictEqual(batch.messages[3].body, batch.messages[3].timestamp); - assert.strictEqual(batch.messages[3].attempts, 4); - batch.messages[3].retry({ delaySeconds: 2 }); - - assert.strictEqual(batch.messages[4].id, "#4"); - assert.deepStrictEqual(batch.messages[4].body, new Map([["key", "value"]])); - assert.strictEqual(batch.messages[4].attempts, 5); - - batch.ackAll(); - }, - - async test(ctrl, env, ctx) { - await env.QUEUE.send("abc", { contentType: "text", delaySeconds: 2 }); - await env.QUEUE.send(new Uint16Array([1, 2, 3]), { contentType: "bytes" }); - await env.QUEUE.send({ a: 1 }, { contentType: "json" }); - await env.QUEUE.send(new Map([["key", "value"]]), { contentType: "v8" }); - - await env.QUEUE.sendBatch([ - { body: "def", contentType: "text" }, - { body: new Uint8Array([4, 5, 6]), contentType: "bytes" }, - { body: [7, 8, { b: 9 }], contentType: "json" }, - { body: new Set(["value"]), contentType: "v8", delaySeconds: 1 }, - ], { delaySeconds: 2 }); - - const timestamp = new Date(); - const response = await env.SERVICE.queue("test-queue", [ - { id: "#0", timestamp, body: "ghi", attempts: 1 }, - { id: "#1", timestamp, body: new Uint8Array([7, 8, 9]), attempts: 2 }, - { id: "#2", timestamp, body: { c: { d: 10 } }, attempts: 3 }, - { id: "#3", timestamp, body: timestamp, attempts: 4 }, - { id: "#4", timestamp, serializedBody, attempts: 5 }, - ]); - assert.strictEqual(response.outcome, "ok"); - assert(!response.retryBatch.retry); - assert(response.ackAll); - assert.deepStrictEqual(response.retryMessages, [{ msgId: '#2' }, { msgId: '#3', delaySeconds: 2 }]); - assert.deepStrictEqual(response.explicitAcks, []); - - await assert.rejects(env.SERVICE.queue("test-queue", [ - { id: "#0", timestamp, attempts: 1 } - ]), { - name: "TypeError", - message: "Expected one of body or serializedBody for each message" - }); - await assert.rejects(env.SERVICE.queue("test-queue", [ - { id: "#0", timestamp, body: "", serializedBody, attempts: 1 } - ]), { - name: "TypeError", - message: "Expected one of body or serializedBody for each message" - }); - }, -} +// Copyright (c) 2023 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 + +import assert from 'node:assert'; +import { Buffer } from 'node:buffer'; + +let serializedBody; + +export default { + // Producer receiver (from `env.QUEUE`) + async fetch(request, env, ctx) { + assert.strictEqual(request.method, 'POST'); + const { pathname } = new URL(request.url); + if (pathname === '/message') { + const format = request.headers.get('X-Msg-Fmt') ?? 'v8'; + if (format === 'text') { + assert.strictEqual(request.headers.get('X-Msg-Delay-Secs'), '2'); + assert.strictEqual(await request.text(), 'abc'); + } else if (format === 'bytes') { + const array = new Uint16Array(await request.arrayBuffer()); + assert.deepStrictEqual(array, new Uint16Array([1, 2, 3])); + } else if (format === 'json') { + assert.deepStrictEqual(await request.json(), { a: 1 }); + } else if (format === 'v8') { + // workerd doesn't provide V8 deserialization APIs, so just look for expected strings + const buffer = Buffer.from(await request.arrayBuffer()); + assert(buffer.includes('key')); + assert(buffer.includes('value')); + serializedBody = buffer; + } else { + assert.fail(`Unexpected format: ${JSON.stringify(format)}`); + } + } else if (pathname === '/batch') { + assert.strictEqual(request.headers.get('X-Msg-Delay-Secs'), '2'); + + const body = await request.json(); + + assert.strictEqual(typeof body, 'object'); + assert(Array.isArray(body?.messages)); + assert.strictEqual(body.messages.length, 4); + + assert.strictEqual(body.messages[0].contentType, 'text'); + assert.strictEqual( + Buffer.from(body.messages[0].body, 'base64').toString(), + 'def' + ); + + assert.strictEqual(body.messages[1].contentType, 'bytes'); + assert.deepStrictEqual( + Buffer.from(body.messages[1].body, 'base64'), + Buffer.from([4, 5, 6]) + ); + + assert.strictEqual(body.messages[2].contentType, 'json'); + assert.deepStrictEqual( + JSON.parse(Buffer.from(body.messages[2].body, 'base64')), + [7, 8, { b: 9 }] + ); + + assert.strictEqual(body.messages[3].contentType, 'v8'); + assert(Buffer.from(body.messages[3].body, 'base64').includes('value')); + assert.strictEqual(body.messages[3].delaySecs, 1); + } else { + assert.fail(`Unexpected pathname: ${JSON.stringify(pathname)}`); + } + return new Response(); + }, + + // Consumer receiver (from `env.SERVICE`) + async queue(batch, env, ctx) { + assert.strictEqual(batch.queue, 'test-queue'); + assert.strictEqual(batch.messages.length, 5); + + assert.strictEqual(batch.messages[0].id, '#0'); + assert.strictEqual(batch.messages[0].body, 'ghi'); + assert.strictEqual(batch.messages[0].attempts, 1); + + assert.strictEqual(batch.messages[1].id, '#1'); + assert.deepStrictEqual(batch.messages[1].body, new Uint8Array([7, 8, 9])); + assert.strictEqual(batch.messages[1].attempts, 2); + + assert.strictEqual(batch.messages[2].id, '#2'); + assert.deepStrictEqual(batch.messages[2].body, { c: { d: 10 } }); + assert.strictEqual(batch.messages[2].attempts, 3); + batch.messages[2].retry(); + + assert.strictEqual(batch.messages[3].id, '#3'); + assert.deepStrictEqual(batch.messages[3].body, batch.messages[3].timestamp); + assert.strictEqual(batch.messages[3].attempts, 4); + batch.messages[3].retry({ delaySeconds: 2 }); + + assert.strictEqual(batch.messages[4].id, '#4'); + assert.deepStrictEqual(batch.messages[4].body, new Map([['key', 'value']])); + assert.strictEqual(batch.messages[4].attempts, 5); + + batch.ackAll(); + }, + + async test(ctrl, env, ctx) { + await env.QUEUE.send('abc', { contentType: 'text', delaySeconds: 2 }); + await env.QUEUE.send(new Uint16Array([1, 2, 3]), { contentType: 'bytes' }); + await env.QUEUE.send({ a: 1 }, { contentType: 'json' }); + await env.QUEUE.send(new Map([['key', 'value']]), { contentType: 'v8' }); + + await env.QUEUE.sendBatch( + [ + { body: 'def', contentType: 'text' }, + { body: new Uint8Array([4, 5, 6]), contentType: 'bytes' }, + { body: [7, 8, { b: 9 }], contentType: 'json' }, + { body: new Set(['value']), contentType: 'v8', delaySeconds: 1 }, + ], + { delaySeconds: 2 } + ); + + const timestamp = new Date(); + const response = await env.SERVICE.queue('test-queue', [ + { id: '#0', timestamp, body: 'ghi', attempts: 1 }, + { id: '#1', timestamp, body: new Uint8Array([7, 8, 9]), attempts: 2 }, + { id: '#2', timestamp, body: { c: { d: 10 } }, attempts: 3 }, + { id: '#3', timestamp, body: timestamp, attempts: 4 }, + { id: '#4', timestamp, serializedBody, attempts: 5 }, + ]); + assert.strictEqual(response.outcome, 'ok'); + assert(!response.retryBatch.retry); + assert(response.ackAll); + assert.deepStrictEqual(response.retryMessages, [ + { msgId: '#2' }, + { msgId: '#3', delaySeconds: 2 }, + ]); + assert.deepStrictEqual(response.explicitAcks, []); + + await assert.rejects( + env.SERVICE.queue('test-queue', [{ id: '#0', timestamp, attempts: 1 }]), + { + name: 'TypeError', + message: 'Expected one of body or serializedBody for each message', + } + ); + await assert.rejects( + env.SERVICE.queue('test-queue', [ + { id: '#0', timestamp, body: '', serializedBody, attempts: 1 }, + ]), + { + name: 'TypeError', + message: 'Expected one of body or serializedBody for each message', + } + ); + }, +}; diff --git a/src/workerd/api/rtti-test.js b/src/workerd/api/rtti-test.js index 6fc3653911c..3003365f74a 100644 --- a/src/workerd/api/rtti-test.js +++ b/src/workerd/api/rtti-test.js @@ -2,12 +2,12 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import assert from "node:assert"; -import rtti from "workerd:rtti"; +import assert from 'node:assert'; +import rtti from 'workerd:rtti'; export default { async test(ctrl, env, ctx) { - const buffer = rtti.exportTypes("2023-05-18", ["nodejs_compat"]); + const buffer = rtti.exportTypes('2023-05-18', ['nodejs_compat']); assert(buffer.byteLength > 0); - } -} + }, +}; diff --git a/src/workerd/api/sql-test.js b/src/workerd/api/sql-test.js index 16e47d3eab7..5a75f147564 100644 --- a/src/workerd/api/sql-test.js +++ b/src/workerd/api/sql-test.js @@ -2,46 +2,46 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from 'node:assert' +import * as assert from 'node:assert'; async function test(state) { - const storage = state.storage - const sql = storage.sql + const storage = state.storage; + const sql = storage.sql; // Test numeric results - const resultNumber = [...sql.exec('SELECT 123')] - assert.equal(resultNumber.length, 1) - assert.equal(resultNumber[0]['123'], 123) + const resultNumber = [...sql.exec('SELECT 123')]; + assert.equal(resultNumber.length, 1); + assert.equal(resultNumber[0]['123'], 123); // Test raw results - const resultNumberRaw = [...sql.exec('SELECT 123').raw()] - assert.equal(resultNumberRaw.length, 1) - assert.equal(resultNumberRaw[0].length, 1) - assert.equal(resultNumberRaw[0][0], 123) + const resultNumberRaw = [...sql.exec('SELECT 123').raw()]; + assert.equal(resultNumberRaw.length, 1); + assert.equal(resultNumberRaw[0].length, 1); + assert.equal(resultNumberRaw[0][0], 123); // Test string results - const resultStr = [...sql.exec("SELECT 'hello'")] - assert.equal(resultStr.length, 1) - assert.equal(resultStr[0]["'hello'"], 'hello') + const resultStr = [...sql.exec("SELECT 'hello'")]; + assert.equal(resultStr.length, 1); + assert.equal(resultStr[0]["'hello'"], 'hello'); // Test blob results - const resultBlob = [...sql.exec("SELECT x'ff' as blob")] - assert.equal(resultBlob.length, 1) - const blob = new Uint8Array(resultBlob[0].blob) - assert.equal(blob.length, 1) - assert.equal(blob[0], 255) + const resultBlob = [...sql.exec("SELECT x'ff' as blob")]; + assert.equal(resultBlob.length, 1); + const blob = new Uint8Array(resultBlob[0].blob); + assert.equal(blob.length, 1); + assert.equal(blob[0], 255); { // Test binding values - const result = [...sql.exec('SELECT ?', 456)] - assert.equal(result.length, 1) - assert.equal(result[0]['?'], 456) + const result = [...sql.exec('SELECT ?', 456)]; + assert.equal(result.length, 1); + assert.equal(result[0]['?'], 456); } { // Test multiple binding values - const result = [...sql.exec('SELECT ? + ?', 123, 456)] - assert.equal(result.length, 1) - assert.equal(result[0]['? + ?'], 579) + const result = [...sql.exec('SELECT ? + ?', 123, 456)]; + assert.equal(result.length, 1); + assert.equal(result[0]['? + ?'], 579); } { @@ -54,69 +54,80 @@ async function test(state) { 'UNION ALL\n' + 'SELECT 3 AS value;' ), - ] - assert.equal(result.length, 3) - assert.equal(result[0]['value'], 1) - assert.equal(result[1]['value'], 2) - assert.equal(result[2]['value'], 3) + ]; + assert.equal(result.length, 3); + assert.equal(result[0]['value'], 1); + assert.equal(result[1]['value'], 2); + assert.equal(result[2]['value'], 3); } - // Test partial query ingestion - assert.deepEqual(sql.ingest(`SELECT 123; SELECT 456; `).remainder, ' ') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT 456;`).remainder, '') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT 456`).remainder, ' SELECT 456') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT 45`).remainder, ' SELECT 45') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT 4`).remainder, ' SELECT 4') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT `).remainder, ' SELECT ') - assert.deepEqual(sql.ingest(`SELECT 123; SELECT`).remainder, ' SELECT') - assert.deepEqual(sql.ingest(`SELECT 123; SELEC`).remainder, ' SELEC') - assert.deepEqual(sql.ingest(`SELECT 123; SELE`).remainder, ' SELE') - assert.deepEqual(sql.ingest(`SELECT 123; SEL`).remainder, ' SEL') - assert.deepEqual(sql.ingest(`SELECT 123; SE`).remainder, ' SE') - assert.deepEqual(sql.ingest(`SELECT 123; S`).remainder, ' S') - assert.deepEqual(sql.ingest(`SELECT 123; `).remainder, ' ') - assert.deepEqual(sql.ingest(`SELECT 123;`).remainder, '') - assert.deepEqual(sql.ingest(`SELECT 123`).remainder, 'SELECT 123') - assert.deepEqual(sql.ingest(`SELECT 12`).remainder, 'SELECT 12') - assert.deepEqual(sql.ingest(`SELECT 1`).remainder, 'SELECT 1') + assert.deepEqual(sql.ingest(`SELECT 123; SELECT 456; `).remainder, ' '); + assert.deepEqual(sql.ingest(`SELECT 123; SELECT 456;`).remainder, ''); + assert.deepEqual( + sql.ingest(`SELECT 123; SELECT 456`).remainder, + ' SELECT 456' + ); + assert.deepEqual(sql.ingest(`SELECT 123; SELECT 45`).remainder, ' SELECT 45'); + assert.deepEqual(sql.ingest(`SELECT 123; SELECT 4`).remainder, ' SELECT 4'); + assert.deepEqual(sql.ingest(`SELECT 123; SELECT `).remainder, ' SELECT '); + assert.deepEqual(sql.ingest(`SELECT 123; SELECT`).remainder, ' SELECT'); + assert.deepEqual(sql.ingest(`SELECT 123; SELEC`).remainder, ' SELEC'); + assert.deepEqual(sql.ingest(`SELECT 123; SELE`).remainder, ' SELE'); + assert.deepEqual(sql.ingest(`SELECT 123; SEL`).remainder, ' SEL'); + assert.deepEqual(sql.ingest(`SELECT 123; SE`).remainder, ' SE'); + assert.deepEqual(sql.ingest(`SELECT 123; S`).remainder, ' S'); + assert.deepEqual(sql.ingest(`SELECT 123; `).remainder, ' '); + assert.deepEqual(sql.ingest(`SELECT 123;`).remainder, ''); + assert.deepEqual(sql.ingest(`SELECT 123`).remainder, 'SELECT 123'); + assert.deepEqual(sql.ingest(`SELECT 12`).remainder, 'SELECT 12'); + assert.deepEqual(sql.ingest(`SELECT 1`).remainder, 'SELECT 1'); // Exec throws with trailing comments assert.throws( () => sql.exec('SELECT 123; SELECT 456; -- trailing comment'), /SQL code did not contain a statement/ - ) + ); // Ingest does not assert.deepEqual( sql.ingest(`SELECT 123; SELECT 456; -- trailing comment`).remainder, ' -- trailing comment' - ) + ); // Ingest throws if statement looks "complete" but is actually a syntax error: - assert.throws(() => sql.ingest(`SELECT * bunk;`), /Error: near "bunk": syntax error at offset/) - assert.throws(() => sql.ingest(`INSER INTO xyz VALUES ('a'),('b');`), /Error: near "INSER": syntax error/) - assert.throws(() => sql.ingest(`INSERT INTO xyz VALUES ('a')('b');`), /Error: near "\(": syntax error/) + assert.throws( + () => sql.ingest(`SELECT * bunk;`), + /Error: near "bunk": syntax error at offset/ + ); + assert.throws( + () => sql.ingest(`INSER INTO xyz VALUES ('a'),('b');`), + /Error: near "INSER": syntax error/ + ); + assert.throws( + () => sql.ingest(`INSERT INTO xyz VALUES ('a')('b');`), + /Error: near "\(": syntax error/ + ); // Test execution of ingested queries by taking an input of 6 INSERT statements, that all // add 6 rows of data, then splitting that into a bunch of chunks, then ingesting them all { - sql.exec(`CREATE TABLE streaming(val TEXT);`) + sql.exec(`CREATE TABLE streaming(val TEXT);`); // Convert to binary otherwise .split can cause corruption for multi-byte chars - const inputBytes = new TextEncoder().encode(INSERT_36_ROWS) - const decoder = new TextDecoder() + const inputBytes = new TextEncoder().encode(INSERT_36_ROWS); + const decoder = new TextDecoder(); // Use a chunk size 1, 3, 9, 27, 81, ... bytes for (let length = 1; length < inputBytes.length; length = length * 3) { let totalRowsWritten = 0; let totalSqlStatements = 0; - let buffer = '' + let buffer = ''; for (let offset = 0; offset < inputBytes.length; offset += length) { // Simulate a single "chunk" arriving - const chunk = inputBytes.slice(offset, offset + length) + const chunk = inputBytes.slice(offset, offset + length); // Append the new chunk to the existing buffer - buffer += decoder.decode(chunk, { stream: true }) + buffer += decoder.decode(chunk, { stream: true }); // Ingest any complete statements and snip those chars off the buffer let result = sql.ingest(buffer); @@ -125,13 +136,13 @@ async function test(state) { totalSqlStatements += result.statementCount; // Simulate awaiting next chunk - await scheduler.wait(1) + await scheduler.wait(1); } // Verify exactly 36 rows were added assert.deepEqual(Array.from(sql.exec(`SELECT count(*) FROM streaming`)), [ { 'count(*)': 36 }, - ]) + ]); // Ensure our precious emoji were preserved, even if their bytes occur across split points assert.deepEqual( @@ -144,16 +155,16 @@ async function test(state) { { val: 'f: 🥺' }, { val: 'f: 🔥😎🔥' }, ] - ) + ); // Verify that all 36 rows we inserted were accounted for. assert.equal(totalRowsWritten, 36); assert.equal(totalSqlStatements, 6); - sql.exec(`DELETE FROM streaming`) - await scheduler.wait(1) + sql.exec(`DELETE FROM streaming`); + await scheduler.wait(1); } - sql.exec(`DROP TABLE streaming;`) + sql.exec(`DROP TABLE streaming;`); } // Test count @@ -166,9 +177,9 @@ async function test(state) { 'UNION ALL\n' + 'SELECT 3 AS value);' ), - ] - assert.equal(result.length, 1) - assert.equal(result[0]['count(value)'], 3) + ]; + assert.equal(result.length, 1); + assert.equal(result[0]['count(value)'], 3); } // Test sum @@ -181,208 +192,220 @@ async function test(state) { 'UNION ALL\n' + 'SELECT 3 AS value);' ), - ] - assert.equal(result.length, 1) - assert.equal(result[0]['sum(value)'], 6) + ]; + assert.equal(result.length, 1); + assert.equal(result[0]['sum(value)'], 6); } // Test math functions enabled { - const result = [...sql.exec("SELECT cos(0)")] - assert.equal(result.length, 1) - assert.equal(result[0]['cos(0)'], 1) + const result = [...sql.exec('SELECT cos(0)')]; + assert.equal(result.length, 1); + assert.equal(result[0]['cos(0)'], 1); } // Empty statements - assert.throws(() => sql.exec(''), 'SQL code did not contain a statement') - assert.throws(() => sql.exec(';'), 'SQL code did not contain a statement') + assert.throws(() => sql.exec(''), 'SQL code did not contain a statement'); + assert.throws(() => sql.exec(';'), 'SQL code did not contain a statement'); // Invalid statements - assert.throws(() => sql.exec('SELECT ;'), /syntax error at offset 7/) - assert.throws(() => sql.exec('SELECT -;'), /syntax error at offset 8/) + assert.throws(() => sql.exec('SELECT ;'), /syntax error at offset 7/); + assert.throws(() => sql.exec('SELECT -;'), /syntax error at offset 8/); // Data type mismatch - sql.exec(`CREATE TABLE test_error_codes (name TEXT);`) - assert.throws(() => sql.exec(`INSERT INTO test_error_codes(rowid, name) values ('yeah','nah');`), /Error: datatype mismatch: SQLITE_MISMATCH/) - sql.exec(`DROP TABLE test_error_codes;`) + sql.exec(`CREATE TABLE test_error_codes (name TEXT);`); + assert.throws( + () => + sql.exec( + `INSERT INTO test_error_codes(rowid, name) values ('yeah','nah');` + ), + /Error: datatype mismatch: SQLITE_MISMATCH/ + ); + sql.exec(`DROP TABLE test_error_codes;`); // Incorrect number of binding values assert.throws( () => sql.exec('SELECT ?'), 'Error: Wrong number of parameter bindings for SQL query.' - ) + ); // Prepared statement - const prepared = sql.prepare('SELECT 789') - const resultPrepared = [...prepared()] - assert.equal(resultPrepared.length, 1) - assert.equal(resultPrepared[0]['789'], 789) + const prepared = sql.prepare('SELECT 789'); + const resultPrepared = [...prepared()]; + assert.equal(resultPrepared.length, 1); + assert.equal(resultPrepared[0]['789'], 789); // Running the same query twice invalidates the previous cursor. - let result1 = prepared() - let result2 = prepared() - assert.equal([...result2][0]['789'], 789) + let result1 = prepared(); + let result2 = prepared(); + assert.equal([...result2][0]['789'], 789); assert.throws( () => [...result1], 'SQL cursor was closed because the same statement was executed again.' - ) + ); // That said if a cursor was already done before the statement was re-run, it's not considered // canceled. - prepared() - assert.equal([...result2].length, 0) + prepared(); + assert.equal([...result2].length, 0); // Prepared statement with binding values - const preparedWithBinding = sql.prepare('SELECT ?') - const resultPreparedWithBinding = [...preparedWithBinding(789)] - assert.equal(resultPreparedWithBinding.length, 1) - assert.equal(resultPreparedWithBinding[0]['?'], 789) + const preparedWithBinding = sql.prepare('SELECT ?'); + const resultPreparedWithBinding = [...preparedWithBinding(789)]; + assert.equal(resultPreparedWithBinding.length, 1); + assert.equal(resultPreparedWithBinding[0]['?'], 789); // Prepared statement (incorrect number of binding values) assert.throws( () => preparedWithBinding(), 'Error: Wrong number of parameter bindings for SQL query.' - ) + ); // Prepared statement with whitespace - const whitespace = [' ', '\t', '\n', '\r', '\v', '\f', '\r\n'] + const whitespace = [' ', '\t', '\n', '\r', '\v', '\f', '\r\n']; for (const char of whitespace) { const prepared = sql.prepare(`SELECT 1;${char}`); - const result = [...prepared()] + const result = [...prepared()]; - assert.equal(result.length, 1) + assert.equal(result.length, 1); } // Prepared statement with multiple statements assert.throws(() => { sql.prepare('SELECT 1; SELECT 2;'); - }, /A prepared SQL statement must contain only one statement./) + }, /A prepared SQL statement must contain only one statement./); // Accessing a hidden _cf_ table assert.throws( () => sql.exec('CREATE TABLE _cf_invalid (name TEXT)'), /not authorized/ - ) - storage.put("blah", 123); // force creation of _cf_KV table + ); + storage.put('blah', 123); // force creation of _cf_KV table assert.throws( () => sql.exec('SELECT * FROM _cf_KV'), /access to _cf_KV.key is prohibited/ - ) + ); // Some pragmas are completely not allowed assert.throws( () => sql.exec('PRAGMA hard_heap_limit = 1024'), /not authorized/ - ) + ); // Test reading read-only pragmas { - const result = [...sql.exec('pragma data_version;')] - assert.equal(result.length, 1) - assert.equal(result[0]['data_version'], 2) + const result = [...sql.exec('pragma data_version;')]; + assert.equal(result.length, 1); + assert.equal(result[0]['data_version'], 2); } // Trying to write to read-only pragmas is not allowed - assert.throws(() => sql.exec('PRAGMA data_version = 5'), /not authorized: SQLITE_AUTH/) + assert.throws( + () => sql.exec('PRAGMA data_version = 5'), + /not authorized: SQLITE_AUTH/ + ); assert.throws( () => sql.exec('PRAGMA max_page_count = 65536'), /not authorized/ - ) - assert.throws(() => sql.exec('PRAGMA page_size = 8192'), /not authorized: SQLITE_AUTH/) + ); + assert.throws( + () => sql.exec('PRAGMA page_size = 8192'), + /not authorized: SQLITE_AUTH/ + ); // PRAGMA table_info and PRAGMA table_xinfo are allowed. - sql.exec('CREATE TABLE myTable (foo TEXT, bar INTEGER)') + sql.exec('CREATE TABLE myTable (foo TEXT, bar INTEGER)'); { - let info = [...sql.exec('PRAGMA table_info(myTable)')] - assert.equal(info.length, 2) - assert.equal(info[0].name, 'foo') - assert.equal(info[1].name, 'bar') - - let xInfo = [...sql.exec('PRAGMA table_xinfo(myTable)')] - assert.equal(xInfo.length, 2) - assert.equal(xInfo[0].name, 'foo') - assert.equal(xInfo[1].name, 'bar') + let info = [...sql.exec('PRAGMA table_info(myTable)')]; + assert.equal(info.length, 2); + assert.equal(info[0].name, 'foo'); + assert.equal(info[1].name, 'bar'); + + let xInfo = [...sql.exec('PRAGMA table_xinfo(myTable)')]; + assert.equal(xInfo.length, 2); + assert.equal(xInfo[0].name, 'foo'); + assert.equal(xInfo[1].name, 'bar'); } // Can't get table_info for _cf_KV. - assert.throws(() => sql.exec('PRAGMA table_info(_cf_KV)'), /not authorized/) + assert.throws(() => sql.exec('PRAGMA table_info(_cf_KV)'), /not authorized/); // Testing the three valid types of inputs for quick_check assert.deepEqual(Array.from(sql.exec('pragma quick_check;')), [ { quick_check: 'ok' }, - ]) + ]); assert.deepEqual(Array.from(sql.exec('pragma quick_check(1);')), [ { quick_check: 'ok' }, - ]) + ]); assert.deepEqual(Array.from(sql.exec('pragma quick_check(100);')), [ { quick_check: 'ok' }, - ]) + ]); assert.deepEqual(Array.from(sql.exec('pragma quick_check(myTable);')), [ { quick_check: 'ok' }, - ]) + ]); // But that private tables are again restricted - assert.throws(() => sql.exec('PRAGMA quick_check(_cf_KV)'), /not authorized/) + assert.throws(() => sql.exec('PRAGMA quick_check(_cf_KV)'), /not authorized/); // Basic functions like abs() work. - assert.equal([...sql.exec('SELECT abs(-123)').raw()][0][0], 123) + assert.equal([...sql.exec('SELECT abs(-123)').raw()][0][0], 123); // We don't permit sqlite_*() functions. assert.throws( () => sql.exec('SELECT sqlite_version()'), /not authorized to use function: sqlite_version/ - ) + ); // JSON -> operator works const jsonResult = [ ...sql.exec('SELECT \'{"a":2,"c":[4,5,{"f":7}]}\' -> \'$.c\' AS value'), - ][0].value - assert.equal(jsonResult, '[4,5,{"f":7}]') + ][0].value; + assert.equal(jsonResult, '[4,5,{"f":7}]'); // current_{date,time,timestamp} functions work - const resultDate = [...sql.exec('SELECT current_date')] - assert.equal(resultDate.length, 1) + const resultDate = [...sql.exec('SELECT current_date')]; + assert.equal(resultDate.length, 1); // Should match results in the format "2023-06-01" - assert.match(resultDate[0]['current_date'], /^\d{4}-\d{2}-\d{2}$/) + assert.match(resultDate[0]['current_date'], /^\d{4}-\d{2}-\d{2}$/); - const resultTime = [...sql.exec('SELECT current_time')] - assert.equal(resultTime.length, 1) + const resultTime = [...sql.exec('SELECT current_time')]; + assert.equal(resultTime.length, 1); // Should match results in the format "15:30:03" - assert.match(resultTime[0]['current_time'], /^\d{2}:\d{2}:\d{2}$/) + assert.match(resultTime[0]['current_time'], /^\d{2}:\d{2}:\d{2}$/); - const resultTimestamp = [...sql.exec('SELECT current_timestamp')] - assert.equal(resultTimestamp.length, 1) + const resultTimestamp = [...sql.exec('SELECT current_timestamp')]; + assert.equal(resultTimestamp.length, 1); // Should match results in the format "2023-06-01 15:30:03" assert.match( resultTimestamp[0]['current_timestamp'], /^\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}$/ - ) + ); // Validate that the SQLITE_LIMIT_COMPOUND_SELECT limit is enforced as expected const compoundWithinLimits = [ ...sql.exec( 'SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5' ), - ] - assert.equal(compoundWithinLimits.length, 5) + ]; + assert.equal(compoundWithinLimits.length, 5); assert.throws( () => sql.exec( 'SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6' ), /too many terms in compound SELECT/ - ) + ); // Can't start transactions or savepoints. - assert.throws(() => sql.exec('BEGIN TRANSACTION'), /not authorized/) - assert.throws(() => sql.exec('SAVEPOINT foo'), /not authorized/) + assert.throws(() => sql.exec('BEGIN TRANSACTION'), /not authorized/); + assert.throws(() => sql.exec('SAVEPOINT foo'), /not authorized/); // Virtual tables // Only fts5 and fts5vocab modules are allowed assert.throws( () => sql.exec(`CREATE VIRTUAL TABLE test_fts USING fts5abcd(id);`), /not authorized/ - ) + ); // Full text search extension sql.exec(` @@ -391,21 +414,21 @@ async function test(state) { title TEXT NOT NULL, content TEXT NOT NULL ); - `) + `); // Module names are case-insensitive sql.exec(` CREATE VIRTUAL TABLE documents_fts USING FtS5(id, title, content, tokenize = porter); - `) + `); sql.exec(` CREATE VIRTUAL TABLE documents_fts_v_col USING fTs5VoCaB(documents_fts, col); - `) + `); sql.exec(` CREATE VIRTUAL TABLE documents_fts_v_row USING FtS5vOcAb(documents_fts, row); - `) + `); sql.exec(` CREATE VIRTUAL TABLE documents_fts_v_instance USING fTs5VoCaB(documents_fts, instance); - `) + `); sql.exec(` CREATE TRIGGER documents_fts_insert @@ -414,37 +437,37 @@ async function test(state) { INSERT INTO documents_fts(id, title, content) VALUES(new.id, new.title, new.content); END; - `) + `); sql.exec(` CREATE TRIGGER documents_fts_update AFTER UPDATE ON documents BEGIN UPDATE documents_fts SET title=new.title, content=new.content WHERE id=old.id; END; - `) + `); sql.exec(` CREATE TRIGGER documents_fts_delete AFTER DELETE ON documents BEGIN DELETE FROM documents_fts WHERE id=old.id; END; - `) + `); sql.exec(` INSERT INTO documents (title, content) VALUES ('Document 1', 'This is the contents of document 1 (of 2).'); - `) + `); sql.exec(` INSERT INTO documents (title, content) VALUES ('Document 2', 'This is the content of document 2 (of 2).'); - `) + `); // Porter stemming makes 'contents' and 'content' the same { let results = Array.from( sql.exec(` SELECT * FROM documents_fts WHERE documents_fts MATCH 'content' ORDER BY rank; `) - ) - assert.equal(results.length, 2) - assert.equal(results[0].id, 1) // Stemming makes doc 1 match first - assert.equal(results[1].id, 2) + ); + assert.equal(results.length, 2); + assert.equal(results[0].id, 1); // Stemming makes doc 1 match first + assert.equal(results[1].id, 2); } // Ranking functions { @@ -452,14 +475,14 @@ async function test(state) { sql.exec(` SELECT *, bm25(documents_fts) FROM documents_fts WHERE documents_fts MATCH '2' ORDER BY rank; `) - ) - assert.equal(results.length, 2) + ); + assert.equal(results.length, 2); assert.equal( results[0]['bm25(documents_fts)'] < results[1]['bm25(documents_fts)'], true - ) // Better matches have lower bm25 (since they're all negative - assert.equal(results[0].id, 2) // Doc 2 comes first (sorted by rank) - assert.equal(results[1].id, 1) + ); // Better matches have lower bm25 (since they're all negative + assert.equal(results[0].id, 2); // Doc 2 comes first (sorted by rank) + assert.equal(results[1].id, 1); } // highlight() function { @@ -467,16 +490,16 @@ async function test(state) { sql.exec(` SELECT highlight(documents_fts, 2, '', '') as output FROM documents_fts WHERE documents_fts MATCH '2' ORDER BY rank; `) - ) - assert.equal(results.length, 2) + ); + assert.equal(results.length, 2); assert.equal( results[0].output, `This is the content of document 2 (of 2).` - ) // two matches, two highlights + ); // two matches, two highlights assert.equal( results[1].output, `This is the contents of document 1 (of 2).` - ) + ); } // snippet() function { @@ -484,10 +507,10 @@ async function test(state) { sql.exec(` SELECT snippet(documents_fts, 2, '', '', '...', 4) as output FROM documents_fts WHERE documents_fts MATCH '2' ORDER BY rank; `) - ) - assert.equal(results.length, 2) - assert.equal(results[0].output, `...document 2 (of 2).`) // two matches, two highlights - assert.equal(results[1].output, `...document 1 (of 2).`) + ); + assert.equal(results.length, 2); + assert.equal(results[0].output, `...document 2 (of 2).`); // two matches, two highlights + assert.equal(results[1].output, `...document 1 (of 2).`); } // Complex queries @@ -503,12 +526,12 @@ async function test(state) { AND tbl_name NOT LIKE "sqlite_%" AND tbl_name NOT LIKE "d1_%" AND tbl_name NOT LIKE "_cf_%"`), - ] - assert.equal(result.length, 2) - assert.equal(result[0].tbl_name, 'myTable') - assert.equal(result[0].num_columns, 2) - assert.equal(result[1].tbl_name, 'documents') - assert.equal(result[1].num_columns, 3) + ]; + assert.equal(result.length, 2); + assert.equal(result[0].tbl_name, 'myTable'); + assert.equal(result[0].num_columns, 2); + assert.equal(result[1].tbl_name, 'documents'); + assert.equal(result[1].num_columns, 3); } // Similar query using JSON objects @@ -528,262 +551,262 @@ async function test(state) { WHERE type = "table" AND tbl_name != "_cf_KV";` ) )[0].data - ) - assert.equal(jsonResult.length, 11) + ); + assert.equal(jsonResult.length, 11); assert.equal( jsonResult.map((r) => r.name).join(','), 'myTable,documents,documents_fts,documents_fts_data,documents_fts_idx,documents_fts_content,documents_fts_docsize,documents_fts_config,documents_fts_v_col,documents_fts_v_row,documents_fts_v_instance' - ) - assert.equal(jsonResult[0].columns.foo, 'TEXT') - assert.equal(jsonResult[0].columns.bar, 'INTEGER') - assert.equal(jsonResult[1].columns.id, 'INTEGER') - assert.equal(jsonResult[1].columns.title, 'TEXT') - assert.equal(jsonResult[1].columns.content, 'TEXT') + ); + assert.equal(jsonResult[0].columns.foo, 'TEXT'); + assert.equal(jsonResult[0].columns.bar, 'INTEGER'); + assert.equal(jsonResult[1].columns.id, 'INTEGER'); + assert.equal(jsonResult[1].columns.title, 'TEXT'); + assert.equal(jsonResult[1].columns.content, 'TEXT'); } let assertValidBool = (name, val) => { - sql.exec('PRAGMA defer_foreign_keys = ' + name + ';') + sql.exec('PRAGMA defer_foreign_keys = ' + name + ';'); assert.equal( [...sql.exec('PRAGMA defer_foreign_keys;')][0].defer_foreign_keys, val - ) - } + ); + }; let assertInvalidBool = (name, msg) => { assert.throws( () => sql.exec('PRAGMA defer_foreign_keys = ' + name + ';'), msg || /not authorized/ - ) - } + ); + }; - assertValidBool('true', 1) - assertValidBool('false', 0) - assertValidBool('on', 1) - assertValidBool('off', 0) - assertValidBool('yes', 1) - assertValidBool('no', 0) - assertValidBool('1', 1) - assertValidBool('0', 0) + assertValidBool('true', 1); + assertValidBool('false', 0); + assertValidBool('on', 1); + assertValidBool('off', 0); + assertValidBool('yes', 1); + assertValidBool('no', 0); + assertValidBool('1', 1); + assertValidBool('0', 0); // case-insensitive - assertValidBool('tRuE', 1) - assertValidBool('NO', 0) + assertValidBool('tRuE', 1); + assertValidBool('NO', 0); // quoted - assertValidBool("'true'", 1) - assertValidBool('"yes"', 1) - assertValidBool('"0"', 0) + assertValidBool("'true'", 1); + assertValidBool('"yes"', 1); + assertValidBool('"0"', 0); // whitespace is trimmed by sqlite before passing to authorizer - assertValidBool(' true ', 1) + assertValidBool(' true ', 1); // Don't accept anything invalid... - assertInvalidBool('abcd') - assertInvalidBool('"foo"') - assertInvalidBool("'yes", 'unrecognized token') + assertInvalidBool('abcd'); + assertInvalidBool('"foo"'); + assertInvalidBool("'yes", 'unrecognized token'); // Test database size interface. - assert.equal(sql.databaseSize, 36864) - sql.exec(`CREATE TABLE should_make_one_more_page(VALUE text);`) - assert.equal(sql.databaseSize, 36864 + 4096) - sql.exec(`DROP TABLE should_make_one_more_page;`) - assert.equal(sql.databaseSize, 36864) + assert.equal(sql.databaseSize, 36864); + sql.exec(`CREATE TABLE should_make_one_more_page(VALUE text);`); + assert.equal(sql.databaseSize, 36864 + 4096); + sql.exec(`DROP TABLE should_make_one_more_page;`); + assert.equal(sql.databaseSize, 36864); - storage.put('txnTest', 0) + storage.put('txnTest', 0); // Try a transaction while no implicit transaction is open. - await scheduler.wait(1) // finish implicit txn + await scheduler.wait(1); // finish implicit txn let txnResult = await storage.transaction(async () => { - storage.put('txnTest', 1) - assert.equal(await storage.get('txnTest'), 1) - return 'foo' - }) - assert.equal(await storage.get('txnTest'), 1) - assert.equal(txnResult, 'foo') + storage.put('txnTest', 1); + assert.equal(await storage.get('txnTest'), 1); + return 'foo'; + }); + assert.equal(await storage.get('txnTest'), 1); + assert.equal(txnResult, 'foo'); // Try a transaction while an implicit transaction is open first. - storage.put('txnTest', 2) + storage.put('txnTest', 2); await storage.transaction(async () => { - storage.put('txnTest', 3) - assert.equal(await storage.get('txnTest'), 3) - }) - assert.equal(await storage.get('txnTest'), 3) + storage.put('txnTest', 3); + assert.equal(await storage.get('txnTest'), 3); + }); + assert.equal(await storage.get('txnTest'), 3); // Try a transaction that is explicitly rolled back. await storage.transaction(async (txn) => { - storage.put('txnTest', 4) - assert.equal(await storage.get('txnTest'), 4) - txn.rollback() - }) - assert.equal(await storage.get('txnTest'), 3) + storage.put('txnTest', 4); + assert.equal(await storage.get('txnTest'), 4); + txn.rollback(); + }); + assert.equal(await storage.get('txnTest'), 3); // Try a transaction that is implicitly rolled back by throwing an exception. try { await storage.transaction(async (txn) => { - storage.put('txnTest', 5) - assert.equal(await storage.get('txnTest'), 5) - throw new Error('txn failure') - }) - throw new Error('expected errror') + storage.put('txnTest', 5); + assert.equal(await storage.get('txnTest'), 5); + throw new Error('txn failure'); + }); + throw new Error('expected errror'); } catch (err) { - assert.equal(err.message, 'txn failure') + assert.equal(err.message, 'txn failure'); } - assert.equal(await storage.get('txnTest'), 3) + assert.equal(await storage.get('txnTest'), 3); // Try a nested transaction. await storage.transaction(async (txn) => { - storage.put('txnTest', 6) - assert.equal(await storage.get('txnTest'), 6) + storage.put('txnTest', 6); + assert.equal(await storage.get('txnTest'), 6); await storage.transaction(async (txn2) => { - storage.put('txnTest', 7) - assert.equal(await storage.get('txnTest'), 7) + storage.put('txnTest', 7); + assert.equal(await storage.get('txnTest'), 7); // Let's even do an await in here for good measure. - await scheduler.wait(1) - }) - assert.equal(await storage.get('txnTest'), 7) - txn.rollback() - }) - assert.equal(await storage.get('txnTest'), 3) + await scheduler.wait(1); + }); + assert.equal(await storage.get('txnTest'), 7); + txn.rollback(); + }); + assert.equal(await storage.get('txnTest'), 3); // Test transactionSync, success { - await scheduler.wait(1) + await scheduler.wait(1); const result = storage.transactionSync(() => { - sql.exec('CREATE TABLE IF NOT EXISTS should_succeed (VALUE text);') - return 'some data' - }) + sql.exec('CREATE TABLE IF NOT EXISTS should_succeed (VALUE text);'); + return 'some data'; + }); - assert.equal(result, 'some data') + assert.equal(result, 'some data'); const results = Array.from( sql.exec(` SELECT * FROM sqlite_master WHERE tbl_name = 'should_succeed' `) - ) - assert.equal(results.length, 1) + ); + assert.equal(results.length, 1); } // Test transactionSync, failure { - await scheduler.wait(1) + await scheduler.wait(1); assert.throws( () => storage.transactionSync(() => { - sql.exec('CREATE TABLE should_be_rolled_back (VALUE text);') - sql.exec('SELECT * FROM misspelled_table_name;') + sql.exec('CREATE TABLE should_be_rolled_back (VALUE text);'); + sql.exec('SELECT * FROM misspelled_table_name;'); }), 'Error: no such table: misspelled_table_name' - ) + ); const results = Array.from( sql.exec(` SELECT * FROM sqlite_master WHERE tbl_name = 'should_be_rolled_back' `) - ) - assert.equal(results.length, 0) + ); + assert.equal(results.length, 0); } // Test transactionSync, nested { - sql.exec('CREATE TABLE txnTest (i INTEGER)') - sql.exec('INSERT INTO txnTest VALUES (1)') + sql.exec('CREATE TABLE txnTest (i INTEGER)'); + sql.exec('INSERT INTO txnTest VALUES (1)'); - let setI = sql.prepare('UPDATE txnTest SET i = ?') - let getIStmt = sql.prepare('SELECT i FROM txnTest') - let getI = () => [...getIStmt()][0].i + let setI = sql.prepare('UPDATE txnTest SET i = ?'); + let getIStmt = sql.prepare('SELECT i FROM txnTest'); + let getI = () => [...getIStmt()][0].i; - assert.equal(getI(), 1) + assert.equal(getI(), 1); storage.transactionSync(() => { - setI(2) - assert.equal(getI(), 2) + setI(2); + assert.equal(getI(), 2); assert.throws( () => storage.transactionSync(() => { - setI(3) - assert.equal(getI(), 3) - throw new Error('foo') + setI(3); + assert.equal(getI(), 3); + throw new Error('foo'); }), 'Error: foo' - ) + ); - assert.equal(getI(), 2) - }) - assert.equal(getI(), 2) + assert.equal(getI(), 2); + }); + assert.equal(getI(), 2); } // Test joining two tables with overlapping names { - sql.exec(`CREATE TABLE abc (a INT, b INT, c INT);`) - sql.exec(`CREATE TABLE cde (c INT, d INT, e INT);`) - sql.exec(`INSERT INTO abc VALUES (1,2,3),(4,5,6);`) - sql.exec(`INSERT INTO cde VALUES (7,8,9),(1,2,3);`) + sql.exec(`CREATE TABLE abc (a INT, b INT, c INT);`); + sql.exec(`CREATE TABLE cde (c INT, d INT, e INT);`); + sql.exec(`INSERT INTO abc VALUES (1,2,3),(4,5,6);`); + sql.exec(`INSERT INTO cde VALUES (7,8,9),(1,2,3);`); - const stmt = sql.prepare(`SELECT * FROM abc, cde`) + const stmt = sql.prepare(`SELECT * FROM abc, cde`); // In normal iteration, data is lost - const objResults = Array.from(stmt()) - assert.equal(Object.values(objResults[0]).length, 5) // duplicate column 'c' dropped - assert.equal(Object.values(objResults[1]).length, 5) // duplicate column 'c' dropped - assert.equal(Object.values(objResults[2]).length, 5) // duplicate column 'c' dropped - assert.equal(Object.values(objResults[3]).length, 5) // duplicate column 'c' dropped + const objResults = Array.from(stmt()); + assert.equal(Object.values(objResults[0]).length, 5); // duplicate column 'c' dropped + assert.equal(Object.values(objResults[1]).length, 5); // duplicate column 'c' dropped + assert.equal(Object.values(objResults[2]).length, 5); // duplicate column 'c' dropped + assert.equal(Object.values(objResults[3]).length, 5); // duplicate column 'c' dropped - assert.equal(objResults[0].c, 7) // Value of 'c' is the second in the join - assert.equal(objResults[1].c, 1) // Value of 'c' is the second in the join - assert.equal(objResults[2].c, 7) // Value of 'c' is the second in the join - assert.equal(objResults[3].c, 1) // Value of 'c' is the second in the join + assert.equal(objResults[0].c, 7); // Value of 'c' is the second in the join + assert.equal(objResults[1].c, 1); // Value of 'c' is the second in the join + assert.equal(objResults[2].c, 7); // Value of 'c' is the second in the join + assert.equal(objResults[3].c, 1); // Value of 'c' is the second in the join // Iterator has a 'columnNames' property, with .raw() that lets us get the full data - const iterator = stmt() - assert.deepEqual(iterator.columnNames, ['a', 'b', 'c', 'c', 'd', 'e']) - const rawResults = Array.from(iterator.raw()) - assert.equal(rawResults.length, 4) - assert.deepEqual(rawResults[0], [1, 2, 3, 7, 8, 9]) - assert.deepEqual(rawResults[1], [1, 2, 3, 1, 2, 3]) - assert.deepEqual(rawResults[2], [4, 5, 6, 7, 8, 9]) - assert.deepEqual(rawResults[3], [4, 5, 6, 1, 2, 3]) + const iterator = stmt(); + assert.deepEqual(iterator.columnNames, ['a', 'b', 'c', 'c', 'd', 'e']); + const rawResults = Array.from(iterator.raw()); + assert.equal(rawResults.length, 4); + assert.deepEqual(rawResults[0], [1, 2, 3, 7, 8, 9]); + assert.deepEqual(rawResults[1], [1, 2, 3, 1, 2, 3]); + assert.deepEqual(rawResults[2], [4, 5, 6, 7, 8, 9]); + assert.deepEqual(rawResults[3], [4, 5, 6, 1, 2, 3]); // Once an iterator is consumed, it can no longer access the columnNames. assert.throws(() => { - iterator.columnNames - }, 'Error: Cannot call .getColumnNames after Cursor iterator has been consumed.') + iterator.columnNames; + }, 'Error: Cannot call .getColumnNames after Cursor iterator has been consumed.'); // Also works with cursors returned from .exec - const execIterator = sql.exec(`SELECT * FROM abc, cde`) - assert.deepEqual(execIterator.columnNames, ['a', 'b', 'c', 'c', 'd', 'e']) - assert.equal(Array.from(execIterator.raw())[0].length, 6) + const execIterator = sql.exec(`SELECT * FROM abc, cde`); + assert.deepEqual(execIterator.columnNames, ['a', 'b', 'c', 'c', 'd', 'e']); + assert.equal(Array.from(execIterator.raw())[0].length, 6); } - await scheduler.wait(1) + await scheduler.wait(1); // Test for bug where a cursor constructed from a prepared statement didn't have a strong ref // to the statement object. { - sql.exec('CREATE TABLE iteratorTest (i INTEGER)') - sql.exec('INSERT INTO iteratorTest VALUES (0), (1)') + sql.exec('CREATE TABLE iteratorTest (i INTEGER)'); + sql.exec('INSERT INTO iteratorTest VALUES (0), (1)'); - let q = sql.prepare('SELECT * FROM iteratorTest')() - let i = 0 + let q = sql.prepare('SELECT * FROM iteratorTest')(); + let i = 0; for (let row of q) { - assert.equal(row.i, i++) - gc() + assert.equal(row.i, i++); + gc(); } } { // Test binding blobs & nulls - sql.exec(`CREATE TABLE test_blob (id INTEGER PRIMARY KEY, data BLOB);`) + sql.exec(`CREATE TABLE test_blob (id INTEGER PRIMARY KEY, data BLOB);`); sql.prepare( `INSERT INTO test_blob(data) VALUES(?),(ZEROBLOB(10)),(null),(?);` - )(crypto.getRandomValues(new Uint8Array(12)), null) - const results = Array.from(sql.exec(`SELECT * FROM test_blob`)) - assert.equal(results.length, 4) - assert.equal(results[0].data instanceof ArrayBuffer, true) - assert.equal(results[0].data.byteLength, 12) - assert.equal(results[1].data instanceof ArrayBuffer, true) - assert.equal(results[1].data.byteLength, 10) - assert.equal(results[2].data, null) - assert.equal(results[3].data, null) + )(crypto.getRandomValues(new Uint8Array(12)), null); + const results = Array.from(sql.exec(`SELECT * FROM test_blob`)); + assert.equal(results.length, 4); + assert.equal(results[0].data instanceof ArrayBuffer, true); + assert.equal(results[0].data.byteLength, 12); + assert.equal(results[1].data instanceof ArrayBuffer, true); + assert.equal(results[1].data.byteLength, 10); + assert.equal(results[2].data, null); + assert.equal(results[3].data, null); } // Can rename tables @@ -791,45 +814,45 @@ async function test(state) { CREATE TABLE beforerename ( id INTEGER ); - `) + `); sql.exec(` ALTER TABLE beforerename RENAME TO afterrename; - `) + `); sql.exec(` CREATE TABLE altercolumns ( meta TEXT ); - `) + `); // Can add columns sql.exec(` ALTER TABLE altercolumns ADD COLUMN tobedeleted TEXT; - `) + `); // Can rename columns within a table sql.exec(` ALTER TABLE altercolumns RENAME COLUMN meta TO metadata - `) + `); // Can drop columns sql.exec(` ALTER TABLE altercolumns DROP COLUMN tobedeleted - `) + `); // Can add columns with a CHECK sql.exec(` ALTER TABLE altercolumns ADD COLUMN checked_col TEXT CHECK(checked_col IN ('A','B')); - `) + `); // The CHECK is enforced unless `ignore_check_constraints` is on - sql.exec(`INSERT INTO altercolumns(checked_col) VALUES ('A')`) + sql.exec(`INSERT INTO altercolumns(checked_col) VALUES ('A')`); assert.throws( () => sql.exec(`INSERT INTO altercolumns(checked_col) VALUES ('C')`), /Error: CHECK constraint failed: checked_col IN \('A','B'\)/ - ) + ); // Because there's already a row, adding another column with a CHECK // but no default value will fail @@ -840,27 +863,27 @@ async function test(state) { ADD COLUMN second_col TEXT CHECK(second_col IS NOT NULL); `), /Error: CHECK constraint failed/ - ) + ); // ignore_check_constraints lets us bypass this for adding bad data - sql.exec(`PRAGMA ignore_check_constraints=ON;`) - sql.exec(`INSERT INTO altercolumns(checked_col) VALUES ('C')`) + sql.exec(`PRAGMA ignore_check_constraints=ON;`); + sql.exec(`INSERT INTO altercolumns(checked_col) VALUES ('C')`); assert.deepEqual( [...sql.exec(`SELECT * FROM altercolumns`)], [ { checked_col: 'A', metadata: null }, { checked_col: 'C', metadata: null }, ] - ) + ); // Or even adding columns that start broken (because second_col is NULL) sql.exec(` ALTER TABLE altercolumns ADD COLUMN second_col TEXT CHECK(second_col IS NOT NULL); - `) + `); // Turning check constraints back on doesn't actually do any checking, eagerly - sql.exec(`PRAGMA ignore_check_constraints=OFF;`) + sql.exec(`PRAGMA ignore_check_constraints=OFF;`); // But anything else that CHECKs that table will now fail, like adding another CHECK assert.throws( @@ -870,7 +893,7 @@ async function test(state) { ADD COLUMN third_col TEXT DEFAULT 'E' CHECK(third_col IN ('E','F')); `), /Error: CHECK constraint failed/ - ) + ); // And we can use quick_check to list out that there are now errors // (although these messages aren't great): @@ -880,7 +903,7 @@ async function test(state) { { quick_check: 'CHECK constraint failed in altercolumns' }, { quick_check: 'CHECK constraint failed in altercolumns' }, ] - ) + ); // Can't create another temp table assert.throws( @@ -890,12 +913,12 @@ async function test(state) { SELECT * FROM sqlite_master; `), 'Error: not authorized' - ) + ); // Assert foreign keys can be truly turned off, not just deferred await state.blockConcurrencyWhile(async () => { - sql.exec(`PRAGMA foreign_keys = OFF;`) - }) + sql.exec(`PRAGMA foreign_keys = OFF;`); + }); storage.transactionSync(() => { sql.exec(` CREATE TABLE A ( @@ -906,33 +929,33 @@ async function test(state) { CREATE TABLE B ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT ); - `) - }) + `); + }); // Until we've inserted the row into B, we can detect our // foreign key violation (even with foreign_keys=OFF) assert.deepEqual(Array.from(sql.exec(`pragma foreign_key_check;`)), [ { table: 'A', rowid: 1, parent: 'B', fkid: 0 }, - ]) - sql.exec(`INSERT INTO B VALUES (1);`) - assert.deepEqual(Array.from(sql.exec(`pragma foreign_key_check;`)), []) + ]); + sql.exec(`INSERT INTO B VALUES (1);`); + assert.deepEqual(Array.from(sql.exec(`pragma foreign_key_check;`)), []); // Restore foreign keys for the rest of the tests await state.blockConcurrencyWhile(async () => { - sql.exec(`PRAGMA foreign_keys = ON;`) - }) + sql.exec(`PRAGMA foreign_keys = ON;`); + }); } async function testIoStats(storage) { - const sql = storage.sql + const sql = storage.sql; - sql.exec(`CREATE TABLE tbl (id INTEGER PRIMARY KEY, value TEXT)`) + sql.exec(`CREATE TABLE tbl (id INTEGER PRIMARY KEY, value TEXT)`); sql.exec( `INSERT INTO tbl (id, value) VALUES (?, ?)`, 100000, 'arbitrary-initial-value' - ) - await scheduler.wait(1) + ); + await scheduler.wait(1); // When writing, the rowsWritten count goes up. { @@ -940,97 +963,97 @@ async function testIoStats(storage) { `INSERT INTO tbl (id, value) VALUES (?, ?)`, 1, 'arbitrary-value' - ) - Array.from(cursor) // Consume all the results - assert.equal(cursor.rowsWritten, 1) + ); + Array.from(cursor); // Consume all the results + assert.equal(cursor.rowsWritten, 1); } // When reading, the rowsRead count goes up. { - const cursor = sql.exec(`SELECT * FROM tbl`) - Array.from(cursor) // Consume all the results - assert.equal(cursor.rowsRead, 2) + const cursor = sql.exec(`SELECT * FROM tbl`); + Array.from(cursor); // Consume all the results + assert.equal(cursor.rowsRead, 2); } // Each invocation of a prepared statement gets its own counters. { - const id1 = 101 - const id2 = 202 - - const prepared = sql.prepare(`INSERT INTO tbl (id, value) VALUES (?, ?)`) - const cursor123 = prepared(id1, 'value1') - Array.from(cursor123) - assert.equal(cursor123.rowsWritten, 1) - - const cursor456 = prepared(id2, 'value2') - Array.from(cursor456) - assert.equal(cursor456.rowsWritten, 1) - assert.equal(cursor123.rowsWritten, 1) // remained unchanged + const id1 = 101; + const id2 = 202; + + const prepared = sql.prepare(`INSERT INTO tbl (id, value) VALUES (?, ?)`); + const cursor123 = prepared(id1, 'value1'); + Array.from(cursor123); + assert.equal(cursor123.rowsWritten, 1); + + const cursor456 = prepared(id2, 'value2'); + Array.from(cursor456); + assert.equal(cursor456.rowsWritten, 1); + assert.equal(cursor123.rowsWritten, 1); // remained unchanged } // Row counters are updated as you consume the cursor. { - sql.exec(`DELETE FROM tbl`) - const prepared = sql.prepare(`INSERT INTO tbl (id, value) VALUES (?, ?)`) + sql.exec(`DELETE FROM tbl`); + const prepared = sql.prepare(`INSERT INTO tbl (id, value) VALUES (?, ?)`); for (let i = 1; i <= 10; i++) { - Array.from(prepared(i, 'value' + i)) + Array.from(prepared(i, 'value' + i)); } - const cursor = sql.exec(`SELECT * FROM tbl`) - const resultsIterator = cursor[Symbol.iterator]() - let rowsSeen = 0 + const cursor = sql.exec(`SELECT * FROM tbl`); + const resultsIterator = cursor[Symbol.iterator](); + let rowsSeen = 0; while (true) { - const result = resultsIterator.next() + const result = resultsIterator.next(); if (result.done) { - break + break; } - assert.equal(++rowsSeen, cursor.rowsRead) + assert.equal(++rowsSeen, cursor.rowsRead); } } // Row counters can track interleaved cursors { - const join = [] - const colCounts = [] + const join = []; + const colCounts = []; // In-JS joining of two tables should be possible: - const rows = sql.exec(`SELECT * FROM abc`) + const rows = sql.exec(`SELECT * FROM abc`); for (let row of rows) { - const cols = sql.exec(`SELECT * FROM cde`) + const cols = sql.exec(`SELECT * FROM cde`); for (let col of cols) { - join.push({ row, col }) + join.push({ row, col }); } - colCounts.push(cols.rowsRead) + colCounts.push(cols.rowsRead); } assert.deepEqual(join, [ { col: { c: 7, d: 8, e: 9 }, row: { a: 1, b: 2, c: 3 } }, { col: { c: 1, d: 2, e: 3 }, row: { a: 1, b: 2, c: 3 } }, { col: { c: 7, d: 8, e: 9 }, row: { a: 4, b: 5, c: 6 } }, { col: { c: 1, d: 2, e: 3 }, row: { a: 4, b: 5, c: 6 } }, - ]) - assert.deepEqual(rows.rowsRead, 2) - assert.deepEqual(colCounts, [2, 2]) + ]); + assert.deepEqual(rows.rowsRead, 2); + assert.deepEqual(colCounts, [2, 2]); } // Temporary tables (i.e. for IN clauses) don't contribute to rowsWritten { - const cursor = sql.exec(`SELECT * FROM abc WHERE a IN (1,2,3,4,5,6)`) - const rows = Array.from(cursor) - assert.deepEqual(cursor.rowsRead, 2) - assert.deepEqual(cursor.rowsWritten, 0) + const cursor = sql.exec(`SELECT * FROM abc WHERE a IN (1,2,3,4,5,6)`); + const rows = Array.from(cursor); + assert.deepEqual(cursor.rowsRead, 2); + assert.deepEqual(cursor.rowsWritten, 0); } } async function testForeignKeys(storage) { - const sql = storage.sql + const sql = storage.sql; // Test defer_foreign_keys { - sql.exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);`) + sql.exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);`); sql.exec( `CREATE TABLE posts (id INTEGER PRIMARY KEY, user_id INTEGER, content TEXT, FOREIGN KEY(user_id) REFERENCES users(id));` - ) + ); - await scheduler.wait(1) + await scheduler.wait(1); // By default, primary keys are enforced: assert.throws( @@ -1041,10 +1064,10 @@ async function testForeignKeys(storage) { 'Post 1' ), /Error: FOREIGN KEY constraint failed/ - ) + ); // Transactions fail immediately too - let passed_first_statement = false + let passed_first_statement = false; assert.throws( () => storage.transactionSync(() => { @@ -1052,63 +1075,63 @@ async function testForeignKeys(storage) { `INSERT INTO posts (user_id, content) VALUES (?, ?)`, 1, 'Post 1' - ) - passed_first_statement = true + ); + passed_first_statement = true; }), /Error: FOREIGN KEY constraint failed/ - ) - assert.equal(passed_first_statement, false) + ); + assert.equal(passed_first_statement, false); - await scheduler.wait(1) + await scheduler.wait(1); // With defer_foreign_keys, we can insert things out-of-order within transactions, // as long as the data is valid by the end. storage.transactionSync(() => { - sql.exec(`PRAGMA defer_foreign_keys=ON;`) + sql.exec(`PRAGMA defer_foreign_keys=ON;`); sql.exec( `INSERT INTO posts (user_id, content) VALUES (?, ?)`, 1, 'Post 1' - ) - sql.exec(`INSERT INTO users VALUES (?, ?)`, 1, 'Alice') - }) + ); + sql.exec(`INSERT INTO users VALUES (?, ?)`, 1, 'Alice'); + }); - await scheduler.wait(1) + await scheduler.wait(1); // But if we use defer_foreign_keys but try to commit, it resets the DO storage.transactionSync(() => { - sql.exec(`PRAGMA defer_foreign_keys=ON;`) + sql.exec(`PRAGMA defer_foreign_keys=ON;`); sql.exec( `INSERT INTO posts (user_id, content) VALUES (?, ?)`, 2, 'Post 2' - ) - }) + ); + }); } } async function testStreamingIngestion(request, storage) { - const { sql } = storage + const { sql } = storage; - sql.exec(`CREATE TABLE streaming(val TEXT);`) + sql.exec(`CREATE TABLE streaming(val TEXT);`); await storage.transaction(async () => { - const stream = request.body.pipeThrough(new TextDecoderStream()) - let buffer = '' + const stream = request.body.pipeThrough(new TextDecoderStream()); + let buffer = ''; for await (const chunk of stream) { // Append the new chunk to the existing buffer - buffer += chunk + buffer += chunk; // Ingest any complete statements and snip those chars off the buffer - buffer = sql.ingest(buffer).remainder + buffer = sql.ingest(buffer).remainder; } - }) + }); // Verify exactly 36 rows were added assert.deepEqual(Array.from(sql.exec(`SELECT count(*) FROM streaming`)), [ { 'count(*)': 36 }, - ]) + ]); assert.deepEqual( Array.from(sql.exec(`SELECT * FROM streaming WHERE val LIKE 'f%'`)), [ @@ -1119,63 +1142,63 @@ async function testStreamingIngestion(request, storage) { { val: 'f: 🥺' }, { val: 'f: 🔥😎🔥' }, ] - ) + ); } export class DurableObjectExample { constructor(state, env) { - this.state = state + this.state = state; } async fetch(req) { if (req.url.endsWith('/sql-test')) { - await test(this.state) - return Response.json({ ok: true }) + await test(this.state); + return Response.json({ ok: true }); } else if (req.url.endsWith('/sql-test-foreign-keys')) { - await testForeignKeys(this.state.storage) - return Response.json({ ok: true }) + await testForeignKeys(this.state.storage); + return Response.json({ ok: true }); } else if (req.url.endsWith('/increment')) { - let val = (await this.state.storage.get('counter')) || 0 - ++val - this.state.storage.put('counter', val) - return Response.json(val) + let val = (await this.state.storage.get('counter')) || 0; + ++val; + this.state.storage.put('counter', val); + return Response.json(val); } else if (req.url.endsWith('/break')) { // This `put()` should be discarded due to the actor aborting immediately after. - this.state.storage.put('counter', 888) + this.state.storage.put('counter', 888); // Abort the actor, which also cancels unflushed writes. - this.state.abort('test broken') + this.state.abort('test broken'); // abort() always throws. - throw new Error("can't get here") + throw new Error("can't get here"); } else if (req.url.endsWith('/sql-test-io-stats')) { - await testIoStats(this.state.storage) - return Response.json({ ok: true }) + await testIoStats(this.state.storage); + return Response.json({ ok: true }); } else if (req.url.endsWith('/streaming-ingestion')) { - await testStreamingIngestion(req, this.state.storage) - return Response.json({ ok: true }) + await testStreamingIngestion(req, this.state.storage); + return Response.json({ ok: true }); } - throw new Error('unknown url: ' + req.url) + throw new Error('unknown url: ' + req.url); } } export default { async test(ctrl, env, ctx) { - let id = env.ns.idFromName('A') - let obj = env.ns.get(id) + let id = env.ns.idFromName('A'); + let obj = env.ns.get(id); // Now let's test persistence through breakage and atomic write coalescing. let doReq = async (path, init = {}) => { - let resp = await obj.fetch('http://foo/' + path, init) - return await resp.json() - } + let resp = await obj.fetch('http://foo/' + path, init); + return await resp.json(); + }; // Test SQL API - assert.deepEqual(await doReq('sql-test'), { ok: true }) + assert.deepEqual(await doReq('sql-test'), { ok: true }); // Test SQL IO stats - assert.deepEqual(await doReq('sql-test-io-stats'), { ok: true }) + assert.deepEqual(await doReq('sql-test-io-stats'), { ok: true }); // Test SQL streaming ingestion assert.deepEqual( @@ -1183,11 +1206,11 @@ export default { method: 'POST', body: new ReadableStream({ async start(controller) { - const data = new TextEncoder().encode(INSERT_36_ROWS) + const data = new TextEncoder().encode(INSERT_36_ROWS); // Pick a value for chunkSize that splits the first emoji in half - const chunkSize = INSERT_36_ROWS.indexOf('😳') + 1 - assert.equal(chunkSize, 35) // Validate we're getting the value we expect + const chunkSize = INSERT_36_ROWS.indexOf('😳') + 1; + assert.equal(chunkSize, 35); // Validate we're getting the value we expect // Send each chunk with a wait of 1ms in between for ( @@ -1195,41 +1218,41 @@ export default { offset < data.length - 1; offset += chunkSize ) { - controller.enqueue(data.slice(offset, offset + chunkSize)) - await scheduler.wait(1) + controller.enqueue(data.slice(offset, offset + chunkSize)); + await scheduler.wait(1); } - controller.close() + controller.close(); }, }), }), { ok: true } - ) + ); // Test defer_foreign_keys (explodes the DO) await assert.rejects(async () => { - await doReq('sql-test-foreign-keys') - }, /Error: internal error/) + await doReq('sql-test-foreign-keys'); + }, /Error: internal error/); // Some increments. - assert.equal(await doReq('increment'), 1) - assert.equal(await doReq('increment'), 2) + assert.equal(await doReq('increment'), 1); + assert.equal(await doReq('increment'), 2); // Now induce a failure. await assert.rejects( async () => { - await doReq('break') + await doReq('break'); }, (err) => err.message === 'test broken' && err.durableObjectReset - ) + ); // Get a new stub. - obj = env.ns.get(id) + obj = env.ns.get(id); // Everything's still consistent. - assert.equal(await doReq('increment'), 3) + assert.equal(await doReq('increment'), 3); }, -} +}; const INSERT_36_ROWS = ['a', 'b', 'c', 'd', 'e', 'f'] .map( @@ -1238,4 +1261,4 @@ const INSERT_36_ROWS = ['a', 'b', 'c', 'd', 'e', 'f'] .map((suffix) => `('${prefix}: ${suffix}')`) .join(',')};` ) - .join(' ') + .join(' '); diff --git a/src/workerd/api/streams/identitytransformstream-backpressure-test.js b/src/workerd/api/streams/identitytransformstream-backpressure-test.js index 4770d47ac3c..3f6a2f9b42e 100644 --- a/src/workerd/api/streams/identitytransformstream-backpressure-test.js +++ b/src/workerd/api/streams/identitytransformstream-backpressure-test.js @@ -2,10 +2,7 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { - notStrictEqual, - strictEqual, -} from 'node:assert'; +import { notStrictEqual, strictEqual } from 'node:assert'; export const identityTransformStream = { async test(ctrl, env, ctx) { @@ -50,7 +47,7 @@ export const identityTransformStream = { // If we read again, the backpressure should be fully resolved. await reader.read(); strictEqual(writer.desiredSize, 10); - } + }, }; export const identityTransformStreamNoHWM = { @@ -96,7 +93,7 @@ export const identityTransformStreamNoHWM = { // If we read again, the backpressure should be fully resolved. await reader.read(); strictEqual(writer.desiredSize, 1); - } + }, }; export const fixedLengthStream = { @@ -141,5 +138,5 @@ export const fixedLengthStream = { // If we read again, the backpressure should be fully resolved. await reader.read(); strictEqual(writer.desiredSize, 10); - } + }, }; diff --git a/src/workerd/api/streams/streams-test.js b/src/workerd/api/streams/streams-test.js index 7b81f779594..39385078218 100644 --- a/src/workerd/api/streams/streams-test.js +++ b/src/workerd/api/streams/streams-test.js @@ -5,7 +5,7 @@ import * as assert from 'node:assert'; import * as util from 'node:util'; -export const partiallyReadStream= { +export const partiallyReadStream = { async test(ctrl, env, ctx) { const enc = new TextEncoder(); const rs = new ReadableStream({ @@ -14,35 +14,35 @@ export const partiallyReadStream= { controller.enqueue(enc.encode('hello')); controller.enqueue(enc.encode('world')); controller.close(); - } + }, }); const reader = rs.getReader({ mode: 'byob' }); await reader.read(new Uint8Array(5)); reader.releaseLock(); // Should not throw! - await env.KV.put("key", rs); - } + await env.KV.put('key', rs); + }, }; export const arrayBufferOfReadable = { async test() { - const cs = new CompressionStream("gzip"); + const cs = new CompressionStream('gzip'); const cw = cs.writable.getWriter(); - await cw.write(new TextEncoder().encode("0123456789".repeat(1000))); + await cw.write(new TextEncoder().encode('0123456789'.repeat(1000))); await cw.close(); const data = await new Response(cs.readable).arrayBuffer(); assert.equal(66, data.byteLength); - const ds = new DecompressionStream("gzip"); + const ds = new DecompressionStream('gzip'); const dw = ds.writable.getWriter(); await dw.write(data); await dw.close(); const read = await new Response(ds.readable).arrayBuffer(); assert.equal(10_000, read.byteLength); - } -} + }, +}; export const inspect = { async test() { @@ -53,10 +53,10 @@ export const inspect = { let pulls = 0; const readableStream = new ReadableStream({ pull(controller) { - if (pulls === 0) controller.enqueue("hello"); + if (pulls === 0) controller.enqueue('hello'); if (pulls === 1) controller.close(); pulls++; - } + }, }); assert.strictEqual( util.inspect(readableStream, inspectOpts), @@ -86,8 +86,8 @@ export const inspect = { { const readableStream = new ReadableStream({ start(controller) { - controller.error(new Error("Oops!")); - } + controller.error(new Error('Oops!')); + }, }); assert.strictEqual( util.inspect(readableStream, inspectOpts), @@ -98,10 +98,10 @@ export const inspect = { // Check with JavaScript bytes ReadableStream { const readableStream = new ReadableStream({ - type: "bytes", + type: 'bytes', pull(controller) { controller.enqueue(new Uint8Array([1])); - } + }, }); assert.strictEqual( util.inspect(readableStream, inspectOpts), @@ -112,7 +112,7 @@ export const inspect = { // Check with JavaScript WritableStream { const writableStream = new WritableStream({ - write(chunk, controller) {} + write(chunk, controller) {}, }); assert.strictEqual( util.inspect(writableStream, inspectOpts), @@ -125,7 +125,7 @@ export const inspect = { "WritableStream { locked: true, [state]: 'writable', [expectsBytes]: false }" ); - await writer.write("chunk"); + await writer.write('chunk'); assert.strictEqual( util.inspect(writableStream, inspectOpts), "WritableStream { locked: true, [state]: 'writable', [expectsBytes]: false }" @@ -142,8 +142,8 @@ export const inspect = { { const writableStream = new WritableStream({ write(chunk, controller) { - controller.error(new Error("Oops!")); - } + controller.error(new Error('Oops!')); + }, }); assert.strictEqual( util.inspect(writableStream, inspectOpts), @@ -151,7 +151,7 @@ export const inspect = { ); const writer = writableStream.getWriter(); - const promise = writer.write("chunk"); + const promise = writer.write('chunk'); assert.strictEqual( util.inspect(writableStream, inspectOpts), "WritableStream { locked: true, [state]: 'erroring', [expectsBytes]: false }" @@ -170,7 +170,7 @@ export const inspect = { const transformStream = new FixedLengthStream(5); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: 5n }, writable: WritableStream { locked: false, [state]: 'writable', [expectsBytes]: true } }` @@ -180,7 +180,7 @@ export const inspect = { const writer = writable.getWriter(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: 5n }, writable: WritableStream { locked: true, [state]: 'writable', [expectsBytes]: true } }` @@ -190,7 +190,7 @@ export const inspect = { void writer.write(new Uint8Array([4, 5])); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: 5n }, writable: WritableStream { locked: true, [state]: 'writable', [expectsBytes]: true } }` @@ -199,7 +199,7 @@ export const inspect = { void writer.close(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: 5n }, writable: WritableStream { locked: true, [state]: 'closed', [expectsBytes]: true } }` @@ -208,7 +208,7 @@ export const inspect = { const reader = readable.getReader(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: true, [state]: 'readable', [supportsBYOB]: true, [length]: 5n }, writable: WritableStream { locked: true, [state]: 'closed', [expectsBytes]: true } }` @@ -217,7 +217,7 @@ export const inspect = { await reader.read(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: true, [state]: 'readable', [supportsBYOB]: true, [length]: 2n }, writable: WritableStream { locked: true, [state]: 'closed', [expectsBytes]: true } }` @@ -226,7 +226,7 @@ export const inspect = { await reader.read(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: true, [state]: 'readable', [supportsBYOB]: true, [length]: 0n }, writable: WritableStream { locked: true, [state]: 'closed', [expectsBytes]: true } }` @@ -235,7 +235,7 @@ export const inspect = { await reader.read(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`FixedLengthStream { + `FixedLengthStream { readable: ReadableStream { locked: true, [state]: 'closed', [supportsBYOB]: true, [length]: 0n }, writable: WritableStream { locked: true, [state]: 'closed', [expectsBytes]: true } }` @@ -248,7 +248,7 @@ export const inspect = { const transformStream = new IdentityTransformStream(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`IdentityTransformStream { + `IdentityTransformStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: undefined }, writable: WritableStream { locked: false, [state]: 'writable', [expectsBytes]: true } }` @@ -256,10 +256,10 @@ export const inspect = { const { writable, readable } = transformStream; const writer = writable.getWriter(); - void writer.abort(new Error("Oops!")); + void writer.abort(new Error('Oops!')); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`IdentityTransformStream { + `IdentityTransformStream { readable: ReadableStream { locked: false, [state]: 'readable', [supportsBYOB]: true, [length]: undefined }, writable: WritableStream { locked: true, [state]: 'errored', [expectsBytes]: true } }` @@ -268,7 +268,7 @@ export const inspect = { const reader = readable.getReader(); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`IdentityTransformStream { + `IdentityTransformStream { readable: ReadableStream { locked: true, [state]: 'readable', [supportsBYOB]: true, [length]: undefined }, writable: WritableStream { locked: true, [state]: 'errored', [expectsBytes]: true } }` @@ -277,11 +277,11 @@ export const inspect = { await reader.read().catch(() => {}); assert.strictEqual( util.inspect(transformStream, inspectOpts), -`IdentityTransformStream { + `IdentityTransformStream { readable: ReadableStream { locked: true, [state]: 'errored', [supportsBYOB]: true, [length]: undefined }, writable: WritableStream { locked: true, [state]: 'errored', [expectsBytes]: true } }` ); } - } + }, }; diff --git a/src/workerd/api/tests/abort-internal-streams-test.js b/src/workerd/api/tests/abort-internal-streams-test.js index 84fa756f230..a2654fff5c4 100644 --- a/src/workerd/api/tests/abort-internal-streams-test.js +++ b/src/workerd/api/tests/abort-internal-streams-test.js @@ -19,5 +19,5 @@ export const abortInternalStreamsTest = { } catch (err) { strictEqual(err, undefined); } - } + }, }; diff --git a/src/workerd/api/tests/abortable-fetch-test.js b/src/workerd/api/tests/abortable-fetch-test.js index 1fc762cf070..7a2dfab196b 100644 --- a/src/workerd/api/tests/abortable-fetch-test.js +++ b/src/workerd/api/tests/abortable-fetch-test.js @@ -1,8 +1,4 @@ -import { - strictEqual, - ok, - throws -} from 'node:assert'; +import { strictEqual, ok, throws } from 'node:assert'; // Test for the AbortSignal and AbortController standard Web API implementations. // The implementation for these are in api/basics.{h|c++} @@ -12,12 +8,14 @@ export const abortControllerAlreadyAborted = { const ac = new AbortController(); ac.abort(); try { - const result = await env.subrequest.fetch('http://example.org', { signal: ac.signal }); + const result = await env.subrequest.fetch('http://example.org', { + signal: ac.signal, + }); throw new Error('should have failed'); } catch (err) { strictEqual(err.message, 'The operation was aborted'); } - } + }, }; export const alreadyAborted = { @@ -29,7 +27,7 @@ export const alreadyAborted = { } catch (err) { strictEqual(err, 'boom'); } - } + }, }; export const timedAbort = { @@ -41,21 +39,23 @@ export const timedAbort = { } catch (err) { strictEqual(err.message, 'The operation was aborted due to timeout'); } - } + }, }; export const abortControllerSyncAbort = { async test(ctrl, env) { const ac = new AbortController(); try { - const promise = env.subrequest.fetch('http://example.org', { signal: ac.signal }); + const promise = env.subrequest.fetch('http://example.org', { + signal: ac.signal, + }); ac.abort(); await promise; throw new Error('should have failed'); } catch (err) { strictEqual(err.message, 'The operation was aborted'); } - } + }, }; export const asyncSubrequest = { @@ -66,7 +66,7 @@ export const asyncSubrequest = { } catch (err) { strictEqual(err.message, 'The operation was aborted due to timeout'); } - } + }, }; export const syncSubrequest = { @@ -77,7 +77,7 @@ export const syncSubrequest = { } catch (err) { strictEqual(err.message, 'The operation was aborted'); } - } + }, }; export const requestAbortSignal = { @@ -90,7 +90,7 @@ export const requestAbortSignal = { const ac = new AbortController(); const req2 = new Request('', { signal: ac.signal }); strictEqual(req2.signal, ac.signal); - } + }, }; export default { @@ -104,13 +104,14 @@ export default { // Verifies that a fetch subrequest returned as the response can be synchronously // aborted. const ac = new AbortController(); - const resp = env.subrequest.fetch('http://example.org', { signal: ac.signal }); + const resp = env.subrequest.fetch('http://example.org', { + signal: ac.signal, + }); ac.abort(); return resp; } else { await scheduler.wait(10000); - return new Response("ok"); + return new Response('ok'); } - } + }, }; - diff --git a/src/workerd/api/tests/abortsignal-test.js b/src/workerd/api/tests/abortsignal-test.js index c8032e51239..3827e9cd472 100644 --- a/src/workerd/api/tests/abortsignal-test.js +++ b/src/workerd/api/tests/abortsignal-test.js @@ -1,8 +1,4 @@ -import { - strictEqual, - ok, - throws -} from 'node:assert'; +import { strictEqual, ok, throws } from 'node:assert'; // Test for the AbortSignal and AbortController standard Web API implementations. // The implementation for these are in api/basics.{h|c++} @@ -10,7 +6,7 @@ import { export const abortcontroller = { test() { // AbortSignal is not directly creatable - throws(() => new AbortSignal); + throws(() => new AbortSignal()); const ac = new AbortController(); ok(ac.signal instanceof AbortSignal); @@ -20,7 +16,7 @@ export const abortcontroller = { strictEqual(ac.signal, ac.signal); // signal is read only - throws(() => ac.signal = 1); + throws(() => (ac.signal = 1)); let invoked = 0; ac.signal.onabort = (event) => { @@ -32,8 +28,8 @@ export const abortcontroller = { ac.signal.throwIfAborted(); // reason and aborted are read only - throws(() => ac.signal.reason = 1); - throws(() => ac.signal.aborted = 'foo'); + throws(() => (ac.signal.reason = 1)); + throws(() => (ac.signal.aborted = 'foo')); // trigger our abort with a default reason... ac.abort(); @@ -54,7 +50,7 @@ export const abortcontroller = { ac.abort(); strictEqual(invoked, 1); - } + }, }; export const abortcontrollerWithReason = { @@ -75,7 +71,7 @@ export const abortcontrollerWithReason = { strictEqual(ac.signal.reason, 'foo'); strictEqual(invoked, 1); - } + }, }; export const alreadyAborted = { @@ -92,14 +88,14 @@ export const alreadyAborted = { } catch (err) { strictEqual(err, 'foo'); } - } + }, }; export const timedAbort = { async test() { const timed = AbortSignal.timeout(100); let resolve; - const promise = new Promise(r => resolve = r); + const promise = new Promise((r) => (resolve = r)); let invoked = 0; timed.onabort = () => { invoked++; @@ -107,7 +103,7 @@ export const timedAbort = { }; await promise; strictEqual(invoked, 1); - } + }, }; export const anyAbort = { @@ -128,7 +124,7 @@ export const anyAbort = { ac.abort(); strictEqual(invoked, 1); - } + }, }; export const anyAbort2 = { @@ -139,7 +135,7 @@ export const anyAbort2 = { let invoked = 0; let resolve; - const promise = new Promise(r => resolve = r); + const promise = new Promise((r) => (resolve = r)); any.onabort = () => { invoked++; @@ -149,7 +145,7 @@ export const anyAbort2 = { await promise; strictEqual(invoked, 1); - } + }, }; export const anyAbort3 = { @@ -161,7 +157,7 @@ export const anyAbort3 = { const any = AbortSignal.any([timed, aborted]); strictEqual(any.aborted, true); strictEqual(any.reason, 123); - } + }, }; export const onabortPrototypeProperty = { @@ -194,5 +190,5 @@ export const onabortPrototypeProperty = { const handler = {}; ac.signal.onabort = handler; strictEqual(ac.signal.onabort, handler); - } + }, }; diff --git a/src/workerd/api/tests/actor-stub-test.js b/src/workerd/api/tests/actor-stub-test.js index 4dab9d1807f..40dde4e148a 100644 --- a/src/workerd/api/tests/actor-stub-test.js +++ b/src/workerd/api/tests/actor-stub-test.js @@ -4,7 +4,7 @@ // We want to test the behavior of the Durable Object stub now that it uses name interception to // behave like a JS Proxy object. -import * as assert from 'node:assert' +import * as assert from 'node:assert'; export class DurableObjectExample { constructor() { @@ -12,12 +12,12 @@ export class DurableObjectExample { } async fetch(request) { - return new Response("OK"); + return new Response('OK'); } async foo() { // Server side impl of foo. - return "foo from remote"; + return 'foo from remote'; } thisCheck() { @@ -35,16 +35,16 @@ export default { // // We should still be able to define names on the stub in JS and get the expected result. - let id = env.ns.idFromName("foo"); + let id = env.ns.idFromName('foo'); let obj = env.ns.get(id); // Since we have the flag enabled, we should be able to call foo(); - let expected = "foo from remote"; + let expected = 'foo from remote'; try { let foo = await obj.foo(); - if (typeof foo != "string" && foo != expected) { + if (typeof foo != 'string' && foo != expected) { throw foo; } - } catch(e) { + } catch (e) { throw new Error(`Expected ${expected} but got ${e}`); } @@ -61,22 +61,24 @@ export default { } // Now let's define a method on our object, we should be able to call it. - obj.baz = () => { return "called baz"; }; - if (typeof obj.baz != "function") { + obj.baz = () => { + return 'called baz'; + }; + if (typeof obj.baz != 'function') { throw new Error(`baz was not a function: ${obj.baz}`); } // Make sure the call works right. - if (obj.baz() != "called baz") { + if (obj.baz() != 'called baz') { throw new Error(`obj.baz() returned unexpected value: ${obj.baz()}`); } // Check the keys again, we should have `baz` now. keys = Object.keys(obj); - if (keys.length != 3 || !(keys.includes("baz"))) { + if (keys.length != 3 || !keys.includes('baz')) { throw new Error(`New Durable Object stub had unexpected keys: ${keys}`); } // End it with a call to the DO. - return await obj.fetch("http://foo/"); - } -} + return await obj.fetch('http://foo/'); + }, +}; diff --git a/src/workerd/api/tests/als-only-test.js b/src/workerd/api/tests/als-only-test.js index 58a8ef18fe0..7f5d8c20183 100644 --- a/src/workerd/api/tests/als-only-test.js +++ b/src/workerd/api/tests/als-only-test.js @@ -1,11 +1,8 @@ -import { - AsyncLocalStorage, -} from 'node:async_hooks'; +import { AsyncLocalStorage } from 'node:async_hooks'; export const customthenable = { // Test to ensure that async context is propagated into custom thenables. async test() { - // This should just work const als = new AsyncLocalStorage(); if (!(als instanceof AsyncLocalStorage)) { @@ -21,5 +18,5 @@ export const customthenable = { throw err; } } - } + }, }; diff --git a/src/workerd/api/tests/als-test.js b/src/workerd/api/tests/als-test.js index cad43928a1a..16347a9558a 100644 --- a/src/workerd/api/tests/als-test.js +++ b/src/workerd/api/tests/als-test.js @@ -1,10 +1,6 @@ -import { - strictEqual, -} from 'node:assert'; +import { strictEqual } from 'node:assert'; -import { - AsyncLocalStorage, -} from 'node:async_hooks'; +import { AsyncLocalStorage } from 'node:async_hooks'; export const customthenable = { // Test to ensure that async context is propagated into custom thenables. @@ -14,18 +10,20 @@ export const customthenable = { return await { then(done) { done(als.getStore()); - } + }, }; }); strictEqual(result, 123); const result2 = await als.run(123, async () => { - return await new Promise((resolve) => resolve({ - then(done) { - done(als.getStore()); - } - })); + return await new Promise((resolve) => + resolve({ + then(done) { + done(als.getStore()); + }, + }) + ); }); strictEqual(result2, 123); - } + }, }; diff --git a/src/workerd/api/tests/blob-test.js b/src/workerd/api/tests/blob-test.js index 2c4ed8439e8..9eac63b3a1d 100644 --- a/src/workerd/api/tests/blob-test.js +++ b/src/workerd/api/tests/blob-test.js @@ -7,36 +7,41 @@ import { inspect } from 'node:util'; export const test1 = { async test(ctrl, env, ctx) { - let blob = new Blob(["foo", new TextEncoder().encode("bar"), "baz"]); - strictEqual(await blob.text(), "foobarbaz"); - strictEqual(new TextDecoder().decode(await blob.arrayBuffer()), "foobarbaz"); - strictEqual(blob.type, ""); - - let blob2 = new Blob(["xx", blob, "yy", blob], {type: "application/whatever"}); - strictEqual(await blob2.text(), "xxfoobarbazyyfoobarbaz"); - strictEqual(blob2.type, "application/whatever"); + let blob = new Blob(['foo', new TextEncoder().encode('bar'), 'baz']); + strictEqual(await blob.text(), 'foobarbaz'); + strictEqual( + new TextDecoder().decode(await blob.arrayBuffer()), + 'foobarbaz' + ); + strictEqual(blob.type, ''); + + let blob2 = new Blob(['xx', blob, 'yy', blob], { + type: 'application/whatever', + }); + strictEqual(await blob2.text(), 'xxfoobarbazyyfoobarbaz'); + strictEqual(blob2.type, 'application/whatever'); let blob3 = new Blob(); - strictEqual(await blob3.text(), ""); + strictEqual(await blob3.text(), ''); let slice = blob2.slice(5, 16); - strictEqual(await slice.text(), "barbazyyfoo"); - strictEqual(slice.type, ""); + strictEqual(await slice.text(), 'barbazyyfoo'); + strictEqual(slice.type, ''); - let slice2 = slice.slice(-5, 1234, "type/type"); - strictEqual(await slice2.text(), "yyfoo"); - strictEqual(slice2.type, "type/type"); + let slice2 = slice.slice(-5, 1234, 'type/type'); + strictEqual(await slice2.text(), 'yyfoo'); + strictEqual(slice2.type, 'type/type'); - strictEqual(await blob2.slice(5).text(), "barbazyyfoobarbaz"); - strictEqual(await blob2.slice().text(), "xxfoobarbazyyfoobarbaz"); - strictEqual(await blob2.slice(3, 1).text(), ""); + strictEqual(await blob2.slice(5).text(), 'barbazyyfoobarbaz'); + strictEqual(await blob2.slice().text(), 'xxfoobarbazyyfoobarbaz'); + strictEqual(await blob2.slice(3, 1).text(), ''); { let stream = blob.stream(); let reader = stream.getReader(); let readResult = await reader.read(); strictEqual(readResult.done, false); - strictEqual(new TextDecoder().decode(readResult.value), "foobarbaz"); + strictEqual(new TextDecoder().decode(readResult.value), 'foobarbaz'); readResult = await reader.read(); strictEqual(readResult.value, undefined); strictEqual(readResult.done, true); @@ -45,68 +50,84 @@ export const test1 = { let before = Date.now(); - let file = new File([blob, "qux"], "filename.txt"); + let file = new File([blob, 'qux'], 'filename.txt'); strictEqual(file instanceof Blob, true); - strictEqual(await file.text(), "foobarbazqux"); - strictEqual(file.name, "filename.txt"); - strictEqual(file.type, ""); + strictEqual(await file.text(), 'foobarbazqux'); + strictEqual(file.name, 'filename.txt'); + strictEqual(file.type, ''); if (file.lastModified < before || file.lastModified > Date.now()) { - throw new Error("incorrect lastModified"); + throw new Error('incorrect lastModified'); } - let file2 = new File(["corge", file], "file2", {type: "text/foo", lastModified: 123}); - strictEqual(await file2.text(), "corgefoobarbazqux"); - strictEqual(file2.name, "file2"); - strictEqual(file2.type, "text/foo"); + let file2 = new File(['corge', file], 'file2', { + type: 'text/foo', + lastModified: 123, + }); + strictEqual(await file2.text(), 'corgefoobarbazqux'); + strictEqual(file2.name, 'file2'); + strictEqual(file2.type, 'text/foo'); strictEqual(file2.lastModified, 123); try { - new Blob(["foo"], {endings: "native"}); + new Blob(['foo'], { endings: 'native' }); throw new Error("use of 'endings' should throw"); } catch (err) { - if (!err.message.includes("The 'endings' field on 'Options' is not implemented.")) { + if ( + !err.message.includes( + "The 'endings' field on 'Options' is not implemented." + ) + ) { throw err; } } // Test type normalization. - strictEqual(new Blob([], {type: "FoO/bAr"}).type, "foo/bar"); - strictEqual(new Blob([], {type: "FoO\u0019/bAr"}).type, ""); - strictEqual(new Blob([], {type: "FoO\u0020/bAr"}).type, "foo /bar"); - strictEqual(new Blob([], {type: "FoO\u007e/bAr"}).type, "foo\u007e/bar"); - strictEqual(new Blob([], {type: "FoO\u0080/bAr"}).type, ""); - strictEqual(new File([], "foo.txt", {type: "FoO/bAr"}).type, "foo/bar"); - strictEqual(blob2.slice(1, 2, "FoO/bAr").type, "foo/bar"); - } + strictEqual(new Blob([], { type: 'FoO/bAr' }).type, 'foo/bar'); + strictEqual(new Blob([], { type: 'FoO\u0019/bAr' }).type, ''); + strictEqual(new Blob([], { type: 'FoO\u0020/bAr' }).type, 'foo /bar'); + strictEqual(new Blob([], { type: 'FoO\u007e/bAr' }).type, 'foo\u007e/bar'); + strictEqual(new Blob([], { type: 'FoO\u0080/bAr' }).type, ''); + strictEqual(new File([], 'foo.txt', { type: 'FoO/bAr' }).type, 'foo/bar'); + strictEqual(blob2.slice(1, 2, 'FoO/bAr').type, 'foo/bar'); + }, }; export const test2 = { async test(ctrl, env, ctx) { // This test verifies that a Blob created from a request/response properly reflects // the content and content-type specified by the request/response. - const res = await env['request-blob'].fetch('http://example.org/blob-request', { - method: 'POST', - body: 'abcd1234', - headers: { 'content-type': 'some/type' } - }); + const res = await env['request-blob'].fetch( + 'http://example.org/blob-request', + { + method: 'POST', + body: 'abcd1234', + headers: { 'content-type': 'some/type' }, + } + ); strictEqual(res.headers.get('content-type'), 'return/type'); strictEqual(await res.text(), 'foobarbaz'); }, async doTest(request) { let b = await request.blob(); - strictEqual(await b.text(), "abcd1234"); - strictEqual(b.type, "some/type"); + strictEqual(await b.text(), 'abcd1234'); + strictEqual(b.type, 'some/type'); // Quick check that content-type header is correctly not set when the blob type is an empty // string. - strictEqual(new Response(new Blob(["typeful"], {type: "foo"})) - .headers.has("Content-Type"), true); - strictEqual(new Response(new Blob(["typeless"])) - .headers.has("Content-Type"), false); - - return new Response(new Blob(["foobar", "baz"], {type: "return/type"})); - } + strictEqual( + new Response(new Blob(['typeful'], { type: 'foo' })).headers.has( + 'Content-Type' + ), + true + ); + strictEqual( + new Response(new Blob(['typeless'])).headers.has('Content-Type'), + false + ); + + return new Response(new Blob(['foobar', 'baz'], { type: 'return/type' })); + }, }; export default { @@ -116,35 +137,47 @@ export default { } else { throw new Error('Unexpected test request'); } - } + }, }; export const testInspect = { async test(ctrl, env, ctx) { - const blob = new Blob(["abc"], { type: "text/plain" }); + const blob = new Blob(['abc'], { type: 'text/plain' }); strictEqual(inspect(blob), "Blob { size: 3, type: 'text/plain' }"); - const file = new File(["1"], "file.txt", { type: "text/plain", lastModified: 1000 }); - strictEqual(inspect(file), "File { name: 'file.txt', lastModified: 1000, size: 1, type: 'text/plain' }"); - } + const file = new File(['1'], 'file.txt', { + type: 'text/plain', + lastModified: 1000, + }); + strictEqual( + inspect(file), + "File { name: 'file.txt', lastModified: 1000, size: 1, type: 'text/plain' }" + ); + }, }; export const overLarge = { test() { const blob1 = new Blob([new ArrayBuffer(128 * 1024 * 1024)]); - throws(() => { - new Blob([new ArrayBuffer((128 * 1024 * 1024) + 1)]); - }, { - message: 'Blob size 134217729 exceeds limit 134217728', - name: 'RangeError', - }); - - throws(() => { - new Blob([' ', blob1]); - }, { - message: 'Blob size 134217729 exceeds limit 134217728', - name: 'RangeError', - }); - } + throws( + () => { + new Blob([new ArrayBuffer(128 * 1024 * 1024 + 1)]); + }, + { + message: 'Blob size 134217729 exceeds limit 134217728', + name: 'RangeError', + } + ); + + throws( + () => { + new Blob([' ', blob1]); + }, + { + message: 'Blob size 134217729 exceeds limit 134217728', + name: 'RangeError', + } + ); + }, }; diff --git a/src/workerd/api/tests/blob2-test.js b/src/workerd/api/tests/blob2-test.js index 79f2f5c9edc..5149e2dd82a 100644 --- a/src/workerd/api/tests/blob2-test.js +++ b/src/workerd/api/tests/blob2-test.js @@ -2,18 +2,14 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { - ok, - strictEqual, - deepStrictEqual, -} from 'node:assert'; +import { ok, strictEqual, deepStrictEqual } from 'node:assert'; export const test = { async test() { const res = new Response('test', { headers: { 'content-type': 'text/plain, x/y, text/html', - } + }, }); const blob = await res.blob(); @@ -23,7 +19,7 @@ export const test = { strictEqual(await blob.text(), 'test'); strictEqual(blob.type, 'text/html'); - } + }, }; export const bytes = { @@ -38,5 +34,5 @@ export const bytes = { const u8_2 = await res.bytes(); deepStrictEqual(u8_2, check); ok(u8_2 instanceof Uint8Array); - } + }, }; diff --git a/src/workerd/api/tests/commonjs-module-test.js b/src/workerd/api/tests/commonjs-module-test.js index 0205c42d5fc..e320dfc3a48 100644 --- a/src/workerd/api/tests/commonjs-module-test.js +++ b/src/workerd/api/tests/commonjs-module-test.js @@ -10,5 +10,5 @@ export const test = { strictEqual(foo, 1); strictEqual(bar, undefined); strictEqual(baz.foo, foo); - } + }, }; diff --git a/src/workerd/api/tests/crypto-extras-test.js b/src/workerd/api/tests/crypto-extras-test.js index 6a1fa218e0b..d329ef01240 100644 --- a/src/workerd/api/tests/crypto-extras-test.js +++ b/src/workerd/api/tests/crypto-extras-test.js @@ -1,12 +1,7 @@ -import { - strictEqual, - ok, - throws -} from 'node:assert'; +import { strictEqual, ok, throws } from 'node:assert'; export const timingSafeEqual = { test() { - // Note that this does not actually test that the equality check is, // in fact, timing safe. It checks only the basic operation of the API @@ -24,7 +19,7 @@ export const timingSafeEqual = { [ [enc.encode('hello'), enc.encode('there')], - [new Uint8Array([1,2,3,4]), new Uint32Array([1])], + [new Uint8Array([1, 2, 3, 4]), new Uint32Array([1])], ].forEach(([a, b]) => { if (crypto.subtle.timingSafeEqual(a, b)) { throw new Error('inputs should not have been equal', a, b); @@ -40,13 +35,13 @@ export const timingSafeEqual = { throw new Error('inputs should have caused an error', a, b); } catch {} }); - - } + }, }; export const randomUuid = { test() { - const pattern = /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[ab89][a-f0-9]{3}-[a-f0-9]{12}/; + const pattern = + /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[ab89][a-f0-9]{3}-[a-f0-9]{12}/; // Loop through a bunch of generated UUID's to make sure we're consistently successful. for (let n = 0; n < 100; n++) { const uuid = crypto.randomUUID(); @@ -54,46 +49,60 @@ export const randomUuid = { throw new Error(`${uuid} is not a valid random UUID`); } } - } + }, }; export const cryptoGcmIvZeroLength = { async test() { - const key = await crypto.subtle.generateKey({ - name: 'AES-GCM', - length: 256 - }, true, ['encrypt', 'decrypt']); + const key = await crypto.subtle.generateKey( + { + name: 'AES-GCM', + length: 256, + }, + true, + ['encrypt', 'decrypt'] + ); for (const op of ['encrypt', 'decrypt']) { - await crypto.subtle[op]({ - name: 'AES-GCM', - iv: new ArrayBuffer(0) - }, key, new ArrayBuffer(100)).then(() => { - throw new Error('should not have resolved'); - }, (err) => { - if (err.constructor !== DOMException || - err.message !== 'AES-GCM IV must not be empty.') { - throw err; + await crypto.subtle[op]( + { + name: 'AES-GCM', + iv: new ArrayBuffer(0), + }, + key, + new ArrayBuffer(100) + ).then( + () => { + throw new Error('should not have resolved'); + }, + (err) => { + if ( + err.constructor !== DOMException || + err.message !== 'AES-GCM IV must not be empty.' + ) { + throw err; + } } - }); + ); } - } + }, }; export const cryptoZeroLength = { async test() { - function hex2Uint8Array(str) { var v = str.match(/.{1,2}/g); var buf = new Uint8Array((str.length + 1) / 2); for (var i = 0; i < v.length; i++) { buf[i] = parseInt(v[i], 16); } - return buf + return buf; } function arrayBuffer2hex(arr) { - return Array.from(new Uint8Array(arr)).map(i => ('0' + i.toString(16)).slice(-2)).join(''); + return Array.from(new Uint8Array(arr)) + .map((i) => ('0' + i.toString(16)).slice(-2)) + .join(''); } // Try using a zero-length input to various crypto functions. This should be valid. @@ -104,53 +113,68 @@ export const cryptoZeroLength = { const empty = new ArrayBuffer(); const DIGESTS = { - "MD5": "d41d8cd98f00b204e9800998ecf8427e", - "SHA-1": "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "SHA-256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "SHA-512": "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + MD5: 'd41d8cd98f00b204e9800998ecf8427e', + 'SHA-1': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', + 'SHA-256': + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + 'SHA-512': + 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', }; for (const name in DIGESTS) { const result = arrayBuffer2hex(await crypto.subtle.digest(name, empty)); if (result != DIGESTS[name]) { - throw new Error("for " + name + ", expected " + DIGESTS[name] + " got " + result); + throw new Error( + 'for ' + name + ', expected ' + DIGESTS[name] + ' got ' + result + ); } } const ENCRYPTS = { - "AES-CBC": "dd3eedef984211b98384dc5677bc728e", - "AES-GCM": "fedbd1a722cb7c1a52f529e0469ee449" + 'AES-CBC': 'dd3eedef984211b98384dc5677bc728e', + 'AES-GCM': 'fedbd1a722cb7c1a52f529e0469ee449', }; for (const name in ENCRYPTS) { - const key = await crypto.subtle.importKey("raw", - new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf]), - name, true, ["encrypt"]); - const result = arrayBuffer2hex(await crypto.subtle.encrypt( - {name, iv: new Uint8Array(16)}, key, empty)); + const key = await crypto.subtle.importKey( + 'raw', + new Uint8Array([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + ]), + name, + true, + ['encrypt'] + ); + const result = arrayBuffer2hex( + await crypto.subtle.encrypt( + { name, iv: new Uint8Array(16) }, + key, + empty + ) + ); if (result != ENCRYPTS[name]) { - throw new Error("for " + name + ", expected " + ENCRYPTS[name] + " got " + result); + throw new Error( + 'for ' + name + ', expected ' + ENCRYPTS[name] + ' got ' + result + ); } } - - } + }, }; export const deriveBitsNullLength = { async test() { - // Tests that deriveBits can take a null or undefined length // argument and still return the correct number of bits if // the algorithm supports it. This is a recent spec change. const pair = await crypto.subtle.generateKey( { - name: "ECDH", - namedCurve: "P-384", + name: 'ECDH', + namedCurve: 'P-384', }, false, - ["deriveBits"], + ['deriveBits'] ); { @@ -160,7 +184,8 @@ export const deriveBitsNullLength = { namedCurve: 'P-384', public: pair.publicKey, }, - pair.privateKey, undefined + pair.privateKey, + undefined ); strictEqual(bits.byteLength, 48); @@ -173,7 +198,8 @@ export const deriveBitsNullLength = { namedCurve: 'P-384', public: pair.publicKey, }, - pair.privateKey, null + pair.privateKey, + null ); strictEqual(bits.byteLength, 48); @@ -191,6 +217,5 @@ export const deriveBitsNullLength = { strictEqual(bits.byteLength, 48); } - - } + }, }; diff --git a/src/workerd/api/tests/crypto-impl-asymmetric-test.js b/src/workerd/api/tests/crypto-impl-asymmetric-test.js index 5217c726bce..60a201ebfe1 100644 --- a/src/workerd/api/tests/crypto-impl-asymmetric-test.js +++ b/src/workerd/api/tests/crypto-impl-asymmetric-test.js @@ -10,13 +10,13 @@ export const rsa_reject_infinite_loop_test = { await assert.rejects( crypto.subtle.generateKey( { - name: "RSASSA-PKCS1-v1_5", - hash: "SHA-256", + name: 'RSASSA-PKCS1-v1_5', + hash: 'SHA-256', modulusLength: 1024, publicExponent: new Uint8Array([1]), }, false, - ["sign", "verify"] + ['sign', 'verify'] ), { message: 'The "publicExponent" must be either 3 or 65537, but got 1.' } ); @@ -24,52 +24,54 @@ export const rsa_reject_infinite_loop_test = { await assert.rejects( crypto.subtle.generateKey( { - name: "RSA-PSS", - hash: "SHA-256", + name: 'RSA-PSS', + hash: 'SHA-256', modulusLength: 1024, publicExponent: new Uint8Array([1]), }, false, - ["sign", "verify"] + ['sign', 'verify'] ), - { message: 'The "publicExponent" must be either 3 or 65537, but got 1.', } + { message: 'The "publicExponent" must be either 3 or 65537, but got 1.' } ); - } -} + }, +}; export const eddsa_test = { async test(ctrl, env, ctx) { // Test EDDSA ED25519 generateKey const edKey = await crypto.subtle.generateKey( { - name: "NODE-ED25519", - namedCurve: "NODE-ED25519", + name: 'NODE-ED25519', + namedCurve: 'NODE-ED25519', }, false, - ["sign", "verify"] + ['sign', 'verify'] ); - assert.ok(edKey.publicKey.algorithm.name == "NODE-ED25519"); - } -} + assert.ok(edKey.publicKey.algorithm.name == 'NODE-ED25519'); + }, +}; export const publicExponent_type_test = { async test(ctrl, env, ctx) { const key = await crypto.subtle.generateKey( { - name: "RSA-PSS", - hash: "SHA-256", + name: 'RSA-PSS', + hash: 'SHA-256', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), }, false, - ["sign", "verify"] + ['sign', 'verify'] ); // Check that a Uint8Array is used for publicExponent. Without the // crypto_preserve_public_exponent feature flag, this would incorrectly return an ArrayBuffer. - assert.ok(key.publicKey.algorithm.publicExponent[Symbol.toStringTag] == "Uint8Array"); - } -} + assert.ok( + key.publicKey.algorithm.publicExponent[Symbol.toStringTag] == 'Uint8Array' + ); + }, +}; export const ecdhJwkTest = { async test() { @@ -79,11 +81,16 @@ export const ecdhJwkTest = { alg: 'THIS CAN BE ANYTHING', x: 'Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0', y: 'HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw', - } + }; // The import should succeed with no errors. // Refs: https://github.com/cloudflare/workerd/issues/1403 - await crypto.subtle.importKey('jwk', publicJwk, - { name: 'ECDH', namedCurve: 'P-256' }, true, []); - } + await crypto.subtle.importKey( + 'jwk', + publicJwk, + { name: 'ECDH', namedCurve: 'P-256' }, + true, + [] + ); + }, }; diff --git a/src/workerd/api/tests/crypto-streams-test.js b/src/workerd/api/tests/crypto-streams-test.js index 68da2e4d219..1ce4171abdd 100644 --- a/src/workerd/api/tests/crypto-streams-test.js +++ b/src/workerd/api/tests/crypto-streams-test.js @@ -1,15 +1,10 @@ -import { - strictEqual, - deepStrictEqual, - rejects, - throws, -} from 'node:assert'; +import { strictEqual, deepStrictEqual, rejects, throws } from 'node:assert'; export const digeststream = { async test() { { const check = new Uint8Array([ - 198, 247, 195, 114, 100, 29, 210, 94, 15, 221, 240, 33, 83, 117, 86, 31 + 198, 247, 195, 114, 100, 29, 210, 94, 15, 221, 240, 33, 83, 117, 86, 31, ]); const stream = new crypto.DigestStream('md5'); @@ -45,13 +40,13 @@ export const digeststream = { new crypto.DigestStream('SHA-512'); // But fails for unknown digest names... - throws(() => new crypto.DigestStream("foo")); + throws(() => new crypto.DigestStream('foo')); } (async () => { let digestPromise; { - digestPromise = (new crypto.DigestStream('md5')).digest; + digestPromise = new crypto.DigestStream('md5').digest; } globalThis.gc(); await digestPromise; @@ -60,8 +55,9 @@ export const digeststream = { { const enc = new TextEncoder(); - const check = - new Uint8Array([93, 65, 64, 42, 188, 75, 42, 118, 185, 113, 157, 145, 16, 23, 197, 146]); + const check = new Uint8Array([ + 93, 65, 64, 42, 188, 75, 42, 118, 185, 113, 157, 145, 16, 23, 197, 146, + ]); const digestStream = new crypto.DigestStream('md5'); const writer = digestStream.getWriter(); await writer.write(enc.encode('hello')); @@ -71,8 +67,9 @@ export const digeststream = { } { - const check = - new Uint8Array([93, 65, 64, 42, 188, 75, 42, 118, 185, 113, 157, 145, 16, 23, 197, 146]); + const check = new Uint8Array([ + 93, 65, 64, 42, 188, 75, 42, 118, 185, 113, 157, 145, 16, 23, 197, 146, + ]); const digestStream = new crypto.DigestStream('md5'); const writer = digestStream.getWriter(); await writer.write('hello'); @@ -82,27 +79,29 @@ export const digeststream = { } { - const check = new Uint8Array([70, - 54, 153, 61, 62, 29, 164, 233, 214, 184, 248, 123, 121, 232, 247, 198, 208, 24, - 88, 13, 82, 102, 25, 80, 234, 188, 56, 69, 197, 137, 122, 77, + const check = new Uint8Array([ + 70, 54, 153, 61, 62, 29, 164, 233, 214, 184, 248, 123, 121, 232, 247, + 198, 208, 24, 88, 13, 82, 102, 25, 80, 234, 188, 56, 69, 197, 137, 122, + 77, ]); const digestStream = new crypto.DigestStream('SHA-256'); const writer = digestStream.getWriter(); - await writer.write(new Uint32Array([1,2,3])); + await writer.write(new Uint32Array([1, 2, 3])); await writer.close(); const digest = new Uint8Array(await digestStream.digest); deepStrictEqual(digest, check); } { - const check = new Uint8Array([70, - 54, 153, 61, 62, 29, 164, 233, 214, 184, 248, 123, 121, 232, 247, 198, 208, 24, - 88, 13, 82, 102, 25, 80, 234, 188, 56, 69, 197, 137, 122, 77, + const check = new Uint8Array([ + 70, 54, 153, 61, 62, 29, 164, 233, 214, 184, 248, 123, 121, 232, 247, + 198, 208, 24, 88, 13, 82, 102, 25, 80, 234, 188, 56, 69, 197, 137, 122, + 77, ]); const digestStream = new crypto.DigestStream('SHA-256'); const writer = digestStream.getWriter(); // Ensures that byteOffset is correctly handled. - await writer.write(new Uint32Array([0,1,2,3]).subarray(1)); + await writer.write(new Uint32Array([0, 1, 2, 3]).subarray(1)); await writer.close(); const digest = new Uint8Array(await digestStream.digest); deepStrictEqual(digest, check); @@ -116,15 +115,17 @@ export const digeststream = { await writer.write(123); throw new Error('should have failed'); } catch (err) { - strictEqual(err.message, - 'DigestStream is a byte stream but received an object ' + - 'of non-ArrayBuffer/ArrayBufferView/string type on its writable side.'); + strictEqual( + err.message, + 'DigestStream is a byte stream but received an object ' + + 'of non-ArrayBuffer/ArrayBufferView/string type on its writable side.' + ); } } // Creating and not using a digest stream doesn't crash new crypto.DigestStream('SHA-1'); - } + }, }; export const digestStreamNoEnd = { @@ -136,7 +137,7 @@ export const digestStreamNoEnd = { writer.write(enc.encode('hello')); writer.write(enc.encode('there')); // stream never ends, should not crash. - } + }, }; export const digestStreamDisposable = { @@ -156,5 +157,5 @@ export const digestStreamDisposable = { // Calling dispose again should have no impact stream[Symbol.dispose](); - } + }, }; diff --git a/src/workerd/api/tests/data-url-fetch-test.js b/src/workerd/api/tests/data-url-fetch-test.js index ee610736f9a..17ef23fc4e6 100644 --- a/src/workerd/api/tests/data-url-fetch-test.js +++ b/src/workerd/api/tests/data-url-fetch-test.js @@ -1,6 +1,4 @@ -import { - strictEqual, -} from 'node:assert'; +import { strictEqual } from 'node:assert'; export const dataUrl = { async test() { @@ -9,15 +7,17 @@ export const dataUrl = { strictEqual(resp.statusText, 'OK'); strictEqual(await resp.text(), 'Hello, World!'); strictEqual(resp.headers.get('content-type'), 'text/plain'); - } + }, }; export const base64DataUrl = { async test() { - const resp = await fetch(' DATA:text/plain;a=\"b\";base64,\t\nSGVsbG8sIFdvcmxkIQ%3D%3D' ); + const resp = await fetch( + ' DATA:text/plain;a="b";base64,\t\nSGVsbG8sIFdvcmxkIQ%3D%3D' + ); strictEqual(resp.status, 200); strictEqual(resp.statusText, 'OK'); strictEqual(await resp.text(), 'Hello, World!'); strictEqual(resp.headers.get('content-type'), 'text/plain;a=b'); - } + }, }; diff --git a/src/workerd/api/tests/encoding-test.js b/src/workerd/api/tests/encoding-test.js index ff01512535d..3f733813c1c 100644 --- a/src/workerd/api/tests/encoding-test.js +++ b/src/workerd/api/tests/encoding-test.js @@ -1,9 +1,4 @@ -import { - deepStrictEqual, - strictEqual, - throws, - ok, -} from 'node:assert'; +import { deepStrictEqual, strictEqual, throws, ok } from 'node:assert'; // Test for the Encoding standard Web API implementation. // The implementation for these are in api/encoding.{h|c++} @@ -18,7 +13,7 @@ function decodeStreaming(decoder, input) { } x += decoder.decode(); return x; -}; +} // From https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings const windows1252Labels = [ @@ -41,91 +36,125 @@ const windows1252Labels = [ 'x-cp1252', ]; -const utf8Labels = [ - 'unicode-1-1-utf-8', - 'utf-8', - 'utf8', -]; +const utf8Labels = ['unicode-1-1-utf-8', 'utf-8', 'utf8']; export const decodeStreamingTest = { test() { let results = []; for (const label of windows1252Labels) { - ok(new TextDecoder(`${label}`).encoding === "windows-1252", - `TextDecoder constructed with '${label}' label to have 'windows-1252' encoding.`); + ok( + new TextDecoder(`${label}`).encoding === 'windows-1252', + `TextDecoder constructed with '${label}' label to have 'windows-1252' encoding.` + ); } for (const label of utf8Labels) { - ok(new TextDecoder(`${label}`).encoding === "utf-8", - `TextDecoder constructed with '${label}' label to have 'utf-8' encoding.`); + ok( + new TextDecoder(`${label}`).encoding === 'utf-8', + `TextDecoder constructed with '${label}' label to have 'utf-8' encoding.` + ); } const decoder = new TextDecoder(); const fatalDecoder = new TextDecoder('utf-8', { fatal: true }); - const fatalIgnoreBomDecoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); + const fatalIgnoreBomDecoder = new TextDecoder('utf-8', { + fatal: true, + ignoreBOM: true, + }); - ok(decoder.encoding === "utf-8", "default encoding property to be 'utf-8'"); - ok(decoder.fatal === false, "default fatal property to be false"); - ok(decoder.ignoreBOM === false, "default ignoreBOM property to be false"); + ok(decoder.encoding === 'utf-8', "default encoding property to be 'utf-8'"); + ok(decoder.fatal === false, 'default fatal property to be false'); + ok(decoder.ignoreBOM === false, 'default ignoreBOM property to be false'); const fooCat = new Uint8Array([102, 111, 111, 32, 240, 159, 152, 186]); - ok(decoder.decode().length === 0, "decoded undefined array length to be 0"); - ok(decoder.decode(fooCat) === "foo 😺", "foo-cat from Uint8Buffer to be foo 😺"); - ok(decoder.decode(fooCat.buffer) === "foo 😺", "foo-cat from ArrayBuffer to be foo 😺"); - - const twoByteCodePoint = new Uint8Array([0xc2, 0xa2]); // cent sign - const threeByteCodePoint = new Uint8Array([0xe2, 0x82, 0xac]); // euro sign - const fourByteCodePoint = new Uint8Array([240, 159, 152, 186]); // cat emoji - - [twoByteCodePoint, threeByteCodePoint, fourByteCodePoint].forEach((input) => { - // For each input sequence of code units, try decoding each subsequence of code units except the - // full code point itself. - for (let i = 1; i < input.length; ++i) { - const head = input.slice(0, input.length - i); - const tail = input.slice(input.length - i); - - ok(decoder.decode(head) === "�", - "code point fragment (head) to be replaced with replacement character"); - ok(decoder.decode(tail) === "�".repeat(tail.length), - "code point fragment (tail) to be replaced with replacement character"); - - const errMsg = "Failed to decode input."; - - // Exception to be thrown decoding code point fragment (tail) in fatal mode - throws(() => fatalDecoder.decode(head)); - throws(() => fatalDecoder.decode(tail)); + ok(decoder.decode().length === 0, 'decoded undefined array length to be 0'); + ok( + decoder.decode(fooCat) === 'foo 😺', + 'foo-cat from Uint8Buffer to be foo 😺' + ); + ok( + decoder.decode(fooCat.buffer) === 'foo 😺', + 'foo-cat from ArrayBuffer to be foo 😺' + ); + + const twoByteCodePoint = new Uint8Array([0xc2, 0xa2]); // cent sign + const threeByteCodePoint = new Uint8Array([0xe2, 0x82, 0xac]); // euro sign + const fourByteCodePoint = new Uint8Array([240, 159, 152, 186]); // cat emoji + + [twoByteCodePoint, threeByteCodePoint, fourByteCodePoint].forEach( + (input) => { + // For each input sequence of code units, try decoding each subsequence of code units except the + // full code point itself. + for (let i = 1; i < input.length; ++i) { + const head = input.slice(0, input.length - i); + const tail = input.slice(input.length - i); + + ok( + decoder.decode(head) === '�', + 'code point fragment (head) to be replaced with replacement character' + ); + ok( + decoder.decode(tail) === '�'.repeat(tail.length), + 'code point fragment (tail) to be replaced with replacement character' + ); + + const errMsg = 'Failed to decode input.'; + + // Exception to be thrown decoding code point fragment (tail) in fatal mode + throws(() => fatalDecoder.decode(head)); + throws(() => fatalDecoder.decode(tail)); + } } - }); + ); // Test ASCII const asciiDecoder = new TextDecoder('ascii'); - ok(asciiDecoder.decode().length === 0, "decoded undefined array length to be 0"); - ok(asciiDecoder.decode(new Uint8Array([162, 174, 255])) === '¢®ÿ', - "decoded extended ascii correctly") + ok( + asciiDecoder.decode().length === 0, + 'decoded undefined array length to be 0' + ); + ok( + asciiDecoder.decode(new Uint8Array([162, 174, 255])) === '¢®ÿ', + 'decoded extended ascii correctly' + ); // Test streaming - ok(decodeStreaming(fatalDecoder, twoByteCodePoint) === '¢', - "2-byte code point (cent sign) to be decoded correctly"); - ok(decodeStreaming(fatalDecoder, threeByteCodePoint) === '€', - "3-byte code point (euro sign) to be decoded correctly"); - ok(decodeStreaming(fatalDecoder, fourByteCodePoint) === '😺', - "4-byte code point (cat emoji) to be decoded correctly"); + ok( + decodeStreaming(fatalDecoder, twoByteCodePoint) === '¢', + '2-byte code point (cent sign) to be decoded correctly' + ); + ok( + decodeStreaming(fatalDecoder, threeByteCodePoint) === '€', + '3-byte code point (euro sign) to be decoded correctly' + ); + ok( + decodeStreaming(fatalDecoder, fourByteCodePoint) === '😺', + '4-byte code point (cat emoji) to be decoded correctly' + ); const bom = new Uint8Array([0xef, 0xbb, 0xbf]); const bomBom = new Uint8Array([0xef, 0xbb, 0xbf, 0xef, 0xbb, 0xbf]); - ok(decodeStreaming(fatalDecoder, bom) === '', - "BOM to be stripped by TextDecoder without ignoreBOM set"); - ok(decodeStreaming(fatalDecoder, bomBom) === '\ufeff', - "first BOM to be stripped by TextDecoder without ignoreBOM set"); - - ok(decodeStreaming(fatalIgnoreBomDecoder, bom) === '\ufeff', - "BOM not to be stripped by TextDecoder with ignoreBOM set"); - ok(decodeStreaming(fatalIgnoreBomDecoder, bomBom) === '\ufeff\ufeff', - "first BOM not to be stripped by TextDecoder with ignoreBOM set"); - } + ok( + decodeStreaming(fatalDecoder, bom) === '', + 'BOM to be stripped by TextDecoder without ignoreBOM set' + ); + ok( + decodeStreaming(fatalDecoder, bomBom) === '\ufeff', + 'first BOM to be stripped by TextDecoder without ignoreBOM set' + ); + + ok( + decodeStreaming(fatalIgnoreBomDecoder, bom) === '\ufeff', + 'BOM not to be stripped by TextDecoder with ignoreBOM set' + ); + ok( + decodeStreaming(fatalIgnoreBomDecoder, bomBom) === '\ufeff\ufeff', + 'first BOM not to be stripped by TextDecoder with ignoreBOM set' + ); + }, }; export const textEncoderTest = { @@ -133,9 +162,11 @@ export const textEncoderTest = { const encoder = new TextEncoder(); strictEqual(encoder.encoding, 'utf-8'); strictEqual(encoder.encode().length, 0); - deepStrictEqual(encoder.encode('foo 😺'), - new Uint8Array([102, 111, 111, 32, 240, 159, 152, 186])); - } + deepStrictEqual( + encoder.encode('foo 😺'), + new Uint8Array([102, 111, 111, 32, 240, 159, 152, 186]) + ); + }, }; export const encodeWptTest = { @@ -146,38 +177,38 @@ export const encodeWptTest = { function w3cTestEncode() { const bad = [ { - input: '\uD800', - expected: '\uFFFD', - name: 'lone surrogate lead' + input: '\uD800', + expected: '\uFFFD', + name: 'lone surrogate lead', }, { - input: '\uDC00', - expected: '\uFFFD', - name: 'lone surrogate trail' + input: '\uDC00', + expected: '\uFFFD', + name: 'lone surrogate trail', }, { - input: '\uD800\u0000', - expected: '\uFFFD\u0000', - name: 'unmatched surrogate lead' + input: '\uD800\u0000', + expected: '\uFFFD\u0000', + name: 'unmatched surrogate lead', }, { - input: '\uDC00\u0000', - expected: '\uFFFD\u0000', - name: 'unmatched surrogate trail' + input: '\uDC00\u0000', + expected: '\uFFFD\u0000', + name: 'unmatched surrogate trail', }, { - input: '\uDC00\uD800', - expected: '\uFFFD\uFFFD', - name: 'swapped surrogate pair' + input: '\uDC00\uD800', + expected: '\uFFFD\uFFFD', + name: 'swapped surrogate pair', }, { - input: '\uD834\uDD1E', - expected: '\uD834\uDD1E', - name: 'properly encoded MUSICAL SYMBOL G CLEF (U+1D11E)' - } + input: '\uD834\uDD1E', + expected: '\uD834\uDD1E', + name: 'properly encoded MUSICAL SYMBOL G CLEF (U+1D11E)', + }, ]; - bad.forEach(function(t) { + bad.forEach(function (t) { const encoded = new TextEncoder().encode(t.input); const decoded = new TextDecoder().decode(encoded); strictEqual(decoded, t.expected); @@ -189,92 +220,97 @@ export const encodeWptTest = { function w3cTestEncodeInto() { [ { - "input": "Hi", - "read": 0, - "destinationLength": 0, - "written": [] + input: 'Hi', + read: 0, + destinationLength: 0, + written: [], }, { - "input": "A", - "read": 1, - "destinationLength": 10, - "written": [0x41] + input: 'A', + read: 1, + destinationLength: 10, + written: [0x41], }, { - "input": "\u{1D306}", // "\uD834\uDF06" - "read": 2, - "destinationLength": 4, - "written": [0xF0, 0x9D, 0x8C, 0x86] + input: '\u{1D306}', // "\uD834\uDF06" + read: 2, + destinationLength: 4, + written: [0xf0, 0x9d, 0x8c, 0x86], }, { - "input": "\u{1D306}A", - "read": 0, - "destinationLength": 3, - "written": [] + input: '\u{1D306}A', + read: 0, + destinationLength: 3, + written: [], }, { - "input": "\uD834A\uDF06A¥Hi", - "read": 5, - "destinationLength": 10, - "written": [0xEF, 0xBF, 0xBD, 0x41, 0xEF, 0xBF, 0xBD, 0x41, 0xC2, 0xA5] + input: '\uD834A\uDF06A¥Hi', + read: 5, + destinationLength: 10, + written: [0xef, 0xbf, 0xbd, 0x41, 0xef, 0xbf, 0xbd, 0x41, 0xc2, 0xa5], }, { - "input": "A\uDF06", - "read": 2, - "destinationLength": 4, - "written": [0x41, 0xEF, 0xBF, 0xBD] + input: 'A\uDF06', + read: 2, + destinationLength: 4, + written: [0x41, 0xef, 0xbf, 0xbd], }, { - "input": "¥¥", - "read": 2, - "destinationLength": 4, - "written": [0xC2, 0xA5, 0xC2, 0xA5] - } - ].forEach(testData => { + input: '¥¥', + read: 2, + destinationLength: 4, + written: [0xc2, 0xa5, 0xc2, 0xa5], + }, + ].forEach((testData) => { [ { - "bufferIncrease": 0, - "destinationOffset": 0, - "filler": 0 + bufferIncrease: 0, + destinationOffset: 0, + filler: 0, }, { - "bufferIncrease": 10, - "destinationOffset": 4, - "filler": 0 + bufferIncrease: 10, + destinationOffset: 4, + filler: 0, }, { - "bufferIncrease": 0, - "destinationOffset": 0, - "filler": 0x80 + bufferIncrease: 0, + destinationOffset: 0, + filler: 0x80, }, { - "bufferIncrease": 10, - "destinationOffset": 4, - "filler": 0x80 + bufferIncrease: 10, + destinationOffset: 4, + filler: 0x80, }, { - "bufferIncrease": 0, - "destinationOffset": 0, - "filler": "random" + bufferIncrease: 0, + destinationOffset: 0, + filler: 'random', }, { - "bufferIncrease": 10, - "destinationOffset": 4, - "filler": "random" - } - ].forEach(destinationData => { - const bufferLength = testData.destinationLength + destinationData.bufferIncrease; + bufferIncrease: 10, + destinationOffset: 4, + filler: 'random', + }, + ].forEach((destinationData) => { + const bufferLength = + testData.destinationLength + destinationData.bufferIncrease; const destinationOffset = destinationData.destinationOffset; const destinationLength = testData.destinationLength; const destinationFiller = destinationData.filler; const encoder = new TextEncoder(); const buffer = new ArrayBuffer(bufferLength); - const view = new Uint8Array(buffer, destinationOffset, destinationLength); + const view = new Uint8Array( + buffer, + destinationOffset, + destinationLength + ); const fullView = new Uint8Array(buffer); const control = new Array(bufferLength); let byte = destinationFiller; for (let i = 0; i < bufferLength; i++) { - if (destinationFiller === "random") { + if (destinationFiller === 'random') { byte = Math.floor(Math.random() * 256); } control[i] = byte; @@ -292,7 +328,10 @@ export const encodeWptTest = { strictEqual(result.read, testData.read); strictEqual(result.written, testData.written.length); for (let i = 0; i < bufferLength; i++) { - if (i < destinationOffset || i >= (destinationOffset + testData.written.length)) { + if ( + i < destinationOffset || + i >= destinationOffset + testData.written.length + ) { strictEqual(fullView[i], control[i]); } else { strictEqual(fullView[i], testData.written[i - destinationOffset]); @@ -301,30 +340,34 @@ export const encodeWptTest = { }); }); - [DataView, - Int8Array, - Int16Array, - Int32Array, - Uint16Array, - Uint32Array, - Uint8ClampedArray, - Float32Array, - Float64Array].forEach(view => { + [ + DataView, + Int8Array, + Int16Array, + Int32Array, + Uint16Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array, + ].forEach((view) => { const enc = new TextEncoder(); - throws(() => enc.encodeInto("", new view(new ArrayBuffer(0)))); + throws(() => enc.encodeInto('', new view(new ArrayBuffer(0)))); }); - throws(() => enc.encodeInto("", new ArrayBuffer(0))); + throws(() => enc.encodeInto('', new ArrayBuffer(0))); } - } + }, }; export const big5 = { test() { // Input is the Big5 encoding for the word 中國人 (meaning Chinese Person) // Check is the UTF-8 encoding for the same word. - const input = new Uint8Array([0xA4, 0xA4, 0xB0, 0xEA, 0xA4, 0x48]); - const check = new Uint8Array([0xe4, 0xb8, 0xad, 0xe5, 0x9c, 0x8b, 0xe4, 0xba, 0xba]); + const input = new Uint8Array([0xa4, 0xa4, 0xb0, 0xea, 0xa4, 0x48]); + const check = new Uint8Array([ + 0xe4, 0xb8, 0xad, 0xe5, 0x9c, 0x8b, 0xe4, 0xba, 0xba, + ]); const enc = new TextEncoder(); const dec = new TextDecoder('big5', { ignoreBOM: true }); const result = enc.encode(dec.decode(input)); @@ -332,7 +375,7 @@ export const big5 = { for (let n = 0; n < result.length; n++) { strictEqual(result[n], check[n]); } - } + }, }; export const utf16leFastTrack = { @@ -340,246 +383,248 @@ export const utf16leFastTrack = { // Input is the UTF-16le encoding for the word Hello. This should trigger the fast-path // which should handle the encoding with no problems. Here we only test that the results // are expected. We cannot verify here that the fast track is actually used. - const input = new Uint8Array([0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00]); + const input = new Uint8Array([ + 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, + ]); const dec = new TextDecoder('utf-16le'); strictEqual(dec.decode(input), 'hello'); - } + }, }; export const allTheDecoders = { test() { [ - ["unicode-1-1-utf-8", "utf-8"], - ["unicode11utf8", "utf-8"], - ["unicode20utf8", "utf-8"], - ["utf-8", "utf-8"], - ["utf8", "utf-8"], - ["x-unicode20utf8", "utf-8"], - ["866", "ibm-866"], - ["cp866", "ibm-866"], - ["csibm866", "ibm-866"], - ["ibm866", "ibm-866"], - ["csisolatin2", "iso-8859-2"], - ["iso-8859-2", "iso-8859-2"], - ["iso-ir-101", "iso-8859-2"], - ["iso8859-2", "iso-8859-2"], - ["iso88592", "iso-8859-2"], - ["iso_8859-2", "iso-8859-2"], - ["iso_8859-2:1987", "iso-8859-2"], - ["l2", "iso-8859-2"], - ["latin2", "iso-8859-2"], - ["csisolatin3", "iso-8859-3"], - ["iso-8859-3", "iso-8859-3"], - ["iso-ir-109", "iso-8859-3"], - ["iso8859-3", "iso-8859-3"], - ["iso88593", "iso-8859-3"], - ["iso_8859-3", "iso-8859-3"], - ["iso_8859-3:1988", "iso-8859-3"], - ["l3", "iso-8859-3"], - ["latin3", "iso-8859-3"], - ["csisolatin4", "iso-8859-4"], - ["iso-8859-4", "iso-8859-4"], - ["iso-ir-110", "iso-8859-4"], - ["iso8859-4", "iso-8859-4"], - ["iso88594", "iso-8859-4"], - ["iso_8859-4", "iso-8859-4"], - ["iso_8859-4:1988", "iso-8859-4"], - ["l4", "iso-8859-4"], - ["latin4", "iso-8859-4"], - ["csisolatincyrillic", "iso-8859-5"], - ["cyrillic", "iso-8859-5"], - ["iso-8859-5", "iso-8859-5"], - ["iso-ir-144", "iso-8859-5"], - ["iso8859-5", "iso-8859-5"], - ["iso88595", "iso-8859-5"], - ["iso_8859-5", "iso-8859-5"], - ["iso_8859-5:1988", "iso-8859-5"], - ["arabic", "iso-8859-6"], - ["asmo-708", "iso-8859-6"], - ["csiso88596e", "iso-8859-6"], - ["csiso88596i", "iso-8859-6"], - ["csisolatinarabic", "iso-8859-6"], - ["ecma-114", "iso-8859-6"], - ["iso-8859-6", "iso-8859-6"], - ["iso-8859-6-e", "iso-8859-6"], - ["iso-8859-6-i", "iso-8859-6"], - ["iso-ir-127", "iso-8859-6"], - ["iso8859-6", "iso-8859-6"], - ["iso88596", "iso-8859-6"], - ["iso_8859-6", "iso-8859-6"], - ["iso_8859-6:1987", "iso-8859-6"], - ["csisolatingreek", "iso-8859-7"], - ["ecma-118", "iso-8859-7"], - ["elot_928", "iso-8859-7"], - ["greek", "iso-8859-7"], - ["greek8", "iso-8859-7"], - ["iso-8859-7", "iso-8859-7"], - ["iso-ir-126", "iso-8859-7"], - ["iso8859-7", "iso-8859-7"], - ["iso88597", "iso-8859-7"], - ["iso_8859-7", "iso-8859-7"], - ["iso_8859-7:1987", "iso-8859-7"], - ["sun_eu_greek", "iso-8859-7"], - ["csiso88598e", "iso-8859-8"], - ["csisolatinhebrew", "iso-8859-8"], - ["hebrew", "iso-8859-8"], - ["iso-8859-8", "iso-8859-8"], - ["iso-8859-8-e", "iso-8859-8"], - ["iso-ir-138", "iso-8859-8"], - ["iso8859-8", "iso-8859-8"], - ["iso88598", "iso-8859-8"], - ["iso_8859-8", "iso-8859-8"], - ["iso_8859-8:1988", "iso-8859-8"], - ["visual", "iso-8859-8"], - ["csiso88598i", "iso-8859-8-i"], - ["iso-8859-8-i", "iso-8859-8-i"], - ["logical", "iso-8859-8-i"], - ["csisolatin6", "iso-8859-10"], - ["iso-8859-10", "iso-8859-10"], - ["iso-ir-157", "iso-8859-10"], - ["iso8859-10", "iso-8859-10"], - ["iso885910", "iso-8859-10"], - ["l6", "iso-8859-10"], - ["latin6", "iso-8859-10"], - ["iso-8859-13", "iso-8859-13"], - ["iso8859-13", "iso-8859-13"], - ["iso885913", "iso-8859-13"], - ["iso-8859-14", "iso-8859-14"], - ["iso8859-14", "iso-8859-14"], - ["iso885914", "iso-8859-14"], - ["csisolatin9", "iso-8859-15"], - ["iso-8859-15", "iso-8859-15"], - ["iso8859-15", "iso-8859-15"], - ["iso885915", "iso-8859-15"], - ["iso_8859-15", "iso-8859-15"], - ["l9", "iso-8859-15"], - ["iso-8859-16", "iso-8859-16"], - ["cskoi8r", "koi8-r"], - ["koi", "koi8-r"], - ["koi8", "koi8-r"], - ["koi8-r", "koi8-r"], - ["koi8_r", "koi8-r"], - ["koi8-ru", "koi8-u"], - ["koi8-u", "koi8-u"], - ["csmacintosh", "macintosh"], - ["mac", "macintosh"], - ["macintosh", "macintosh"], - ["x-mac-roman", "macintosh"], - ["dos-874", "windows-874"], - ["iso-8859-11", "windows-874"], - ["iso8859-11", "windows-874"], - ["iso885911", "windows-874"], - ["tis-620", "windows-874"], - ["windows-874", "windows-874"], - ["cp1250", "windows-1250"], - ["windows-1250", "windows-1250"], - ["x-cp1250", "windows-1250"], - ["cp1251", "windows-1251"], - ["windows-1251", "windows-1251"], - ["x-cp1251", "windows-1251"], - ["ansi_x3.4-1968", "windows-1252"], - ["ascii", "windows-1252"], - ["cp1252", "windows-1252"], - ["cp819", "windows-1252"], - ["csisolatin1", "windows-1252"], - ["ibm819", "windows-1252"], - ["iso-8859-1", "windows-1252"], - ["iso-ir-100", "windows-1252"], - ["iso8859-1", "windows-1252"], - ["iso88591", "windows-1252"], - ["iso_8859-1", "windows-1252"], - ["iso_8859-1:1987", "windows-1252"], - ["l1", "windows-1252"], - ["latin1", "windows-1252"], - ["us-ascii", "windows-1252"], - ["windows-1252", "windows-1252"], - ["x-cp1252", "windows-1252"], - ["cp1253", "windows-1253"], - ["windows-1253", "windows-1253"], - ["x-cp1253", "windows-1253"], - ["cp1254", "windows-1254"], - ["csisolatin5", "windows-1254"], - ["iso-8859-9", "windows-1254"], - ["iso-ir-148", "windows-1254"], - ["iso8859-9", "windows-1254"], - ["iso88599", "windows-1254"], - ["iso_8859-9", "windows-1254"], - ["iso_8859-9:1989", "windows-1254"], - ["l5", "windows-1254"], - ["latin5", "windows-1254"], - ["windows-1254", "windows-1254"], - ["x-cp1254", "windows-1254"], - ["cp1255", "windows-1255"], - ["windows-1255", "windows-1255"], - ["x-cp1255", "windows-1255"], - ["cp1256", "windows-1256"], - ["windows-1256", "windows-1256"], - ["x-cp1256", "windows-1256"], - ["cp1257", "windows-1257"], - ["windows-1257", "windows-1257"], - ["x-cp1257", "windows-1257"], - ["cp1258", "windows-1258"], - ["windows-1258", "windows-1258"], - ["x-cp1258", "windows-1258"], - ["x-mac-cyrillic", "x-mac-cyrillic"], - ["x-mac-ukrainian", "x-mac-cyrillic"], - ["chinese", "gbk"], - ["csgb2312", "gbk"], - ["csiso58gb231280", "gbk"], - ["gb2312", "gbk"], - ["gb_2312", "gbk"], - ["gb_2312-80", "gbk"], - ["gbk", "gbk"], - ["iso-ir-58", "gbk"], - ["x-gbk", "gbk"], - ["gb18030", "gb18030"], - ["big5", "big5"], - ["big5-hkscs", "big5"], - ["cn-big5", "big5"], - ["csbig5", "big5"], - ["x-x-big5", "big5"], - ["cseucpkdfmtjapanese", "euc-jp"], - ["euc-jp", "euc-jp"], - ["x-euc-jp", "euc-jp"], - ["csiso2022jp", "iso-2022-jp"], - ["iso-2022-jp", "iso-2022-jp"], - ["csshiftjis", "shift-jis"], - ["ms932", "shift-jis"], - ["ms_kanji", "shift-jis"], - ["shift-jis", "shift-jis"], - ["shift_jis", "shift-jis"], - ["sjis", "shift-jis"], - ["windows-31j", "shift-jis"], - ["x-sjis", "shift-jis"], - ["cseuckr", "euc-kr"], - ["csksc56011987", "euc-kr"], - ["euc-kr", "euc-kr"], - ["iso-ir-149", "euc-kr"], - ["korean", "euc-kr"], - ["ks_c_5601-1987", "euc-kr"], - ["ks_c_5601-1989", "euc-kr"], - ["ksc5601", "euc-kr"], - ["ksc_5601", "euc-kr"], - ["windows-949", "euc-kr"], - ["csiso2022kr", undefined], - ["hz-gb-2312", undefined], - ["iso-2022-cn", undefined], - ["iso-2022-cn-ext", undefined], - ["iso-2022-kr", undefined], - ["replacement", undefined], - ["unicodefffe", "utf-16be"], - ["utf-16be", "utf-16be"], - ["csunicode", "utf-16le"], - ["iso-10646-ucs-2", "utf-16le"], - ["ucs-2", "utf-16le"], - ["unicode", "utf-16le"], - ["unicodefeff", "utf-16le"], - ["utf-16", "utf-16le"], - ["utf-16le", "utf-16le"], - ["x-user-defined", undefined], + ['unicode-1-1-utf-8', 'utf-8'], + ['unicode11utf8', 'utf-8'], + ['unicode20utf8', 'utf-8'], + ['utf-8', 'utf-8'], + ['utf8', 'utf-8'], + ['x-unicode20utf8', 'utf-8'], + ['866', 'ibm-866'], + ['cp866', 'ibm-866'], + ['csibm866', 'ibm-866'], + ['ibm866', 'ibm-866'], + ['csisolatin2', 'iso-8859-2'], + ['iso-8859-2', 'iso-8859-2'], + ['iso-ir-101', 'iso-8859-2'], + ['iso8859-2', 'iso-8859-2'], + ['iso88592', 'iso-8859-2'], + ['iso_8859-2', 'iso-8859-2'], + ['iso_8859-2:1987', 'iso-8859-2'], + ['l2', 'iso-8859-2'], + ['latin2', 'iso-8859-2'], + ['csisolatin3', 'iso-8859-3'], + ['iso-8859-3', 'iso-8859-3'], + ['iso-ir-109', 'iso-8859-3'], + ['iso8859-3', 'iso-8859-3'], + ['iso88593', 'iso-8859-3'], + ['iso_8859-3', 'iso-8859-3'], + ['iso_8859-3:1988', 'iso-8859-3'], + ['l3', 'iso-8859-3'], + ['latin3', 'iso-8859-3'], + ['csisolatin4', 'iso-8859-4'], + ['iso-8859-4', 'iso-8859-4'], + ['iso-ir-110', 'iso-8859-4'], + ['iso8859-4', 'iso-8859-4'], + ['iso88594', 'iso-8859-4'], + ['iso_8859-4', 'iso-8859-4'], + ['iso_8859-4:1988', 'iso-8859-4'], + ['l4', 'iso-8859-4'], + ['latin4', 'iso-8859-4'], + ['csisolatincyrillic', 'iso-8859-5'], + ['cyrillic', 'iso-8859-5'], + ['iso-8859-5', 'iso-8859-5'], + ['iso-ir-144', 'iso-8859-5'], + ['iso8859-5', 'iso-8859-5'], + ['iso88595', 'iso-8859-5'], + ['iso_8859-5', 'iso-8859-5'], + ['iso_8859-5:1988', 'iso-8859-5'], + ['arabic', 'iso-8859-6'], + ['asmo-708', 'iso-8859-6'], + ['csiso88596e', 'iso-8859-6'], + ['csiso88596i', 'iso-8859-6'], + ['csisolatinarabic', 'iso-8859-6'], + ['ecma-114', 'iso-8859-6'], + ['iso-8859-6', 'iso-8859-6'], + ['iso-8859-6-e', 'iso-8859-6'], + ['iso-8859-6-i', 'iso-8859-6'], + ['iso-ir-127', 'iso-8859-6'], + ['iso8859-6', 'iso-8859-6'], + ['iso88596', 'iso-8859-6'], + ['iso_8859-6', 'iso-8859-6'], + ['iso_8859-6:1987', 'iso-8859-6'], + ['csisolatingreek', 'iso-8859-7'], + ['ecma-118', 'iso-8859-7'], + ['elot_928', 'iso-8859-7'], + ['greek', 'iso-8859-7'], + ['greek8', 'iso-8859-7'], + ['iso-8859-7', 'iso-8859-7'], + ['iso-ir-126', 'iso-8859-7'], + ['iso8859-7', 'iso-8859-7'], + ['iso88597', 'iso-8859-7'], + ['iso_8859-7', 'iso-8859-7'], + ['iso_8859-7:1987', 'iso-8859-7'], + ['sun_eu_greek', 'iso-8859-7'], + ['csiso88598e', 'iso-8859-8'], + ['csisolatinhebrew', 'iso-8859-8'], + ['hebrew', 'iso-8859-8'], + ['iso-8859-8', 'iso-8859-8'], + ['iso-8859-8-e', 'iso-8859-8'], + ['iso-ir-138', 'iso-8859-8'], + ['iso8859-8', 'iso-8859-8'], + ['iso88598', 'iso-8859-8'], + ['iso_8859-8', 'iso-8859-8'], + ['iso_8859-8:1988', 'iso-8859-8'], + ['visual', 'iso-8859-8'], + ['csiso88598i', 'iso-8859-8-i'], + ['iso-8859-8-i', 'iso-8859-8-i'], + ['logical', 'iso-8859-8-i'], + ['csisolatin6', 'iso-8859-10'], + ['iso-8859-10', 'iso-8859-10'], + ['iso-ir-157', 'iso-8859-10'], + ['iso8859-10', 'iso-8859-10'], + ['iso885910', 'iso-8859-10'], + ['l6', 'iso-8859-10'], + ['latin6', 'iso-8859-10'], + ['iso-8859-13', 'iso-8859-13'], + ['iso8859-13', 'iso-8859-13'], + ['iso885913', 'iso-8859-13'], + ['iso-8859-14', 'iso-8859-14'], + ['iso8859-14', 'iso-8859-14'], + ['iso885914', 'iso-8859-14'], + ['csisolatin9', 'iso-8859-15'], + ['iso-8859-15', 'iso-8859-15'], + ['iso8859-15', 'iso-8859-15'], + ['iso885915', 'iso-8859-15'], + ['iso_8859-15', 'iso-8859-15'], + ['l9', 'iso-8859-15'], + ['iso-8859-16', 'iso-8859-16'], + ['cskoi8r', 'koi8-r'], + ['koi', 'koi8-r'], + ['koi8', 'koi8-r'], + ['koi8-r', 'koi8-r'], + ['koi8_r', 'koi8-r'], + ['koi8-ru', 'koi8-u'], + ['koi8-u', 'koi8-u'], + ['csmacintosh', 'macintosh'], + ['mac', 'macintosh'], + ['macintosh', 'macintosh'], + ['x-mac-roman', 'macintosh'], + ['dos-874', 'windows-874'], + ['iso-8859-11', 'windows-874'], + ['iso8859-11', 'windows-874'], + ['iso885911', 'windows-874'], + ['tis-620', 'windows-874'], + ['windows-874', 'windows-874'], + ['cp1250', 'windows-1250'], + ['windows-1250', 'windows-1250'], + ['x-cp1250', 'windows-1250'], + ['cp1251', 'windows-1251'], + ['windows-1251', 'windows-1251'], + ['x-cp1251', 'windows-1251'], + ['ansi_x3.4-1968', 'windows-1252'], + ['ascii', 'windows-1252'], + ['cp1252', 'windows-1252'], + ['cp819', 'windows-1252'], + ['csisolatin1', 'windows-1252'], + ['ibm819', 'windows-1252'], + ['iso-8859-1', 'windows-1252'], + ['iso-ir-100', 'windows-1252'], + ['iso8859-1', 'windows-1252'], + ['iso88591', 'windows-1252'], + ['iso_8859-1', 'windows-1252'], + ['iso_8859-1:1987', 'windows-1252'], + ['l1', 'windows-1252'], + ['latin1', 'windows-1252'], + ['us-ascii', 'windows-1252'], + ['windows-1252', 'windows-1252'], + ['x-cp1252', 'windows-1252'], + ['cp1253', 'windows-1253'], + ['windows-1253', 'windows-1253'], + ['x-cp1253', 'windows-1253'], + ['cp1254', 'windows-1254'], + ['csisolatin5', 'windows-1254'], + ['iso-8859-9', 'windows-1254'], + ['iso-ir-148', 'windows-1254'], + ['iso8859-9', 'windows-1254'], + ['iso88599', 'windows-1254'], + ['iso_8859-9', 'windows-1254'], + ['iso_8859-9:1989', 'windows-1254'], + ['l5', 'windows-1254'], + ['latin5', 'windows-1254'], + ['windows-1254', 'windows-1254'], + ['x-cp1254', 'windows-1254'], + ['cp1255', 'windows-1255'], + ['windows-1255', 'windows-1255'], + ['x-cp1255', 'windows-1255'], + ['cp1256', 'windows-1256'], + ['windows-1256', 'windows-1256'], + ['x-cp1256', 'windows-1256'], + ['cp1257', 'windows-1257'], + ['windows-1257', 'windows-1257'], + ['x-cp1257', 'windows-1257'], + ['cp1258', 'windows-1258'], + ['windows-1258', 'windows-1258'], + ['x-cp1258', 'windows-1258'], + ['x-mac-cyrillic', 'x-mac-cyrillic'], + ['x-mac-ukrainian', 'x-mac-cyrillic'], + ['chinese', 'gbk'], + ['csgb2312', 'gbk'], + ['csiso58gb231280', 'gbk'], + ['gb2312', 'gbk'], + ['gb_2312', 'gbk'], + ['gb_2312-80', 'gbk'], + ['gbk', 'gbk'], + ['iso-ir-58', 'gbk'], + ['x-gbk', 'gbk'], + ['gb18030', 'gb18030'], + ['big5', 'big5'], + ['big5-hkscs', 'big5'], + ['cn-big5', 'big5'], + ['csbig5', 'big5'], + ['x-x-big5', 'big5'], + ['cseucpkdfmtjapanese', 'euc-jp'], + ['euc-jp', 'euc-jp'], + ['x-euc-jp', 'euc-jp'], + ['csiso2022jp', 'iso-2022-jp'], + ['iso-2022-jp', 'iso-2022-jp'], + ['csshiftjis', 'shift-jis'], + ['ms932', 'shift-jis'], + ['ms_kanji', 'shift-jis'], + ['shift-jis', 'shift-jis'], + ['shift_jis', 'shift-jis'], + ['sjis', 'shift-jis'], + ['windows-31j', 'shift-jis'], + ['x-sjis', 'shift-jis'], + ['cseuckr', 'euc-kr'], + ['csksc56011987', 'euc-kr'], + ['euc-kr', 'euc-kr'], + ['iso-ir-149', 'euc-kr'], + ['korean', 'euc-kr'], + ['ks_c_5601-1987', 'euc-kr'], + ['ks_c_5601-1989', 'euc-kr'], + ['ksc5601', 'euc-kr'], + ['ksc_5601', 'euc-kr'], + ['windows-949', 'euc-kr'], + ['csiso2022kr', undefined], + ['hz-gb-2312', undefined], + ['iso-2022-cn', undefined], + ['iso-2022-cn-ext', undefined], + ['iso-2022-kr', undefined], + ['replacement', undefined], + ['unicodefffe', 'utf-16be'], + ['utf-16be', 'utf-16be'], + ['csunicode', 'utf-16le'], + ['iso-10646-ucs-2', 'utf-16le'], + ['ucs-2', 'utf-16le'], + ['unicode', 'utf-16le'], + ['unicodefeff', 'utf-16le'], + ['utf-16', 'utf-16le'], + ['utf-16le', 'utf-16le'], + ['x-user-defined', undefined], // Test that match is case-insensitive - ["UTF-8", "utf-8"], - ["UtF-8", "utf-8"], + ['UTF-8', 'utf-8'], + ['UtF-8', 'utf-8'], ].forEach((pair) => { const [label, key] = pair; if (key === undefined) { @@ -596,7 +641,7 @@ export const allTheDecoders = { } } }); - } + }, }; export const textDecoderStream = { @@ -611,5 +656,5 @@ export const textDecoderStream = { const enc = new TextEncoderStream(); strictEqual(enc.encoding, 'utf-8'); - } + }, }; diff --git a/src/workerd/api/tests/events-test.js b/src/workerd/api/tests/events-test.js index ecc915114a8..f0a3f99b811 100644 --- a/src/workerd/api/tests/events-test.js +++ b/src/workerd/api/tests/events-test.js @@ -1,9 +1,4 @@ -import { - deepStrictEqual, - strictEqual, - throws, - ok, -} from 'node:assert'; +import { deepStrictEqual, strictEqual, throws, ok } from 'node:assert'; // Test for the Event and EventTarget standard Web API implementations. // The implementation for these are in api/basics.{h|c++} @@ -14,18 +9,18 @@ export const event = { throws(() => new Event(Symbol('test'))); // stringifiable values do work, however - strictEqual((new Event({})).type, '[object Object]'); - strictEqual((new Event(null)).type, 'null'); - strictEqual((new Event(1)).type, '1'); + strictEqual(new Event({}).type, '[object Object]'); + strictEqual(new Event(null).type, 'null'); + strictEqual(new Event(1).type, '1'); // Passing undefined explicitly works - strictEqual((new Event(undefined)).type, 'undefined'); + strictEqual(new Event(undefined).type, 'undefined'); // But not passing a value for type fails throws(() => new Event()); // We can create an Event object with no options and it works as expected. - const event = new Event("foo"); + const event = new Event('foo'); strictEqual(event.type, 'foo'); strictEqual(event.bubbles, false); strictEqual(event.cancelable, false); @@ -45,7 +40,7 @@ export const event = { // by default, defaultPrevented still is false. strictEqual(event.defaultPrevented, false); strictEqual(event.cancelBubble, true); - } + }, }; export const eventWithOptions = { @@ -55,10 +50,10 @@ export const eventWithOptions = { throws(() => new Event('foo', 'bar')); // We can create an Event object with no options and it works as expected. - const event = new Event("foo", { + const event = new Event('foo', { cancelable: true, bubbles: 'truthy values work also', - composed: true + composed: true, }); strictEqual(event.type, 'foo'); strictEqual(event.bubbles, true); @@ -78,13 +73,15 @@ export const eventWithOptions = { // Because the event is cancelable, defaultPrevented is true. strictEqual(event.defaultPrevented, true); strictEqual(event.returnValue, false); - } + }, }; export const eventSubclass = { test() { class Foo extends Event { - constructor() { super("foo"); } + constructor() { + super('foo'); + } } const event = new Foo(); strictEqual(event.type, 'foo'); @@ -101,32 +98,39 @@ export const eventSubclass = { // Everything except cancelBubble is read only and will throw // if attempts are made to modify - throws(() => event.type = 'foo'); - throws(() => event.bubbles = false); - throws(() => event.cancelable = false); - throws(() => event.composed = false); - throws(() => event.isTrusted = false); - throws(() => event.defaultPrevented = false); - throws(() => event.eventPhase = Event.NONE); - throws(() => event.returnValue = true); - throws(() => event.timeStamp = 0.0); - throws(() => event.currentTarget = undefined); + throws(() => (event.type = 'foo')); + throws(() => (event.bubbles = false)); + throws(() => (event.cancelable = false)); + throws(() => (event.composed = false)); + throws(() => (event.isTrusted = false)); + throws(() => (event.defaultPrevented = false)); + throws(() => (event.eventPhase = Event.NONE)); + throws(() => (event.returnValue = true)); + throws(() => (event.timeStamp = 0.0)); + throws(() => (event.currentTarget = undefined)); event.cancelBubble = true; strictEqual(event.cancelBubble, true); // With the default compatibility flag set, the properties should // exist on the prototype and not as own properties on the event itself. - strictEqual(Reflect.getOwnPropertyDescriptor(event, 'cancelable'), undefined); + strictEqual( + Reflect.getOwnPropertyDescriptor(event, 'cancelable'), + undefined + ); // Which means a subclass can replace the implementation successfully. class Bar extends Event { - constructor() { super('bar'); } - get bubbles() { return 'hello'; } + constructor() { + super('bar'); + } + get bubbles() { + return 'hello'; + } } const bar = new Bar(); strictEqual(bar.bubbles, 'hello'); strictEqual(bar.composed, false); - } + }, }; export const extendableEventNotConstructable = { @@ -137,8 +141,8 @@ export const extendableEventNotConstructable = { // originate from the runtime. That is, user code cannot create their own trusted // events. strictEqual(typeof ExtendableEvent, 'function'); - throws(() => new ExtendableEvent("foo")); - } + throws(() => new ExtendableEvent('foo')); + }, }; export const basicEventTarget = { @@ -163,7 +167,7 @@ export const basicEventTarget = { }; const handlerObj = { - handleEvent: handler + handleEvent: handler, }; throws(() => target.addEventListener('foo', {})); @@ -184,7 +188,7 @@ export const basicEventTarget = { handleEvent(event) { classCalled = true; } - }); + })(); target.addEventListener('foo', foo); target.dispatchEvent(event); @@ -200,7 +204,7 @@ export const basicEventTarget = { target.dispatchEvent(event); strictEqual(dispatchCount, 3); - } + }, }; export const subclassedEventTarget = { @@ -215,7 +219,7 @@ export const subclassedEventTarget = { }); target.dispatchEvent(event); strictEqual(dispatchCount, 1); - } + }, }; export const onceListener = { @@ -225,15 +229,19 @@ export const onceListener = { let dispatchCount = 0; - target.addEventListener('foo', () => { - dispatchCount++; - }, { once: true }); + target.addEventListener( + 'foo', + () => { + dispatchCount++; + }, + { once: true } + ); target.dispatchEvent(event); target.dispatchEvent(event); strictEqual(dispatchCount, 1); - } + }, }; export const cancelableListener = { @@ -245,22 +253,30 @@ export const cancelableListener = { const ac = new AbortController(); - target.addEventListener('foo', () => { - dispatchCount++; - }, { signal: ac.signal }); + target.addEventListener( + 'foo', + () => { + dispatchCount++; + }, + { signal: ac.signal } + ); // Passing an already aborted signal just works as expected. // No errors are thrown. - target.addEventListener('foo', () => { - dispatchCount++; - }, { signal: AbortSignal.abort() }); + target.addEventListener( + 'foo', + () => { + dispatchCount++; + }, + { signal: AbortSignal.abort() } + ); ac.abort(); target.dispatchEvent(event); strictEqual(dispatchCount, 0); - } + }, }; export const cancelableListenerAbortPropagation = { @@ -279,7 +295,7 @@ export const cancelableListenerAbortPropagation = { // }, { signal }); // controller.abort(); // et.dispatchEvent(new Event('foo')); - } + }, }; export const passiveCaptureListener = { @@ -289,7 +305,7 @@ export const passiveCaptureListener = { // we allow them to be set for code portability reasons. throws(() => { target.addEventListener('foo', () => {}, { - capture: true + capture: true, }); }); throws(() => { @@ -297,18 +313,18 @@ export const passiveCaptureListener = { }); throws(() => { target.addEventListener('foo', () => {}, { - passive: true + passive: true, }); }); throws(() => { target.removeEventListener('foo', () => {}, { - capture: true + capture: true, }); }); throws(() => { target.removeEventListener('foo', () => {}, true); }); - } + }, }; export const globalIsEventTarget = { @@ -325,12 +341,16 @@ export const globalIsEventTarget = { const event = new Event('foo'); let dispatchCount = 0; - addEventListener('foo', () => { - dispatchCount++; - }, { once: true }); + addEventListener( + 'foo', + () => { + dispatchCount++; + }, + { once: true } + ); dispatchEvent(event); strictEqual(dispatchCount, 1); - } + }, }; export const errorInHandler = { @@ -343,7 +363,7 @@ export const errorInHandler = { target.addEventListener('foo', () => { dispatchCount++; throw new Error('boom'); - }) + }); target.addEventListener('foo', () => { dispatchCount++; }); @@ -353,7 +373,7 @@ export const errorInHandler = { // The dispatchCount here should be 2, but with the current bug, it's only 1 // strictEqual(dispatchCount, 2); strictEqual(dispatchCount, 1); - } + }, }; export const stopImmediatePropagation = { @@ -372,7 +392,7 @@ export const stopImmediatePropagation = { }); target.dispatchEvent(event); strictEqual(dispatchCount, 1); - } + }, }; export const nullUndefinedHandler = { @@ -382,7 +402,7 @@ export const nullUndefinedHandler = { const target = new EventTarget(); // target.addEventListener('foo', null); // target.addEventListener('foo', undefined); - } + }, }; export const customEvent = { @@ -391,7 +411,7 @@ export const customEvent = { ok(event instanceof Event); strictEqual(event.type, 'foo'); deepStrictEqual(event.detail, { a: 123 }); - } + }, }; export const closeEvent = { @@ -400,5 +420,5 @@ export const closeEvent = { // had it as required. Let's make sure we can create it without the second arg. new CloseEvent('foo'); new CloseEvent('foo', { code: 1000, reason: 'bye' }); - } + }, }; diff --git a/src/workerd/api/tests/eventsource-test.js b/src/workerd/api/tests/eventsource-test.js index 9b46eb269a6..e92199c550a 100644 --- a/src/workerd/api/tests/eventsource-test.js +++ b/src/workerd/api/tests/eventsource-test.js @@ -1,16 +1,14 @@ // Copyright (c) 2017-2024 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { - strictEqual, - ok, - throws -} from 'node:assert'; +import { strictEqual, ok, throws } from 'node:assert'; export const acceptEventStreamTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/accept-event-stream', - { fetcher: env.subrequest }); + const eventsource = new EventSource( + 'http://example.org/accept-event-stream', + { fetcher: env.subrequest } + ); strictEqual(eventsource.readyState, EventSource.CONNECTING); const { promise, resolve } = Promise.withResolvers(); let opened = false; @@ -27,13 +25,15 @@ export const acceptEventStreamTest = { }; await promise; ok(opened); - } + }, }; export const cacheControlEventStreamTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/cache-control-event-stream', - { fetcher: env.subrequest }); + const eventsource = new EventSource( + 'http://example.org/cache-control-event-stream', + { fetcher: env.subrequest } + ); const { promise, resolve } = Promise.withResolvers(); eventsource.onmessage = (event) => { strictEqual(event.data, 'no-cache'); @@ -41,13 +41,14 @@ export const cacheControlEventStreamTest = { resolve(); }; await promise; - } + }, }; export const lastEventIdTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/last-event-id', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/last-event-id', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); let first = true; eventsource.onmessage = (event) => { @@ -61,13 +62,15 @@ export const lastEventIdTest = { } }; await promise; - } + }, }; export const eventIdPersistsTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/event-id-persists', - { fetcher: env.subrequest }); + const eventsource = new EventSource( + 'http://example.org/event-id-persists', + { fetcher: env.subrequest } + ); const { promise, resolve } = Promise.withResolvers(); eventsource.onmessage = (event) => { switch (event.data) { @@ -90,13 +93,14 @@ export const eventIdPersistsTest = { } }; await promise; - } + }, }; export const eventIdResetsTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/event-id-resets', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/event-id-resets', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); eventsource.onmessage = (event) => { switch (event.data) { @@ -113,13 +117,15 @@ export const eventIdResetsTest = { } }; await promise; - } + }, }; export const eventIdResets2Test = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/event-id-resets-2', - { fetcher: env.subrequest }); + const eventsource = new EventSource( + 'http://example.org/event-id-resets-2', + { fetcher: env.subrequest } + ); const { promise, resolve } = Promise.withResolvers(); eventsource.onmessage = (event) => { switch (event.data) { @@ -136,13 +142,14 @@ export const eventIdResets2Test = { } }; await promise; - } + }, }; export const messageTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/message', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/message', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); // We should get two messages... let count = 0; @@ -161,13 +168,14 @@ export const messageTest = { } }; await promise; - } + }, }; export const reconnectFailTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/reconnect-fail', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/reconnect-fail', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); let count = 0; eventsource.onmessage = (event) => { @@ -194,13 +202,14 @@ export const reconnectFailTest = { } }; await promise; - } + }, }; export const statusErrorTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/status-error', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/status-error', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); eventsource.onopen = () => { throw new Error('should not be called'); @@ -210,13 +219,14 @@ export const statusErrorTest = { resolve(); }; await promise; - } -} + }, +}; export const eventTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/event', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/event', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); let count = 0; eventsource.ontest = (event) => { @@ -234,13 +244,14 @@ export const eventTest = { } }; await promise; - } + }, }; export const retryTest = { async test(ctrl, env) { - const eventsource = new EventSource('http://example.org/retry', - { fetcher: env.subrequest }); + const eventsource = new EventSource('http://example.org/retry', { + fetcher: env.subrequest, + }); const { promise, resolve } = Promise.withResolvers(); let count = 0; eventsource.onmessage = (event) => { @@ -266,41 +277,46 @@ export const retryTest = { } }; await promise; - } + }, }; export const constructorTest = { test() { throws(() => new EventSource('not a valid url'), { name: 'SyntaxError', - message: 'Cannot open an EventSource to \'not a valid url\'. The URL is invalid.' + message: + "Cannot open an EventSource to 'not a valid url'. The URL is invalid.", }); throws(() => new EventSource(123), { name: 'SyntaxError', - message: 'Cannot open an EventSource to \'123\'. The URL is invalid.' + message: "Cannot open an EventSource to '123'. The URL is invalid.", }); - throws(() => new EventSource('http://example.org', { withCredentials: true }), { - name: 'NotSupportedError', - message: 'The init.withCredentials option is not supported. It must be false or undefined.' - }); + throws( + () => new EventSource('http://example.org', { withCredentials: true }), + { + name: 'NotSupportedError', + message: + 'The init.withCredentials option is not supported. It must be false or undefined.', + } + ); // Doesn't throw - (new EventSource('http://example.org/message')).close(); - (new EventSource('http://example.org/message', { withCredentials: false })).close(); - (new EventSource('http://example.org/message', { withCredentials: undefined })).close(); - } + new EventSource('http://example.org/message').close(); + new EventSource('http://example.org/message', { + withCredentials: false, + }).close(); + new EventSource('http://example.org/message', { + withCredentials: undefined, + }).close(); + }, }; export const eventSourceFromTest = { async test() { const enc = new TextEncoder(); - const chunks = [ - 'data: first\n\n', - 'data: second\n\n', - 'data: third\n\n', - ]; + const chunks = ['data: first\n\n', 'data: second\n\n', 'data: third\n\n']; const rs = new ReadableStream({ async pull(c) { await scheduler.wait(10); @@ -308,7 +324,7 @@ export const eventSourceFromTest = { if (chunks.length === 0) { c.close(); } - } + }, }); const { promise, resolve } = Promise.withResolvers(); const eventsource = EventSource.from(rs); @@ -333,7 +349,7 @@ export const eventSourceFromTest = { } }; await promise; - } + }, }; export const eventSourceFromWithBOMTest = { @@ -353,7 +369,7 @@ export const eventSourceFromWithBOMTest = { if (chunks.length === 0) { c.close(); } - } + }, }); const { promise, resolve } = Promise.withResolvers(); const eventsource = EventSource.from(rs); @@ -378,7 +394,7 @@ export const eventSourceFromWithBOMTest = { } }; await promise; - } + }, }; export const prototypePropertyTest = { @@ -394,7 +410,7 @@ export const prototypePropertyTest = { ok('readyState' in EventSource.prototype); ok('url' in EventSource.prototype); ok('withCredentials' in EventSource.prototype); - } + }, }; export const disposable = { @@ -406,7 +422,7 @@ export const disposable = { strictEqual(eventsource.readyState, EventSource.OPEN); eventsource[Symbol.dispose](); strictEqual(eventsource.readyState, EventSource.CLOSED); - } + }, }; // ====================================================================================== @@ -449,14 +465,14 @@ async function lastEventId(request) { return new Response('id: 1\ndata: first\n\n', { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } else { return new Response(`data: ${lastEventId}\n\n`, { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } @@ -465,34 +481,32 @@ async function lastEventId(request) { async function eventIdPersists(request) { return new Response( 'id: 1\ndata: first\n\n' + - 'data: second\n\n' + - 'id: 2\ndata: third\n\n' + - 'data: fourth\n\n', { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' - }, - }); + 'data: second\n\n' + + 'id: 2\ndata: third\n\n' + + 'data: fourth\n\n', + { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + }, + } + ); } async function eventIdResets(request) { - return new Response( - 'id: 1\ndata: first\n\n' + - 'id: \ndata: second\n\n', { + return new Response('id: 1\ndata: first\n\n' + 'id: \ndata: second\n\n', { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } async function eventIdResets2(request) { - return new Response( - 'id: 1\ndata: first\n\n' + - 'id\ndata: second\n\n', { + return new Response('id: 1\ndata: first\n\n' + 'id\ndata: second\n\n', { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } @@ -502,87 +516,83 @@ async function message(request) { // including good messages, comments, and bad fields. return new Response( 'data: one\n' + - 'data: two\n\n' + - ': comment' + - 'falsefield:msg\n\n' + - 'falsefield:msg\n' + - 'Data: data\n\n' + - 'data\n\n' + - 'data:end\n\n', { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' - }, - }); - + 'data: two\n\n' + + ': comment' + + 'falsefield:msg\n\n' + + 'falsefield:msg\n' + + 'Data: data\n\n' + + 'data\n\n' + + 'data:end\n\n', + { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + }, + } + ); } let reconnectTestCount = 0; async function reconnectFail(request) { switch (reconnectTestCount++) { case 0: { - return new Response( - 'data: opened\n\n', { + return new Response('data: opened\n\n', { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } case 1: { - return new Response( - 'data: reconnected\n\n', { + return new Response('data: reconnected\n\n', { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, }); } case 2: - // Fall-through + // Fall-through case 3: { - return new Response( - null, { + return new Response(null, { headers: { 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' + 'Cache-Control': 'no-cache', }, - status: 204 + status: 204, }); - } } } async function statusError(request) { return new Response(null, { - status: 500 + status: 500, }); } async function event(request) { return new Response( - 'event: test\n' + - 'data: first\n\n' + - 'event: test\n' + - 'data: second\n\n', { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' - }, - }); + 'event: test\n' + 'data: first\n\n' + 'event: test\n' + 'data: second\n\n', + { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + }, + } + ); } async function retry(request) { return new Response( - 'retry: 3000\n\n' + - 'data: first\n\n' + - 'data: second\n\n', { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache' - }, - }); + 'retry: 3000\n\n' + 'data: first\n\n' + 'data: second\n\n', + { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + }, + } + ); } export default { @@ -593,6 +603,5 @@ export default { throw new Error('Not found'); } return await handler(request); - } + }, }; - diff --git a/src/workerd/api/tests/form-data-legacy-test.js b/src/workerd/api/tests/form-data-legacy-test.js index 0671b3c9108..2526b5b7ad9 100644 --- a/src/workerd/api/tests/form-data-legacy-test.js +++ b/src/workerd/api/tests/form-data-legacy-test.js @@ -32,27 +32,37 @@ qux-content method: 'POST', body: INPUT, headers: { - 'content-type': 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a' - } + 'content-type': + 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a', + }, }); const form = await req.formData(); - form.set("foo", new File(["foo-content"], "foo.txt")); - form.append("bar", new File(["bar1-content"], "bar1.txt"), "bar-renamed.txt"); - form.append("bar", new File(["bar2-content"], "bar2.txt", {type: "text/bary"})); - form.append("baz", new Blob(["baz-content"], {type: "text/bazzy"})); - form.set("qux", new Blob(["qux-content"]), "qux\n\"\\.txt"); + form.set('foo', new File(['foo-content'], 'foo.txt')); + form.append( + 'bar', + new File(['bar1-content'], 'bar1.txt'), + 'bar-renamed.txt' + ); + form.append( + 'bar', + new File(['bar2-content'], 'bar2.txt', { type: 'text/bary' }) + ); + form.append('baz', new Blob(['baz-content'], { type: 'text/bazzy' })); + form.set('qux', new Blob(['qux-content']), 'qux\n"\\.txt'); { let resp = new Response(form); let text = await resp.text(); - let roundtrip = await new Response(text, {headers: resp.headers}).formData(); - if (roundtrip.get("foo") != "foo-content") { - throw new Error("expected round-trip turns into string (wrong, but backwards-compatible)"); + let roundtrip = await new Response(text, { + headers: resp.headers, + }).formData(); + if (roundtrip.get('foo') != 'foo-content') { + throw new Error( + 'expected round-trip turns into string (wrong, but backwards-compatible)' + ); } } - - } + }, }; - diff --git a/src/workerd/api/tests/form-data-test.js b/src/workerd/api/tests/form-data-test.js index 29a14fca45f..d96f4616d6d 100644 --- a/src/workerd/api/tests/form-data-test.js +++ b/src/workerd/api/tests/form-data-test.js @@ -8,7 +8,6 @@ import { export const apiFormDataParse = { async test(ctrl, env) { - const INPUT = `--- Content-Disposition: form-data; name="field0" @@ -31,15 +30,15 @@ part3 method: 'POST', body: INPUT, headers: { - 'content-type': 'multipart/form-data; Boundary="-"' - } + 'content-type': 'multipart/form-data; Boundary="-"', + }, }); const formData = await req.formData(); deepStrictEqual(formData.getAll('field0'), ['part0', 'part2']); deepStrictEqual(formData.getAll('field1'), ['part1', 'part3']); - } + }, }; export const invalidFormdataContentDisposition = { @@ -56,20 +55,23 @@ foo-content method: 'POST', body: INPUT, headers: { - 'content-type': 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a' - } + 'content-type': + 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a', + }, }); try { await req.formData(); throw new Error('Parsing the form data should have thrown'); } catch (err) { - strictEqual(err.message, - 'Content-Disposition header for FormData part must ' + - 'have the value "form-data", possibly followed by ' + - 'parameters. Got: "foobar"'); + strictEqual( + err.message, + 'Content-Disposition header for FormData part must ' + + 'have the value "form-data", possibly followed by ' + + 'parameters. Got: "foobar"' + ); } - } + }, }; export const invalidFormData = { @@ -83,9 +85,9 @@ export const invalidFormData = { }); throw new Error('should have thrown'); } catch (err) { - strictEqual(err.message, 'Name or filename can\'t end with backslash'); + strictEqual(err.message, "Name or filename can't end with backslash"); } - } + }, }; export const formDataWithFilesBlobs = { @@ -122,13 +124,14 @@ qux-content method: 'POST', body: INPUT, headers: { - 'content-type': 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a' - } + 'content-type': + 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a', + }, }); async function assertFile(file, name, type, content) { if (!(file instanceof File)) { - throw new Error("not a File: " + file); + throw new Error('not a File: ' + file); } strictEqual(name, file.name); @@ -137,17 +140,32 @@ qux-content } const form = await req.formData(); - await assertFile(form.get("foo"), "foo.txt", - "application/octet-stream", "foo-content"); - await assertFile(form.getAll("bar")[0], "bar-renamed.txt", - "application/octet-stream", "bar1-content"); - await assertFile(form.getAll("bar")[1], - "bar2.txt", "text/bary", "bar2-content"); - await assertFile(form.get("baz"), "baz", "text/bazzy", - "baz-content"); - await assertFile(form.get("qux"), "qux%0A%22\\.txt", - "application/octet-stream", "qux-content"); - } + await assertFile( + form.get('foo'), + 'foo.txt', + 'application/octet-stream', + 'foo-content' + ); + await assertFile( + form.getAll('bar')[0], + 'bar-renamed.txt', + 'application/octet-stream', + 'bar1-content' + ); + await assertFile( + form.getAll('bar')[1], + 'bar2.txt', + 'text/bary', + 'bar2-content' + ); + await assertFile(form.get('baz'), 'baz', 'text/bazzy', 'baz-content'); + await assertFile( + form.get('qux'), + 'qux%0A%22\\.txt', + 'application/octet-stream', + 'qux-content' + ); + }, }; export const sendFilesInFormdata = { @@ -184,29 +202,36 @@ qux-content method: 'POST', body: INPUT, headers: { - 'content-type': 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a' - } + 'content-type': + 'multipart/form-data;boundary=2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a', + }, }); const form = await req.formData(); - form.set("foo", new File(["foo-content"], "foo.txt")); - form.append("bar", new File(["bar1-content"], "bar1.txt"), "bar-renamed.txt"); - form.append("bar", new File(["bar2-content"], "bar2.txt", {type: "text/bary"})); - form.append("baz", new Blob(["baz-content"], {type: "text/bazzy"})); - form.set("qux", new Blob(["qux-content"]), "qux\n\"\\.txt"); - - if (!(form.get("foo") instanceof File)) { - throw new Error("expected file"); + form.set('foo', new File(['foo-content'], 'foo.txt')); + form.append( + 'bar', + new File(['bar1-content'], 'bar1.txt'), + 'bar-renamed.txt' + ); + form.append( + 'bar', + new File(['bar2-content'], 'bar2.txt', { type: 'text/bary' }) + ); + form.append('baz', new Blob(['baz-content'], { type: 'text/bazzy' })); + form.set('qux', new Blob(['qux-content']), 'qux\n"\\.txt'); + + if (!(form.get('foo') instanceof File)) { + throw new Error('expected file'); } - if (form.get("foo").name != "foo.txt") { - throw new Error("expected file name foo.txt"); + if (form.get('foo').name != 'foo.txt') { + throw new Error('expected file name foo.txt'); } - if (!(form.getAll("bar")[1] instanceof File)) { - throw new Error("expected files"); + if (!(form.getAll('bar')[1] instanceof File)) { + throw new Error('expected files'); } - - } + }, }; async function parseFormData(contentType, text) { @@ -227,9 +252,9 @@ export const testFormDataParser = { // No parts. Note that Chrome throws a TypeError on this input, but it'll generate output that // looks like this if you ask it to serialize an empty form. contentType: 'multipart/form-data; boundary="+"', - body: "--+--", - expected: "", - comment: "Empty form is okay", + body: '--+--', + expected: '', + comment: 'Empty form is okay', }, { contentType: 'multipart/form-data; boundary="+"', @@ -259,9 +284,9 @@ export const testFormDataParser = { 'part3\r\n', '--+--', - ].join(""), - expected: "field0=part0,field1=part1,field0=part2,field1=part3", - comment: "Mixed CRLF and LF, case-insensitivity of header name", + ].join(''), + expected: 'field0=part0,field1=part1,field0=part2,field1=part3', + comment: 'Mixed CRLF and LF, case-insensitivity of header name', }, { contentType: 'multipart/form-data; boundary="+"', @@ -315,9 +340,10 @@ export const testFormDataParser = { '\n', '--+--', - ].join(""), - expected: "empties=,empties=,empties=,empties=,empties=,empties=,empties=,empties=", - comment: "Mixed CRLF and LF with empty messages", + ].join(''), + expected: + 'empties=,empties=,empties=,empties=,empties=,empties=,empties=,empties=', + comment: 'Mixed CRLF and LF with empty messages', }, { contentType: 'multipart/form-data; boundary="+"', @@ -335,9 +361,9 @@ export const testFormDataParser = { 'part1\r\n', '--+--', - ].join(""), - expected: "field0=part0,field1=part1", - comment: "Content-Type header should be okay", + ].join(''), + expected: 'field0=part0,field1=part1', + comment: 'Content-Type header should be okay', }, { contentType: 'application/x-www-form-urlencoded', @@ -346,29 +372,23 @@ export const testFormDataParser = { 'field1=part1', 'field0=part2', 'field1=part3', - ].join("&"), - expected: "field0=part0,field1=part1,field0=part2,field1=part3", - comment: "Basic application/x-www-form-urlencoded parse works", + ].join('&'), + expected: 'field0=part0,field1=part1,field0=part2,field1=part3', + comment: 'Basic application/x-www-form-urlencoded parse works', }, { contentType: 'application/x-www-form-urlencoded', - body: [ - 'field0=data+with+an+%26+in+it', - ].join("&"), - expected: "field0=data with an & in it", - comment: "application/x-www-form-urlencoded data gets percent-and-plus-decoded", + body: ['field0=data+with+an+%26+in+it'].join('&'), + expected: 'field0=data with an & in it', + comment: + 'application/x-www-form-urlencoded data gets percent-and-plus-decoded', }, { contentType: 'application/x-www-form-urlencoded', - body: [ - '', - '=', - 'field1', - '=part2', - 'field1=', - ].join("&"), - expected: "=,field1=,=part2,field1=", - comment: "application/x-www-form-urlencoded data with awkward &, = placement", + body: ['', '=', 'field1', '=part2', 'field1='].join('&'), + expected: '=,field1=,=part2,field1=', + comment: + 'application/x-www-form-urlencoded data with awkward &, = placement', }, ]; @@ -385,18 +405,18 @@ export const testFormDataParser = { let failureCases = [ { contentType: 'multipart/form-data; boundary="+"', - body: "", - comment: "Empty body throws", + body: '', + comment: 'Empty body throws', }, { contentType: 'multipart/form-data; boundary="+"', - body: "--asdf--", - comment: "Bad boundary throws", + body: '--asdf--', + comment: 'Bad boundary throws', }, { contentType: 'multipart/form-data; boundary="+"', - body: "--+", - comment: "Non-terminal boundary at end throws", + body: '--+', + comment: 'Non-terminal boundary at end throws', }, { contentType: 'multipart/form-data; boundary="+"', @@ -406,8 +426,8 @@ export const testFormDataParser = { '\r\n', 'part0\r\n', '-+--', - ].join(""), - comment: "Bad terminal delimiter", + ].join(''), + comment: 'Bad terminal delimiter', }, { contentType: 'multipart/form-data; boundary="+"', @@ -417,8 +437,8 @@ export const testFormDataParser = { '\r\n', 'part0\r\n', '--+--', - ].join(""), - comment: "Bad Content-Disposition header", + ].join(''), + comment: 'Bad Content-Disposition header', }, { contentType: 'multipart/form-data; boundary="+"', @@ -428,8 +448,8 @@ export const testFormDataParser = { '\r\n', 'part0\r\n', '--+--', - ].join(""), - comment: "Bad Content-Disposition header", + ].join(''), + comment: 'Bad Content-Disposition header', }, { contentType: 'multipart/form-data; boundary="+"', @@ -439,8 +459,8 @@ export const testFormDataParser = { '\r', 'part0\r\n', '--+--', - ].join(""), - comment: "No header termination CRLFCRLF", + ].join(''), + comment: 'No header termination CRLFCRLF', }, { contentType: 'multipart/form-data; boundary="+"', @@ -449,8 +469,8 @@ export const testFormDataParser = { 'Content-Disposition: form-data; name="field0"\r\n', '\r\n', 'part0\r\n', - ].join(""), - comment: "No subsequent boundary string", + ].join(''), + comment: 'No subsequent boundary string', }, { contentType: 'multipart/form-data; boundary="+"', @@ -460,27 +480,27 @@ export const testFormDataParser = { '\r\n', 'part0\r\n', '--+\r--', - ].join(""), + ].join(''), comment: "Boundary was not succeeded by CRLF, LF, or '--'", }, { contentType: 'multipart/form-data; boundary=', body: '----', - comment: "Empty boundary parameter in content-type", + comment: 'Empty boundary parameter in content-type', }, { contentType: 'application/x-www-form-urlencoded; charset=big5', body: '--+--', - comment: "Unsupported charset", - } + comment: 'Unsupported charset', + }, ]; for (let i = 0; i < failureCases.length; ++i) { const c = failureCases[i]; await rejects(() => parseFormData(c.contentType, c.body)); } - } -} + }, +}; export const testFormDataSerializer = { async test() { @@ -498,16 +518,20 @@ export const testFormDataSerializer = { // Parse it back. // This regex assumes an unquoted boundary, which is true for our serializer. - const boundary = /boundary=(.+)$/.exec(response.headers.get("Content-Type"))[1]; - const actual = await parseFormData(`multipart/form-data; boundary="${boundary}"`, - await response.text()); + const boundary = /boundary=(.+)$/.exec( + response.headers.get('Content-Type') + )[1]; + const actual = await parseFormData( + `multipart/form-data; boundary="${boundary}"`, + await response.text() + ); const expectedData = [ - "field0=part0", - "field1=part1", - "field0=part2", - "field1=part3", - "field-with-a-%22-in-it=part4", + 'field0=part0', + 'field1=part1', + 'field0=part2', + 'field1=part3', + 'field-with-a-%22-in-it=part4', ]; const actualData = []; for (let [k, v] of actual) { @@ -515,7 +539,7 @@ export const testFormDataSerializer = { } strictEqual('' + actualData.join(','), '' + expectedData.join(',')); - } + }, }; export const testFormDataSet = { @@ -530,7 +554,7 @@ export const testFormDataSet = { fd.set('foo', '6'); strictEqual('' + fd.getAll('foo'), '6'); - } + }, }; export const testFormDataIterators = { @@ -543,71 +567,78 @@ export const testFormDataIterators = { strictEqual(key.next().value, undefined); strictEqual(value.next().value, undefined); - fd.append("key", "0"); - fd.append("key", "1"); - strictEqual("" + entry.next().value, "key,0"); - strictEqual("" + key.next().value, "key"); - strictEqual("" + value.next().value, "0"); + fd.append('key', '0'); + fd.append('key', '1'); + strictEqual('' + entry.next().value, 'key,0'); + strictEqual('' + key.next().value, 'key'); + strictEqual('' + value.next().value, '0'); - fd.delete("key"); + fd.delete('key'); strictEqual(entry.next().value, undefined); strictEqual(key.next().value, undefined); strictEqual(value.next().value, undefined); - } + }, }; export const testFormDataForeach = { test() { const fd = new FormData(); - fd.forEach(function(v, k, t) { + fd.forEach(function (v, k, t) { throw new Error('should not be called on empty array'); }); let foreachOutput = []; - fd.append("key1", "value1"); - fd.append("key2", "value2"); + fd.append('key1', 'value1'); + fd.append('key2', 'value2'); let i = 0; - fd.forEach(function(value, key, captureFd) { - notStrictEqual(value, "3"); // if this is true, then the test is useless + fd.forEach(function (value, key, captureFd) { + notStrictEqual(value, '3'); // if this is true, then the test is useless // updating the headers should affect them immediately when not called through forEach - captureFd.set(key, "3"); - strictEqual(captureFd.get(key), "3"); + captureFd.set(key, '3'); + strictEqual(captureFd.get(key), '3'); // updating the headers should not affect `value` - notStrictEqual(value, "3"); + notStrictEqual(value, '3'); foreachOutput.push(`${key}=${value}`); - captureFd.append("some-key", "4"); + captureFd.append('some-key', '4'); // console.log("appended"); i += 1; }); // appending keys within the loop should call the callback on the new items strictEqual(i, 4); - strictEqual("" + foreachOutput.join('&'), "key1=value1&key2=value2&some-key=4&some-key=4"); + strictEqual( + '' + foreachOutput.join('&'), + 'key1=value1&key2=value2&some-key=4&some-key=4' + ); // `capture_headers.set` should affect the outer headers object - strictEqual(fd.get("key1"), "3"); - strictEqual(fd.get("key2"), "3"); + strictEqual(fd.get('key1'), '3'); + strictEqual(fd.get('key2'), '3'); // `capture_headers.append` should affect the outer object - deepStrictEqual(fd.getAll("some-key"), ["3", "4"]); + deepStrictEqual(fd.getAll('some-key'), ['3', '4']); throws(() => fd.forEach()); throws(() => fd.forEach(1)); // `this` can be overriden by setting the second argument - fd.forEach(function() { + fd.forEach(function () { // NOTE: can't use `assert_equals` because `this` has type `object` which apparently it doesn't like strictEqual(this, 1); }, 1); - throws(() => { fd.forEach(function() { throw new Error("boo"); }) }); + throws(() => { + fd.forEach(function () { + throw new Error('boo'); + }); + }); // forEach should not move the value - fd.set("key1", "a"); + fd.set('key1', 'a'); fd.forEach(() => {}); - strictEqual(fd.get("key1"), "a"); - } + strictEqual(fd.get('key1'), 'a'); + }, }; export const w3cTestFormDataAppend = { @@ -617,37 +648,50 @@ export const w3cTestFormDataAppend = { for (let [k, v] of creator()) { result.push(`${k}=${v}`); } - verifier(result.join(",")); + verifier(result.join(',')); } - test_formdata(function() { - var fd = new FormData(); - fd.append("name", new String("value")); - return fd; - }, function(data) { - strictEqual(data, "name=value"); - }, "Passing a String object to FormData.append should work."); - - strictEqual(create_formdata(['key', 'value1']).get('key'), "value1"); - strictEqual(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value2"); - strictEqual(create_formdata(['key', undefined]).get('key'), "undefined"); - strictEqual(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "undefined"); - strictEqual(create_formdata(['key', null]).get('key'), "null"); - strictEqual(create_formdata(['key', null], ['key', 'value1']).get('key'), "null"); + test_formdata( + function () { + var fd = new FormData(); + fd.append('name', new String('value')); + return fd; + }, + function (data) { + strictEqual(data, 'name=value'); + }, + 'Passing a String object to FormData.append should work.' + ); + + strictEqual(create_formdata(['key', 'value1']).get('key'), 'value1'); + strictEqual( + create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), + 'value2' + ); + strictEqual(create_formdata(['key', undefined]).get('key'), 'undefined'); + strictEqual( + create_formdata(['key', undefined], ['key', 'value1']).get('key'), + 'undefined' + ); + strictEqual(create_formdata(['key', null]).get('key'), 'null'); + strictEqual( + create_formdata(['key', null], ['key', 'value1']).get('key'), + 'null' + ); function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { fd.append.apply(fd, arguments[i]); - }; + } return fd; } - } + }, }; export const w3cTestFormDataBlob = { test() { - function create_formdata () { + function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { fd.append.apply(fd, arguments[i]); @@ -656,7 +700,7 @@ export const w3cTestFormDataBlob = { } throws(() => create_formdata('a', 'b', 'c')); - } + }, }; export const w3cTestFormDataDelete = { @@ -678,16 +722,16 @@ export const w3cTestFormDataDelete = { fd.delete('key1'); strictEqual(fd.get('key1'), null); strictEqual(fd.get('key2'), 'value2'); - }; + } function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { fd.append.apply(fd, arguments[i]); - }; + } return fd; } - } + }, }; export const w3cTestFormDataForeach = { @@ -709,7 +753,8 @@ export const w3cTestFormDataForeach = { //var expected_values = ['v1', 'v3', 'v4', 'v6', file]; { - var mykeys = [], myvalues = []; + var mykeys = [], + myvalues = []; for (var entry of fd) { strictEqual(entry.length, 2); mykeys.push(entry[0]); @@ -720,70 +765,98 @@ export const w3cTestFormDataForeach = { } { - var mykeys = [], myvalues = []; + var mykeys = [], + myvalues = []; for (var entry of fd.entries()) { - strictEqual(entry.length, 2, - 'entries() iterator should yield key/value pairs'); + strictEqual( + entry.length, + 2, + 'entries() iterator should yield key/value pairs' + ); mykeys.push(entry[0]); myvalues.push(entry[1]); } - deepStrictEqual(mykeys, expected_keys, - 'entries() iterator should see duplicate keys'); - deepStrictEqual(myvalues, expected_values, - 'entries() iterator should see non-deleted values'); + deepStrictEqual( + mykeys, + expected_keys, + 'entries() iterator should see duplicate keys' + ); + deepStrictEqual( + myvalues, + expected_values, + 'entries() iterator should see non-deleted values' + ); } { var mykeys = []; - for (var entry of fd.keys()) - mykeys.push(entry); + for (var entry of fd.keys()) mykeys.push(entry); deepStrictEqual(mykeys, expected_keys); } { var myvalues = []; - for (var entry of fd.values()) - myvalues.push(entry); - deepStrictEqual(myvalues, expected_values, - 'values() iterator should see non-deleted values'); + for (var entry of fd.values()) myvalues.push(entry); + deepStrictEqual( + myvalues, + expected_values, + 'values() iterator should see non-deleted values' + ); } - } -} + }, +}; export const w3cTestFormDataGet = { test() { - strictEqual(create_formdata(['key', 'value1'], ['key', 'value2']).get('key'), "value1"); - strictEqual(create_formdata(['key', 'value1'], ['key', 'value2']).get('nil'), null); + strictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).get('key'), + 'value1' + ); + strictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).get('nil'), + null + ); strictEqual(create_formdata().get('key'), null); - deepStrictEqual(create_formdata(['key', 'value1'], - ['key', 'value2']).getAll('key'), ["value1", "value2"]); - deepStrictEqual(create_formdata(['key', 'value1'], ['key', 'value2']).getAll('nil'), []); + deepStrictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).getAll('key'), + ['value1', 'value2'] + ); + deepStrictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).getAll('nil'), + [] + ); deepStrictEqual(create_formdata().getAll('key'), []); function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { - fd.append.apply(fd, arguments[i]); - }; + fd.append.apply(fd, arguments[i]); + } return fd; } - } + }, }; export const w3cTestFormDataHas = { test() { - strictEqual(create_formdata(['key', 'value1'], ['key', 'value2']).has('key'), true); - strictEqual(create_formdata(['key', 'value1'], ['key', 'value2']).has('nil'), false); + strictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).has('key'), + true + ); + strictEqual( + create_formdata(['key', 'value1'], ['key', 'value2']).has('nil'), + false + ); strictEqual(create_formdata().has('key'), false); function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { - fd.append.apply(fd, arguments[i]); - }; + fd.append.apply(fd, arguments[i]); + } return fd; } - } + }, }; export const w3cTestFormDataSet = { @@ -793,23 +866,36 @@ export const w3cTestFormDataSet = { for (let [k, v] of creator()) { result.push(`${k}=${v}`); } - verifier(result.join(",")); + verifier(result.join(',')); } - test_formdata(function () { - var fd = new FormData(); - fd.set("name", new String("value")); - return fd; - }, function (data) { - strictEqual(data, "name=value"); - }, "Passing a String object to FormData.set should work"); - - strictEqual(create_formdata(['key', 'value1']).get('key'), "value1"); - strictEqual(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value1"); - strictEqual(create_formdata(['key', undefined]).get('key'), "undefined"); - strictEqual(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "value1"); - strictEqual(create_formdata(['key', null]).get('key'), "null"); - strictEqual(create_formdata(['key', null], ['key', 'value1']).get('key'), "value1"); + test_formdata( + function () { + var fd = new FormData(); + fd.set('name', new String('value')); + return fd; + }, + function (data) { + strictEqual(data, 'name=value'); + }, + 'Passing a String object to FormData.set should work' + ); + + strictEqual(create_formdata(['key', 'value1']).get('key'), 'value1'); + strictEqual( + create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), + 'value1' + ); + strictEqual(create_formdata(['key', undefined]).get('key'), 'undefined'); + strictEqual( + create_formdata(['key', undefined], ['key', 'value1']).get('key'), + 'value1' + ); + strictEqual(create_formdata(['key', null]).get('key'), 'null'); + strictEqual( + create_formdata(['key', null], ['key', 'value1']).get('key'), + 'value1' + ); // TODO(conform): Support File/Blob. //test(function () { @@ -824,10 +910,10 @@ export const w3cTestFormDataSet = { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { fd.set.apply(fd, arguments[i]); - }; + } return fd; } - } + }, }; export const w3cTestFormData = { @@ -837,19 +923,23 @@ export const w3cTestFormData = { for (let [k, v] of fd) { result.push(`${k}=${v}`); } - strictEqual(result.join(","), expected, name); + strictEqual(result.join(','), expected, name); } - function create_formdata () { + function create_formdata() { var fd = new FormData(); for (var i = 0; i < arguments.length; i++) { fd.append.apply(fd, arguments[i]); - }; + } return fd; } - do_test("empty formdata", new FormData(), ''); - do_test("formdata with string", create_formdata(['key', 'value']), 'key=value'); + do_test('empty formdata', new FormData(), ''); + do_test( + 'formdata with string', + create_formdata(['key', 'value']), + 'key=value' + ); //do_test("formdata with named string", create_formdata(['key', new Blob(['value'], {type: 'text/plain'}), 'kv.txt']), '\nkey=kv.txt:text/plain:5,'); - } + }, }; diff --git a/src/workerd/api/tests/global-scope-test.js b/src/workerd/api/tests/global-scope-test.js index e6420aa0337..eed176ec3bc 100644 --- a/src/workerd/api/tests/global-scope-test.js +++ b/src/workerd/api/tests/global-scope-test.js @@ -9,7 +9,7 @@ import { export const navigatorUserAgent = { async test() { strictEqual(navigator.userAgent, 'Cloudflare-Workers'); - } + }, }; export const timeoutClamping = { @@ -19,17 +19,17 @@ export const timeoutClamping = { const p1 = new Promise((resolve) => { setTimeout(() => { resolve('b'); - }, 9223372036854775808); // Will be clamped to a max of 3153600000000 + }, 9223372036854775808); // Will be clamped to a max of 3153600000000 }); const p2 = new Promise((resolve) => { setTimeout(() => { resolve('a'); - }, -100); // Will be clamped to 0 + }, -100); // Will be clamped to 0 }); strictEqual(await Promise.race([p1, p2]), 'a'); - } + }, }; export const timeoutCount = { @@ -38,9 +38,10 @@ export const timeoutCount = { setTimeout(() => {}); } throws(() => setTimeout(() => {}), { - message: 'You have exceeded the number of active timeouts you may set. max active timeouts: 10000, current active timeouts: 10000, finished timeouts: 0' + message: + 'You have exceeded the number of active timeouts you may set. max active timeouts: 10000, current active timeouts: 10000, finished timeouts: 0', }); - } + }, }; export const timeoutImplicitCancel = { @@ -49,32 +50,41 @@ export const timeoutImplicitCancel = { setTimeout(() => { throw new Error('boom'); }, 100000); - } + }, }; export const timeoutVarargs = { async test() { let resolve; - const promise = new Promise((a) => resolve = a); - setTimeout((a,b,c) => { - resolve([a,b,c]); - }, 10, 1, 2, 3); + const promise = new Promise((a) => (resolve = a)); + setTimeout( + (a, b, c) => { + resolve([a, b, c]); + }, + 10, + 1, + 2, + 3 + ); const results = await promise; - deepStrictEqual(results, [1,2,3]); - } + deepStrictEqual(results, [1, 2, 3]); + }, }; export const intervalVarargs = { async test() { let resolve; - const promise = new Promise((a) => resolve = a); + const promise = new Promise((a) => (resolve = a)); + + // prettier-ignore const i = setInterval((a,b,c) => { resolve([a,b,c]); clearInterval(i); }, 10, 1, 2, 3); + const results = await promise; - deepStrictEqual(results, [1,2,3]); - } + deepStrictEqual(results, [1, 2, 3]); + }, }; export const mutableGlobals = { @@ -96,7 +106,11 @@ export const mutableGlobals = { caches: { value: 'hello there', writable: true, configurable: true }, crypto: { value: 'we are', writable: true, configurable: true }, self: { value: 'mutable', writable: true, configurable: true }, - scheduler: { value: 'at global scope', writable: true, configurable: true }, + scheduler: { + value: 'at global scope', + writable: true, + configurable: true, + }, }); strictEqual(globalThis.caches, 'hello there'); strictEqual(globalThis.crypto, 'we are'); @@ -107,60 +121,63 @@ export const mutableGlobals = { globalThis.self = oldSelf; globalThis.scheduler = oldScheduler; } - - } + }, }; export const queueMicrotask = { async test() { [1, undefined, 'hello'].forEach((i) => { throws(() => globalThis.queueMicrotask(i), { - message: "Failed to execute 'queueMicrotask' on 'ServiceWorkerGlobalScope': " + - "parameter 1 is not of type 'Function'." + message: + "Failed to execute 'queueMicrotask' on 'ServiceWorkerGlobalScope': " + + "parameter 1 is not of type 'Function'.", }); }); let resolve; - const promise = new Promise((a) => resolve = a); + const promise = new Promise((a) => (resolve = a)); globalThis.queueMicrotask(resolve); await promise; - } + }, }; export const unhandledRejectionHandler = { async test() { let resolve; - const promise = new Promise((a) => resolve = a); - addEventListener('unhandledrejection', (event) => { - resolve(); - }, {once:true}); + const promise = new Promise((a) => (resolve = a)); + addEventListener( + 'unhandledrejection', + (event) => { + resolve(); + }, + { once: true } + ); // This should trigger the unhandledrejection handler Promise.reject('boom'); await promise; - } + }, }; export const unhandledRejectionHandler2 = { async test() { let resolve; - const promise = new Promise((a) => resolve = a); + const promise = new Promise((a) => (resolve = a)); const handler = (event) => { throw new Error('should not have fired'); }; addEventListener('unhandledrejection', handler); try { await Promise.reject('boom'); - } catch { - } + } catch {} await Promise.reject('boom').catch(() => {}); removeEventListener('unhandledrejection', handler); - } + }, }; export const unhandledRejectionHandler3 = { async test() { let resolve, resolve2; - const promise = new Promise((a) => resolve = a); - const promise2 = new Promise((a) => resolve2 = a); + const promise = new Promise((a) => (resolve = a)); + const promise2 = new Promise((a) => (resolve2 = a)); addEventListener('unhandledrejection', (event) => { event.promise.catch(() => {}); resolve(); @@ -170,35 +187,36 @@ export const unhandledRejectionHandler3 = { }); Promise.reject('boom'); await Promise.all([promise, promise2]); - } + }, }; export const unhandledRejectionHandler4 = { async test() { let resolve; - const promise = new Promise((a) => resolve = a); + const promise = new Promise((a) => (resolve = a)); addEventListener('unhandledrejection', (event) => { throw new Error('does not crash. safe to ignore in test logs'); }); Promise.reject('boom'); - } + }, }; export const structuredClone = { test() { - { - strictEqual(globalThis.structuredClone("hello"), "hello"); + strictEqual(globalThis.structuredClone('hello'), 'hello'); } { const a = { b: { - c: [{ - d: 1 - }] - } + c: [ + { + d: 1, + }, + ], + }, }; const clone = globalThis.structuredClone(a); a.b.c[0].d = 2; @@ -208,28 +226,31 @@ export const structuredClone = { { const enc = new TextEncoder(); const dec = new TextDecoder(); - const u8 = enc.encode("hello"); + const u8 = enc.encode('hello'); const clone = globalThis.structuredClone(u8); - strictEqual(dec.decode(clone), "hello"); + strictEqual(dec.decode(clone), 'hello'); } { const enc = new TextEncoder(); const dec = new TextDecoder(); - const u8 = enc.encode("hello"); - const clone = globalThis.structuredClone({a: u8 }); + const u8 = enc.encode('hello'); + const clone = globalThis.structuredClone({ a: u8 }); u8[0] = 1; strictEqual(dec.decode(u8), '\u0001ello'); - strictEqual(dec.decode(clone.a), "hello"); + strictEqual(dec.decode(clone.a), 'hello'); } { const enc = new TextEncoder(); const dec = new TextDecoder(); - const u8 = enc.encode("hello"); - const clone = globalThis.structuredClone({a: u8 }, { transfer: [ u8.buffer ] }); + const u8 = enc.encode('hello'); + const clone = globalThis.structuredClone( + { a: u8 }, + { transfer: [u8.buffer] } + ); strictEqual(u8.byteLength, 0); - strictEqual(dec.decode(clone.a), "hello"); + strictEqual(dec.decode(clone.a), 'hello'); } { @@ -258,28 +279,31 @@ export const structuredClone = { { const u8 = new Uint8Array(1); - globalThis.structuredClone(u8, { transfer: [ u8.buffer, u8.buffer ] }); + globalThis.structuredClone(u8, { transfer: [u8.buffer, u8.buffer] }); } // Non-transferable objects throw throws(() => globalThis.structuredClone({}, { transfer: {} })); - const memory = new WebAssembly.Memory({initial: 2, maximum: 2}); + const memory = new WebAssembly.Memory({ initial: 2, maximum: 2 }); throws(() => globalThis.structuredClone(memory)); - - } + }, }; export const base64 = { test() { - function format_value(elem) { return elem; } + function format_value(elem) { + return elem; + } // Cloudflare note: The real format_value() is in testharness.js. function generate_tests(f, cases) { // Cloudflare note: the real generate_tests() is in the real testharness.js, and presumably it // calls test(t[0], () => { f(t[1]) }), or something, for each `t` in `cases`. We can forgo the // description element (t[0]) for our purposes. - cases.forEach(([description, testCase]) => { f(testCase); }); + cases.forEach(([description, testCase]) => { + f(testCase); + }); } /** @@ -294,11 +318,11 @@ export const base64 = { // greater than U+00FF." for (var i = 0; i < s.length; i++) { if (s.charCodeAt(i) > 255) { - return "INVALID_CHARACTER_ERR"; + return 'INVALID_CHARACTER_ERR'; } } - var out = ""; + var out = ''; for (var i = 0; i < s.length; i += 3) { var groupsOfSix = [undefined, undefined, undefined, undefined]; groupsOfSix[0] = s.charCodeAt(i) >> 2; @@ -312,8 +336,8 @@ export const base64 = { groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f; } for (var j = 0; j < groupsOfSix.length; j++) { - if (typeof groupsOfSix[j] == "undefined") { - out += "="; + if (typeof groupsOfSix[j] == 'undefined') { + out += '='; } else { out += btoaLookup(groupsOfSix[j]); } @@ -355,13 +379,13 @@ export const base64 = { input = String(input); // "Remove all space characters from input." - input = input.replace(/[ \t\n\f\r]/g, ""); + input = input.replace(/[ \t\n\f\r]/g, ''); // "If the length of input divides by 4 leaving no remainder, then: if // input ends with one or two U+003D EQUALS SIGN (=) characters, remove // them from input." if (input.length % 4 == 0 && /==?$/.test(input)) { - input = input.replace(/==?$/, ""); + input = input.replace(/==?$/, ''); } // "If the length of input divides by 4 leaving a remainder of 1, throw an @@ -376,13 +400,12 @@ export const base64 = { // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9) // U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z // U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z" - if (input.length % 4 == 1 - || !/^[+/0-9A-Za-z]*$/.test(input)) { + if (input.length % 4 == 1 || !/^[+/0-9A-Za-z]*$/.test(input)) { return null; } // "Let output be a string, initially empty." - var output = ""; + var output = ''; // "Let buffer be a buffer that can have bits appended to it, initially // empty." @@ -446,18 +469,18 @@ export const base64 = { */ function atobLookup(chr) { if (/[A-Z]/.test(chr)) { - return chr.charCodeAt(0) - "A".charCodeAt(0); + return chr.charCodeAt(0) - 'A'.charCodeAt(0); } if (/[a-z]/.test(chr)) { - return chr.charCodeAt(0) - "a".charCodeAt(0) + 26; + return chr.charCodeAt(0) - 'a'.charCodeAt(0) + 26; } if (/[0-9]/.test(chr)) { - return chr.charCodeAt(0) - "0".charCodeAt(0) + 52; + return chr.charCodeAt(0) - '0'.charCodeAt(0) + 52; } - if (chr == "+") { + if (chr == '+') { return 62; } - if (chr == "/") { + if (chr == '/') { return 63; } // Throw exception; should not be hit in tests @@ -478,16 +501,38 @@ export const base64 = { strictEqual(globalThis.atob(globalThis.btoa(input)), String(input)); } - var tests = ["עברית", "", "ab", "abc", "abcd", "abcde", + var tests = [ + 'עברית', + '', + 'ab', + 'abc', + 'abcd', + 'abcde', // This one is thrown in because IE9 seems to fail atob(btoa()) on it. Or // possibly to fail btoa(). I actually can't tell what's happening here, // but it doesn't hurt. - "\xff\xff\xc0", + '\xff\xff\xc0', // Is your DOM implementation binary-safe? - "\0a", "a\0b", + '\0a', + 'a\0b', // WebIDL tests. - undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0, - { toString: function () { return "foo" } }, + undefined, + null, + 7, + 12, + 1.5, + true, + false, + NaN, + +Infinity, + -Infinity, + 0, + -0, + { + toString: function () { + return 'foo'; + }, + }, ]; for (var i = 0; i < 258; i++) { tests.push(String.fromCharCode(i)); @@ -498,21 +543,25 @@ export const base64 = { // This is supposed to be U+10000. tests.push(String.fromCharCode(0xd800, 0xdc00)); - tests = tests.map( - function (elem) { - var expected = mybtoa(elem); - if (expected === "INVALID_CHARACTER_ERR") { - return ["btoa(" + format_value(elem) + ") must raise INVALID_CHARACTER_ERR", elem]; - } - return ["btoa(" + format_value(elem) + ") == " + format_value(mybtoa(elem)), elem]; + tests = tests.map(function (elem) { + var expected = mybtoa(elem); + if (expected === 'INVALID_CHARACTER_ERR') { + return [ + 'btoa(' + format_value(elem) + ') must raise INVALID_CHARACTER_ERR', + elem, + ]; } - ); + return [ + 'btoa(' + format_value(elem) + ') == ' + format_value(mybtoa(elem)), + elem, + ]; + }); - var everything = ""; + var everything = ''; for (var i = 0; i < 256; i++) { everything += String.fromCharCode(i); } - tests.push(["btoa(first 256 code points concatenated)", everything]); + tests.push(['btoa(first 256 code points concatenated)', everything]); generate_tests(testBtoa, tests); @@ -526,49 +575,109 @@ export const base64 = { strictEqual(globalThis.atob(input), expected); } - var tests = ["", "abcd", " abcd", "abcd ", " abcd===", "abcd=== ", - "abcd ===", "a", "ab", "abc", "abcde", String.fromCharCode(0xd800, 0xdc00), - "=", "==", "===", "====", "=====", - "a=", "a==", "a===", "a====", "a=====", - "ab=", "ab==", "ab===", "ab====", "ab=====", - "abc=", "abc==", "abc===", "abc====", "abc=====", - "abcd=", "abcd==", "abcd===", "abcd====", "abcd=====", - "abcde=", "abcde==", "abcde===", "abcde====", "abcde=====", - "=a", "=a=", "a=b", "a=b=", "ab=c", "ab=c=", "abc=d", "abc=d=", + var tests = [ + '', + 'abcd', + ' abcd', + 'abcd ', + ' abcd===', + 'abcd=== ', + 'abcd ===', + 'a', + 'ab', + 'abc', + 'abcde', + String.fromCharCode(0xd800, 0xdc00), + '=', + '==', + '===', + '====', + '=====', + 'a=', + 'a==', + 'a===', + 'a====', + 'a=====', + 'ab=', + 'ab==', + 'ab===', + 'ab====', + 'ab=====', + 'abc=', + 'abc==', + 'abc===', + 'abc====', + 'abc=====', + 'abcd=', + 'abcd==', + 'abcd===', + 'abcd====', + 'abcd=====', + 'abcde=', + 'abcde==', + 'abcde===', + 'abcde====', + 'abcde=====', + '=a', + '=a=', + 'a=b', + 'a=b=', + 'ab=c', + 'ab=c=', + 'abc=d', + 'abc=d=', // With whitespace - "ab\tcd", "ab\ncd", "ab\fcd", "ab\rcd", "ab cd", "ab\u00a0cd", - "ab\t\n\f\r cd", " \t\n\f\r ab\t\n\f\r cd\t\n\f\r ", - "ab\t\n\f\r =\t\n\f\r =\t\n\f\r ", + 'ab\tcd', + 'ab\ncd', + 'ab\fcd', + 'ab\rcd', + 'ab cd', + 'ab\u00a0cd', + 'ab\t\n\f\r cd', + ' \t\n\f\r ab\t\n\f\r cd\t\n\f\r ', + 'ab\t\n\f\r =\t\n\f\r =\t\n\f\r ', // Test if any bits are set at the end. These should all be fine, since // they end with A, which becomes 0: - "A", "/A", "//A", "///A", "////A", + 'A', + '/A', + '//A', + '///A', + '////A', // These are all bad, since they end in / (= 63, all bits set) but their // length isn't a multiple of four characters, so they can't be output by // btoa(). Thus one might expect some UAs to throw exceptions or otherwise // object, since they could never be output by btoa(), so they're good to // test. - "/", "A/", "AA/", "AAAA/", + '/', + 'A/', + 'AA/', + 'AAAA/', // But this one is possible: - "AAA/", + 'AAA/', // Binary-safety tests - "\0nonsense", "abcd\0nonsense", + '\0nonsense', + 'abcd\0nonsense', // WebIDL tests // TODO(conform): We need automatic stringification of arguments before these will work. //undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0, //{ toString: function () { return "foo" } }, //{ toString: function () { return "abcd" } }, ]; - tests = tests.map( - function (elem) { - if (myatob(elem) === null) { - return ["atob(" + format_value(elem) + ") must raise InvalidCharacterError", elem]; - } - return ["atob(" + format_value(elem) + ") == " + format_value(myatob(elem)), elem]; + tests = tests.map(function (elem) { + if (myatob(elem) === null) { + return [ + 'atob(' + format_value(elem) + ') must raise InvalidCharacterError', + elem, + ]; } - ); + return [ + 'atob(' + format_value(elem) + ') == ' + format_value(myatob(elem)), + elem, + ]; + }); generate_tests(testAtob, tests); - } + }, }; export const webSocketPairIterable = { @@ -576,5 +685,5 @@ export const webSocketPairIterable = { const [a, b] = new WebSocketPair(); ok(a instanceof WebSocket); ok(b instanceof WebSocket); - } + }, }; diff --git a/src/workerd/api/tests/htmlrewriter-test.js b/src/workerd/api/tests/htmlrewriter-test.js index 342e0f30fb7..aea8ca0a990 100644 --- a/src/workerd/api/tests/htmlrewriter-test.js +++ b/src/workerd/api/tests/htmlrewriter-test.js @@ -4,17 +4,19 @@ import { notStrictEqual, rejects, throws, -} from "node:assert"; +} from 'node:assert'; -const arrayIterator = [][Symbol.iterator]() -const arrayIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(arrayIterator)) +const arrayIterator = [][Symbol.iterator](); +const arrayIteratorPrototype = Object.getPrototypeOf( + Object.getPrototypeOf(arrayIterator) +); export const passthroughWithContent = { async test() { const response = new Response('hello', { headers: { - foo: 'bar' - } + foo: 'bar', + }, }); strictEqual(response.headers.get('foo'), 'bar'); @@ -32,8 +34,8 @@ export const passthroughWithContentAndHandler = { async test() { const response = new Response('

hello

', { headers: { - foo: 'bar' - } + foo: 'bar', + }, }); strictEqual(response.headers.get('foo'), 'bar'); @@ -48,15 +50,15 @@ export const passthroughWithContentAndHandler = { notStrictEqual(response, newResponse); strictEqual(newResponse.headers.get('foo'), 'bar'); strictEqual(await newResponse.text(), '

hello

'); - } + }, }; export const passthroughWithContentAndAsyncHandler = { async test() { const response = new Response('

hello

', { headers: { - foo: 'bar' - } + foo: 'bar', + }, }); strictEqual(response.headers.get('foo'), 'bar'); @@ -69,7 +71,7 @@ export const passthroughWithContentAndAsyncHandler = { }, async comments() { await scheduler.wait(10); - } + }, }); const newResponse = rewriter.transform(response); @@ -77,15 +79,15 @@ export const passthroughWithContentAndAsyncHandler = { notStrictEqual(response, newResponse); strictEqual(newResponse.headers.get('foo'), 'bar'); strictEqual(await newResponse.text(), '

hello

'); - } + }, }; export const passthroughWithContentAndAsyncHandler2 = { async test() { const response = new Response('

hello

', { headers: { - foo: 'bar' - } + foo: 'bar', + }, }); strictEqual(response.headers.get('foo'), 'bar'); @@ -100,7 +102,7 @@ export const passthroughWithContentAndAsyncHandler2 = { }, async comments() { await scheduler.wait(10); - } + }, }); const newResponse = rewriter.transform(response); @@ -112,7 +114,7 @@ export const passthroughWithContentAndAsyncHandler2 = { notStrictEqual(response, newResponse); strictEqual(newResponse.headers.get('foo'), 'bar'); strictEqual(await newResponse.text(), '

hello

'); - } + }, }; export const passthroughWithContentStream = { @@ -136,7 +138,7 @@ export const passthroughWithContentStream = { ]); strictEqual(results[0], '

hello

'); - } + }, }; export const passthroughWithEmptyStream = { @@ -152,47 +154,44 @@ export const passthroughWithEmptyStream = { const response = rewriter.transform(new Response(readable)); const writer = writable.getWriter(); - const results = await Promise.all([ - response.text(), - writer.close(), - ]); + const results = await Promise.all([response.text(), writer.close()]); strictEqual(results[0], ''); - } + }, }; export const asyncElementHandler = { async test() { - const rewriter = new HTMLRewriter() - .on('body', { + const rewriter = new HTMLRewriter().on('body', { async element(e) { await scheduler.wait(10); e.setInnerContent('world'); - } + }, }); const response = rewriter.transform(new Response('hello')); strictEqual(await response.text(), 'world'); - } + }, }; export const asyncCommentHandler = { async test() { - const rewriter = new HTMLRewriter() - .on('body', { + const rewriter = new HTMLRewriter().on('body', { async comments(comment) { await scheduler.wait(10); if (comment.text == 'hello') { comment.text = 'world'; } - } + }, }); - const response = rewriter.transform(new Response('')); + const response = rewriter.transform( + new Response('') + ); strictEqual(await response.text(), ''); - } + }, }; export const objectHandlers = { @@ -249,94 +248,113 @@ export const objectHandlers = { ++this.elementCount; // Exercise all the different methods on Element. - if (token.tagName === "body" - && token.hasAttribute("foo") - && !token.hasAttribute("baz") - && token.getAttribute("foo") === "bar") { - token.removeAttribute("foo"); - token.setAttribute("baz", "qux"); + if ( + token.tagName === 'body' && + token.hasAttribute('foo') && + !token.hasAttribute('baz') && + token.getAttribute('foo') === 'bar' + ) { + token.removeAttribute('foo'); + token.setAttribute('baz', 'qux'); try { - token.tagName = "should throw"; - throw new Error("should have thrown"); + token.tagName = 'should throw'; + throw new Error('should have thrown'); } catch (e) { this.expectedErrors.push(e.message); } - token.tagName = "tail"; + token.tagName = 'tail'; // These will show up in order in the response body. - token.before("<1>"); - token.before("<2>", { html: false }); - token.before("<3>\n", null); - token.before("", { html: true }); + token.before('<1>'); + token.before('<2>', { html: false }); + token.before('<3>\n', null); + token.before('', { html: true }); // These will show up in reverse order in the response body. - token.prepend("hello, ", { html: true }); - token.prepend("<6>\n"); - token.prepend("<5>", { html: false }); - token.prepend("\n<4>", null); + token.prepend('hello, ', { html: true }); + token.prepend('<6>\n'); + token.prepend('<5>', { html: false }); + token.prepend('\n<4>', null); // Iterator tests. this.sawAttributes = JSON.stringify([...token.attributes]); let iterator = token.attributes; - let iteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(iterator)); + let iteratorPrototype = Object.getPrototypeOf( + Object.getPrototypeOf(iterator) + ); if (iteratorPrototype !== arrayIteratorPrototype) { - throw new Error("attributes iterator does not have iterator prototype"); + throw new Error( + 'attributes iterator does not have iterator prototype' + ); } // Run the iterator down until it's done. - for (let [k, v] of iterator) {} + for (let [k, v] of iterator) { + } // .next() should now be idempotent. let result = iterator.next(); let result2 = iterator.next(); - if (result.done !== result2.done || result.value !== result2.value - || !result.done || result.value) { - throw new Error("exhausted iterator should continually return done"); + if ( + result.done !== result2.done || + result.value !== result2.value || + !result.done || + result.value + ) { + throw new Error( + 'exhausted iterator should continually return done' + ); } - } else if (token.tagName === "remove") { - let mode = token.getAttribute("mode"); + } else if (token.tagName === 'remove') { + let mode = token.getAttribute('mode'); if (mode === null) { throw new Error("missing attribute on 'remove' element"); } if (token.removed) { - throw new Error("element should not have been removed yet"); + throw new Error('element should not have been removed yet'); } - if (mode === "all") { + if (mode === 'all') { token.remove(); } else { token.removeAndKeepContent(); } if (!token.removed) { - throw new Error("element should have been removed now"); + throw new Error('element should have been removed now'); + } + } else if (token.tagName === 'after') { + let isHtml = token.getAttribute('is-html'); + let html = isHtml === 'true' ? true : false; + token.after('', { html }); + } else if (token.tagName === 'append') { + let isHtml = token.getAttribute('is-html'); + let html = isHtml === 'true' ? true : false; + token.append('', { html }); + } else if (token.tagName === 'replace') { + let isHtml = token.getAttribute('is-html'); + let html = isHtml === 'true' ? true : false; + token.replace('', { html }); + } else if (token.tagName === 'set-inner-content') { + let isHtml = token.getAttribute('is-html'); + let html = isHtml === 'true' ? true : false; + token.setInnerContent('', { html }); + } else if (token.tagName === 'set-attribute') { + if (!token.hasAttribute('foo')) { + throw new Error('element should have had attribute'); + } + let attr = token.getAttribute('foo'); + if (attr !== '') { + throw new Error('element attribute should have been empty'); + } + token.setAttribute('foo', 'bar'); + + if (token.getAttribute('nonexistent')) { + throw new Error('attribute should not exist'); } - } else if (token.tagName === "after") { - let isHtml = token.getAttribute("is-html"); - let html = isHtml === "true" ? true : false; - token.after("", { html }); - } else if (token.tagName === "append") { - let isHtml = token.getAttribute("is-html"); - let html = isHtml === "true" ? true : false; - token.append("", { html }); - } else if (token.tagName === "replace") { - let isHtml = token.getAttribute("is-html"); - let html = isHtml === "true" ? true : false; - token.replace("", { html }); - } else if (token.tagName === "set-inner-content") { - let isHtml = token.getAttribute("is-html"); - let html = isHtml === "true" ? true : false; - token.setInnerContent("", { html }); - } else if (token.tagName === "set-attribute") { - if (!token.hasAttribute("foo")) { throw new Error("element should have had attribute"); } - let attr = token.getAttribute("foo"); - if (attr !== "") { throw new Error("element attribute should have been empty"); } - token.setAttribute("foo", "bar"); - - if (token.getAttribute("nonexistent")) { throw new Error("attribute should not exist"); } } } @@ -347,9 +365,9 @@ export const objectHandlers = { ++this.commentCount; // Exercise all the different methods on Comment. - if (token.text === " SET TEXT PROPERTY ") { - token.text = " text property has been set "; - } else if (token.text === " REMOVE ME ") { + if (token.text === ' SET TEXT PROPERTY ') { + token.text = ' text property has been set '; + } else if (token.text === ' REMOVE ME ') { if (token.removed) { throw new Error("Shouldn't be removed yet"); } @@ -357,27 +375,27 @@ export const objectHandlers = { token.remove(); if (!token.removed) { - throw new Error("Should be removed now"); + throw new Error('Should be removed now'); } - } else if (token.text === " REPLACE ME ") { + } else if (token.text === ' REPLACE ME ') { if (token.removed) { throw new Error("Shouldn't be removed yet"); } - token.replace("this will get overwritten"); + token.replace('this will get overwritten'); if (!token.removed) { - throw new Error("Should be removed now"); + throw new Error('Should be removed now'); } - token.replace("", null); + token.replace('', null); if (!token.removed) { - throw new Error("Should still be removed"); + throw new Error('Should still be removed'); } - token.before("", { html: true }); + token.before('', { html: true }); } } @@ -388,31 +406,31 @@ export const objectHandlers = { ++this.textCount; if (token.lastInTextNode && token.text.length > 0) { - throw new Error("last text chunk has non-zero length"); + throw new Error('last text chunk has non-zero length'); } else if (!token.lastInTextNode && token.text.length === 0) { - throw new Error("non-last text chunk has zero length"); + throw new Error('non-last text chunk has zero length'); } - if (token.text === "world") { - token.before("again, "); - token.after("..."); + if (token.text === 'world') { + token.before('again, '); + token.after('...'); if (token.removed) { throw new Error("Shouldn't be removed yet"); } - token.replace("this will get overwritten"); + token.replace('this will get overwritten'); if (!token.removed) { - throw new Error("Should be removed now"); + throw new Error('Should be removed now'); } - token.replace("", { html: true }); + token.replace('', { html: true }); if (!token.removed) { - throw new Error("Should still be removed"); + throw new Error('Should still be removed'); } - } else if (token.text === "REMOVE ME\n") { + } else if (token.text === 'REMOVE ME\n') { if (token.removed) { throw new Error("Shouldn't be removed yet"); } @@ -420,7 +438,7 @@ export const objectHandlers = { token.remove(); if (!token.removed) { - throw new Error("Should be removed now"); + throw new Error('Should be removed now'); } } } @@ -430,8 +448,8 @@ export const objectHandlers = { let elementHandlers = new ElementContentHandlers(); const rewriter = new HTMLRewriter() - .onDocument(documentHandlers) - .on("*", elementHandlers); + .onDocument(documentHandlers) + .on('*', elementHandlers); let count = 0; @@ -473,7 +491,7 @@ export const objectHandlers = { } else { controller.close(); } - } + }, }); const response = rewriter.transform(new Response(readable)); @@ -488,32 +506,39 @@ export const objectHandlers = { // Verify that tokens are invalidated outside handler execution scope. throws(() => documentHandlers.deadTokens.doctype.publicId, { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => documentHandlers.deadTokens.comment.text, { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => documentHandlers.deadTokens.text.text, { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => elementHandlers.deadTokens.element.getAttribute('foo'), { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => elementHandlers.deadTokens.attributesIterator.next(), { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => elementHandlers.deadTokens.comment.text, { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); throws(() => elementHandlers.deadTokens.text.text, { - message: 'This content token is no longer valid. Content tokens are only ' + - 'valid during the execution of the relevant content handler.' + message: + 'This content token is no longer valid. Content tokens are only ' + + 'valid during the execution of the relevant content handler.', }); strictEqual(documentHandlers.doctypeCount, 1); @@ -524,85 +549,91 @@ export const objectHandlers = { strictEqual(elementHandlers.commentCount, 3); strictEqual(elementHandlers.textCount, 24); deepStrictEqual(elementHandlers.expectedErrors, [ - 'Parser error: ` ` character is forbidden in the tag name' + 'Parser error: ` ` character is forbidden in the tag name', ]); - } + }, }; export const manualWriting = { async test() { - - const { readable, writable } = new IdentityTransformStream() + const { readable, writable } = new IdentityTransformStream(); const response = new HTMLRewriter() - .on("*", { element(element) { element.prepend("foo ") } }) - .transform(new Response(readable)) + .on('*', { + element(element) { + element.prepend('foo '); + }, + }) + .transform(new Response(readable)); - const writer = writable.getWriter() - const encoder = new TextEncoder() + const writer = writable.getWriter(); + const encoder = new TextEncoder(); // Because this variation uses IdentityTransformStream, we must // initiate the read before doing the writes. const promise = response.text(); - await writer.write(encoder.encode("")) - await writer.write(encoder.encode("bar")) - await writer.write(encoder.encode("")) - await writer.close() + await writer.write(encoder.encode('')); + await writer.write(encoder.encode('bar')); + await writer.write(encoder.encode('')); + await writer.close(); strictEqual(await promise, 'foo bar'); - } + }, }; export const manualWriting2 = { async test() { - - const { readable, writable } = new TransformStream() + const { readable, writable } = new TransformStream(); const response = new HTMLRewriter() - .on("*", { element(element) { element.prepend("foo ") } }) - .transform(new Response(readable)) + .on('*', { + element(element) { + element.prepend('foo '); + }, + }) + .transform(new Response(readable)); - const writer = writable.getWriter() - const encoder = new TextEncoder() + const writer = writable.getWriter(); + const encoder = new TextEncoder(); - await writer.write(encoder.encode("")) - await writer.write(encoder.encode("bar")) - await writer.write(encoder.encode("")) - await writer.close() + await writer.write(encoder.encode('')); + await writer.write(encoder.encode('bar')); + await writer.write(encoder.encode('')); + await writer.close(); // This variation uses the JavaScript TransformStream, so we can // initiate the read after doing the writes. const promise = response.text(); strictEqual(await promise, 'foo bar'); - } + }, }; export const appendOnEnd = { async test() { - const kInput = ''; + const kInput = + ''; const kSuffix = ''; const result = new HTMLRewriter() .onDocument({ end(end) { - end.append(kSuffix, { html: true }) - } + end.append(kSuffix, { html: true }); + }, }) .transform(new Response(kInput)); strictEqual(await result.text(), kInput + kSuffix); - } + }, }; export const interleavedAsyncHandlers = { async test() { - class OneTimeBarrier { constructor(limit) { this.limit = limit; this.current = 0; let resolve; - this.promise = new Promise(r => resolve = r); + this.promise = new Promise((r) => (resolve = r)); this.resolver = resolve; } @@ -619,69 +650,75 @@ export const interleavedAsyncHandlers = { const barrier = new OneTimeBarrier(2); const responses = await Promise.all([ new HTMLRewriter() - .on("body", { + .on('body', { async element(e) { await barrier.wait(); e.setInnerContent('foo bar'); - } + }, }) .transform(new Response('body value')) .text(), new HTMLRewriter() - .on("body", { + .on('body', { async element(e) { await barrier.wait(); e.remove(); - } + }, }) - .transform(new Response('')) + .transform( + new Response('') + ) .arrayBuffer(), - ]) + ]); - const body = responses[0] - const blank = responses[1] + const body = responses[0]; + const blank = responses[1]; const inserted = new HTMLRewriter() - .on("html", { + .on('html', { element(e) { e.append(body, { html: true }); - } + }, }) - .transform(new Response(blank)) + .transform(new Response(blank)); - strictEqual(await inserted.text(), - 'foo bar'); - } + strictEqual( + await inserted.text(), + 'foo bar' + ); + }, }; export const exceptionInHandler = { async test() { const response = new HTMLRewriter() - .on('*', { - text() { - throw new Error('boom'); - } - }).transform(new Response('hello')); + .on('*', { + text() { + throw new Error('boom'); + }, + }) + .transform(new Response('hello')); await rejects(response.text(), { - message: 'boom' + message: 'boom', }); - } + }, }; export const exceptionInAsyncHandler = { async test() { const response = new HTMLRewriter() - .on('*', { - async text() { - throw new Error('boom'); - } - }).transform(new Response('hello')); + .on('*', { + async text() { + throw new Error('boom'); + }, + }) + .transform(new Response('hello')); await rejects(response.text(), { - message: 'boom' + message: 'boom', }); - } + }, }; export const invalidEncoding = { @@ -689,15 +726,18 @@ export const invalidEncoding = { const response = new Response('hello', { headers: { 'content-type': 'text/html; charset=invalid', - } + }, }); - throws(() => { - new HTMLRewriter().on('*', {}).transform(response); - }, { - message: 'Parser error: Unknown character encoding has been provided.' - }); - } + throws( + () => { + new HTMLRewriter().on('*', {}).transform(response); + }, + { + message: 'Parser error: Unknown character encoding has been provided.', + } + ); + }, }; export const exceptionPropagation = { @@ -713,9 +753,9 @@ export const exceptionPropagation = { await writer.write(enc.encode('test')); rejects(writer.write(enc.encode('test')), { - message: 'boom' + message: 'boom', }); - } + }, }; export const sameToken = { @@ -724,24 +764,24 @@ export const sameToken = { let element; const r = new HTMLRewriter() - .on("*", { + .on('*', { element(e) { element = e; strictEqual(e.hi, undefined); - e.hi = "test"; - strictEqual(e.hi, "test"); + e.hi = 'test'; + strictEqual(e.hi, 'test'); - e.hi = "hi"; + e.hi = 'hi'; e.obj = obj; - e.replace("foo"); - } + e.replace('foo'); + }, }) - .on("img", { + .on('img', { element(e) { notStrictEqual(e, element); - notStrictEqual(e.hi, "hi"); + notStrictEqual(e.hi, 'hi'); notStrictEqual(e.obj, obj); // The HTMLRewriter creates a fresh new Element/Doctype/Text @@ -749,13 +789,13 @@ export const sameToken = { // assigned it in the first handler. // See https://jira.cfdata.org/browse/EW-2200. e.replace(e.hi); - } + }, }) - .transform(new Response("")) + .transform(new Response('')) .text(); await r; - } + }, }; export const svgNamespace = { @@ -765,15 +805,15 @@ export const svgNamespace = { `); let namespace; - await (new HTMLRewriter) - .on("a", { + await new HTMLRewriter() + .on('a', { element(e) { namespace = e.namespaceURI; - } + }, }) .transform(response) .text(); - strictEqual(namespace, "http://www.w3.org/2000/svg"); - } + strictEqual(namespace, 'http://www.w3.org/2000/svg'); + }, }; diff --git a/src/workerd/api/tests/js-rpc-flag.js b/src/workerd/api/tests/js-rpc-flag.js index 6c51d20f230..b2b6782820e 100644 --- a/src/workerd/api/tests/js-rpc-flag.js +++ b/src/workerd/api/tests/js-rpc-flag.js @@ -14,19 +14,18 @@ export class DurableObjectExample { } fetch(req) { - return new Response(req.method + " " + req.url); + return new Response(req.method + ' ' + req.url); } } export default { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("foo"); + let id = env.ns.idFromName('foo'); let obj = env.ns.get(id); assert.strictEqual(await obj.foo(), 123); // Test that the object has the old helper get() method that wraps fetch(). This is deprecated, // but enabled because this test's compat date is before the date when these went away. - assert.strictEqual(await obj.get("http://foo"), "GET http://foo"); - } -} - + assert.strictEqual(await obj.get('http://foo'), 'GET http://foo'); + }, +}; diff --git a/src/workerd/api/tests/js-rpc-test.js b/src/workerd/api/tests/js-rpc-test.js index a97422190d2..b1fffc51297 100644 --- a/src/workerd/api/tests/js-rpc-test.js +++ b/src/workerd/api/tests/js-rpc-test.js @@ -1,5 +1,10 @@ import assert from 'node:assert'; -import {WorkerEntrypoint,DurableObject,RpcStub,RpcTarget} from 'cloudflare:workers'; +import { + WorkerEntrypoint, + DurableObject, + RpcStub, + RpcTarget, +} from 'cloudflare:workers'; class MyCounter extends RpcTarget { constructor(i = 0) { @@ -15,7 +20,9 @@ class MyCounter extends RpcTarget { disposed = false; #disposedResolver; - #onDisposedPromise = new Promise(resolve => this.#disposedResolver = resolve); + #onDisposedPromise = new Promise( + (resolve) => (this.#disposedResolver = resolve) + ); [Symbol.dispose]() { this.disposed = true; @@ -26,8 +33,8 @@ class MyCounter extends RpcTarget { return Promise.race([ this.#onDisposedPromise, scheduler.wait(1000).then(() => { - throw new Error("timed out waiting for disposal"); - }) + throw new Error('timed out waiting for disposal'); + }), ]); } @@ -43,19 +50,21 @@ class NonRpcClass { } get bar() { return { - baz() { return 456; } - } + baz() { + return 456; + }, + }; } -}; +} export let nonClass = { async noArgs(x, env, ctx) { - assert.strictEqual(typeof ctx.waitUntil, "function"); - return (x === undefined) ? (env.twelve + 1) : "param not undefined?"; + assert.strictEqual(typeof ctx.waitUntil, 'function'); + return x === undefined ? env.twelve + 1 : 'param not undefined?'; }, async oneArg(i, env, ctx) { - assert.strictEqual(typeof ctx.waitUntil, "function"); + assert.strictEqual(typeof ctx.waitUntil, 'function'); return env.twelve * i; }, @@ -68,26 +77,26 @@ export let nonClass = { }, async twoArgs(i, j, env, ctx) { - assert.strictEqual(typeof ctx.waitUntil, "function"); + assert.strictEqual(typeof ctx.waitUntil, 'function'); return i * j + env.twelve; }, async fetch(req, env, ctx) { // This is used in the stream test to fetch some gziped data. - if (req.url.endsWith("/gzip")) { - return new Response("this text was gzipped", { + if (req.url.endsWith('/gzip')) { + return new Response('this text was gzipped', { headers: { - "Content-Encoding": "gzip" - } + 'Content-Encoding': 'gzip', + }, }); - } else if (req.url.endsWith("/stream-from-rpc")) { + } else if (req.url.endsWith('/stream-from-rpc')) { let stream = await env.MyService.returnReadableStream(); return new Response(stream); } else { - throw new Error("unknown route"); + throw new Error('unknown route'); } - } -} + }, +}; // Globals used to test passing RPC promises or properties across I/O contexts (which is expected // to fail). @@ -105,8 +114,8 @@ export class MyService extends WorkerEntrypoint { // This shouldn't be callable! this.instanceMethod = () => { - return "nope"; - } + return 'nope'; + }; this.instanceObject = { func: (a) => a * 5, @@ -114,7 +123,7 @@ export class MyService extends WorkerEntrypoint { } async noArgsMethod(x) { - return (x === undefined) ? (this.env.twelve + 1) : "param not undefined?"; + return x === undefined ? this.env.twelve + 1 : 'param not undefined?'; } async oneArgMethod(i) { @@ -134,21 +143,25 @@ export class MyService extends WorkerEntrypoint { } async getAnObject(i) { - return {foo: 123 + i, counter: new MyCounter(i)}; + return { foo: 123 + i, counter: new MyCounter(i) }; } async fetch(req, x) { assert.strictEqual(x, undefined); - return new Response("method = " + req.method + ", url = " + req.url); + return new Response('method = ' + req.method + ', url = ' + req.url); } // Define a property to test behavior of property accessors. - get nonFunctionProperty() { return {foo: 123}; } + get nonFunctionProperty() { + return { foo: 123 }; + } - get functionProperty() { return (a, b) => a - b; } + get functionProperty() { + return (a, b) => a - b; + } get objectProperty() { - let nullPrototype = {foo: 123}; + let nullPrototype = { foo: 123 }; nullPrototype.__proto__ = null; return { @@ -159,7 +172,7 @@ export class MyService extends WorkerEntrypoint { counter5: new MyCounter(5), nonRpc: new NonRpcClass(), nullPrototype, - someText: "hello", + someText: 'hello', }; } @@ -168,15 +181,15 @@ export class MyService extends WorkerEntrypoint { } get rejectingPromiseProperty() { - return Promise.reject(new Error("REJECTED")); + return Promise.reject(new Error('REJECTED')); } get throwingProperty() { - throw new Error("PROPERTY THREW"); + throw new Error('PROPERTY THREW'); } throwingMethod() { - throw new Error("METHOD THREW"); + throw new Error('METHOD THREW'); } async tryUseGlobalRpcPromise() { @@ -187,11 +200,11 @@ export class MyService extends WorkerEntrypoint { } async getNonRpcClass() { - return {obj: new NonRpcClass()}; + return { obj: new NonRpcClass() }; } async getNullPrototypeObject() { - let obj = {foo: 123}; + let obj = { foo: 123 }; obj.__proto__ = null; return obj; } @@ -206,7 +219,7 @@ export class MyService extends WorkerEntrypoint { return callback(); } getNestedRpcPromise(callback) { - return {value: callback()}; + return { value: callback() }; } getRemoteNestedRpcPromise(callback) { // Use a function as a cheap way to return a JsRpcStub that has a remote property `value` which @@ -219,7 +232,7 @@ export class MyService extends WorkerEntrypoint { return callback.foo; } getNestedRpcProperty(callback) { - return {value: callback.foo}; + return { value: callback.foo }; } getRemoteNestedRpcProperty(callback) { // Use a function as a cheap way to return a JsRpcStub that has a remote property `value` which @@ -256,7 +269,7 @@ export class MyService extends WorkerEntrypoint { return { count, - counter: counter.dup(), // need to dup() for return + counter: counter.dup(), // need to dup() for return async incrementOriginal(n) { // This will fail because after the call ends, the counter stub is disposed. return await counter.increment(n); @@ -267,7 +280,7 @@ export class MyService extends WorkerEntrypoint { }, [Symbol.dispose]() { counterDup[Symbol.dispose](); - } + }, }; } @@ -280,16 +293,18 @@ export class MyService extends WorkerEntrypoint { // Return something that contains stubs, holding the context open. return { noop() {}, - abort() { ctx.abort(new RangeError("foo bar abort reason")); } + abort() { + ctx.abort(new RangeError('foo bar abort reason')); + }, }; } async writeToStream(stream) { let writer = stream.getWriter(); let enc = new TextEncoder(); - await writer.write(enc.encode("foo, ")); - await writer.write(enc.encode("bar, ")); - await writer.write(enc.encode("baz!")); + await writer.write(enc.encode('foo, ')); + await writer.write(enc.encode('bar, ')); + await writer.write(enc.encode('baz!')); await writer.close(); } @@ -302,7 +317,7 @@ export class MyService extends WorkerEntrypoint { let writer = stream.getWriter(); let enc = new TextEncoder(); for (;;) { - await writer.write(enc.encode("foo, ")); + await writer.write(enc.encode('foo, ')); } } @@ -348,37 +363,37 @@ export class MyService extends WorkerEntrypoint { async returnHeaders() { let result = new Headers(); - result.append("foo", "bar"); - result.append("Set-Cookie", "abc"); - result.append("set-cookie", "def"); - result.append("corge", "!@#"); - result.append("Content-Length", "123"); + result.append('foo', 'bar'); + result.append('Set-Cookie', 'abc'); + result.append('set-cookie', 'def'); + result.append('corge', '!@#'); + result.append('Content-Length', '123'); return result; } async returnRequest() { - return new Request("http://my-url.com", { - method: "PUT", + return new Request('http://my-url.com', { + method: 'PUT', headers: { - "Accept-Encoding": "bazzip", - "Foo": "Bar" + 'Accept-Encoding': 'bazzip', + Foo: 'Bar', }, - redirect: "manual", - body: "Hello every body!", + redirect: 'manual', + body: 'Hello every body!', cf: { abc: 123, - hello: "goodbye", - } + hello: 'goodbye', + }, }); } async returnResponse() { - return new Response("Response body!", { + return new Response('Response body!', { status: 404, headers: { - "Content-Type": "abc" + 'Content-Type': 'abc', }, - cf: {foo: 123, bar: "def"}, + cf: { foo: 123, bar: 'def' }, }); } @@ -387,12 +402,16 @@ export class MyService extends WorkerEntrypoint { // later on. We'll perform a cross-context wait to verify that the waitUntil task actually // completes and resolves the promise. let resolve; - globalWaitUntilPromise = new Promise(r => { resolve = r; }); + globalWaitUntilPromise = new Promise((r) => { + resolve = r; + }); - this.ctx.waitUntil((async () => { - await scheduler.wait(100); - resolve(); - })()); + this.ctx.waitUntil( + (async () => { + await scheduler.wait(100); + resolve(); + })() + ); } } @@ -414,7 +433,7 @@ export class MyActor extends DurableObject { export class ActorNoExtends { async fetch(req) { - return new Response("from ActorNoExtends"); + return new Response('from ActorNoExtends'); } // This can't be called! @@ -426,7 +445,7 @@ export class ActorNoExtends { export default class DefaultService extends WorkerEntrypoint { async fetch(req) { // Test this.env here just to prove omitting the constructor entirely works. - return new Response("default service " + this.env.twelve); + return new Response('default service ' + this.env.twelve); } } @@ -437,31 +456,31 @@ export let basicServiceBinding = { assert.strictEqual(await env.self.oneArgOmitCtx(3), 37); assert.strictEqual(await env.self.oneArgOmitEnvCtx(3), 6); await assert.rejects(() => env.self.twoArgs(123, 2), { - name: "TypeError", + name: 'TypeError', message: - "Cannot call handler function \"twoArgs\" over RPC because it has the wrong " + - "number of arguments. A simple function handler can only be called over RPC if it has " + - "exactly the arguments (arg, env, ctx), where only the first argument comes from the " + - "client. To support multi-argument RPC functions, use class-based syntax (extending " + - "WorkerEntrypoint) instead." + 'Cannot call handler function "twoArgs" over RPC because it has the wrong ' + + 'number of arguments. A simple function handler can only be called over RPC if it has ' + + 'exactly the arguments (arg, env, ctx), where only the first argument comes from the ' + + 'client. To support multi-argument RPC functions, use class-based syntax (extending ' + + 'WorkerEntrypoint) instead.', }); await assert.rejects(() => env.self.noArgs(), { - name: "TypeError", + name: 'TypeError', message: - "Attempted to call RPC function \"noArgs\" with the wrong number of arguments. " + - "When calling a top-level handler function that is not declared as part of a class, you " + - "must always send exactly one argument. In order to support variable numbers of " + - "arguments, the server must use class-based syntax (extending WorkerEntrypoint) " + - "instead." + 'Attempted to call RPC function "noArgs" with the wrong number of arguments. ' + + 'When calling a top-level handler function that is not declared as part of a class, you ' + + 'must always send exactly one argument. In order to support variable numbers of ' + + 'arguments, the server must use class-based syntax (extending WorkerEntrypoint) ' + + 'instead.', }); await assert.rejects(() => env.self.oneArg(1, 2), { - name: "TypeError", + name: 'TypeError', message: - "Attempted to call RPC function \"oneArg\" with the wrong number of arguments. " + - "When calling a top-level handler function that is not declared as part of a class, you " + - "must always send exactly one argument. In order to support variable numbers of " + - "arguments, the server must use class-based syntax (extending WorkerEntrypoint) " + - "instead." + 'Attempted to call RPC function "oneArg" with the wrong number of arguments. ' + + 'When calling a top-level handler function that is not declared as part of a class, you ' + + 'must always send exactly one argument. In order to support variable numbers of ' + + 'arguments, the server must use class-based syntax (extending WorkerEntrypoint) ' + + 'instead.', }); // If we restore multi-arg support, remove the `rejects` checks above and un-comment these: @@ -469,7 +488,7 @@ export let basicServiceBinding = { // assert.strictEqual(await env.self.twoArgs(123, 2), 258); // assert.strictEqual(await env.self.twoArgs(123, 2, "foo", "bar", "baz"), 258); }, -} +}; export let extendingEntrypointClasses = { async test(controller, env, ctx) { @@ -477,7 +496,7 @@ export let extendingEntrypointClasses = { let svc = new MyService(ctx, env); assert.equal(svc instanceof WorkerEntrypoint, true); }, -} +}; export let namedServiceBinding = { async test(controller, env, ctx) { @@ -490,12 +509,21 @@ export let namedServiceBinding = { // Members of an object-typed property can be invoked. assert.strictEqual(await env.MyService.objectProperty.func(6, 4), 24); - assert.strictEqual(await env.MyService.objectProperty.deeper.deepFunc(6, 3), 2); - assert.strictEqual(await env.MyService.objectProperty.counter5.increment(3), 8); + assert.strictEqual( + await env.MyService.objectProperty.deeper.deepFunc(6, 3), + 2 + ); + assert.strictEqual( + await env.MyService.objectProperty.counter5.increment(3), + 8 + ); // Awaiting a property itself gets the value. - assert.strictEqual(JSON.stringify(await env.MyService.nonFunctionProperty), '{"foo":123}'); - assert.strictEqual(await env.MyService.objectProperty.someText, "hello"); + assert.strictEqual( + JSON.stringify(await env.MyService.nonFunctionProperty), + '{"foo":123}' + ); + assert.strictEqual(await env.MyService.objectProperty.someText, 'hello'); { let counter = await env.MyService.objectProperty.counter5; assert.strictEqual(await counter.increment(3), 8); @@ -522,179 +550,203 @@ export let namedServiceBinding = { assert.strictEqual(await env.MyService.promiseProperty, 123); let sawFinally = false; - assert.strictEqual(await env.MyService.promiseProperty - .finally(() => {sawFinally = true;}), 123); + assert.strictEqual( + await env.MyService.promiseProperty.finally(() => { + sawFinally = true; + }), + 123 + ); assert.strictEqual(sawFinally, true); // `fetch()` is special, the params get converted into a Request. - let resp = await env.MyService.fetch("http://foo/", {method: "POST"}); - assert.strictEqual(await resp.text(), "method = POST, url = http://foo/"); + let resp = await env.MyService.fetch('http://foo/', { method: 'POST' }); + assert.strictEqual(await resp.text(), 'method = POST, url = http://foo/'); await assert.rejects(() => env.MyService.instanceMethod(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"instanceMethod\"." + name: 'TypeError', + message: + 'The RPC receiver does not implement the method "instanceMethod".', }); await assert.rejects(() => env.MyService.instanceObject.func(3), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"instanceObject\"." + name: 'TypeError', + message: + 'The RPC receiver does not implement the method "instanceObject".', }); await assert.rejects(() => env.MyService.instanceObject, { - name: "TypeError", - message: "The RPC receiver does not implement the method \"instanceObject\"." + name: 'TypeError', + message: + 'The RPC receiver does not implement the method "instanceObject".', }); await assert.rejects(() => env.MyService.throwingProperty, { - name: "Error", - message: "PROPERTY THREW" + name: 'Error', + message: 'PROPERTY THREW', }); await assert.rejects(() => env.MyService.throwingMethod(), { - name: "Error", - message: "METHOD THREW" + name: 'Error', + message: 'METHOD THREW', }); await assert.rejects(() => env.MyService.rejectingPromiseProperty, { - name: "Error", - message: "REJECTED" + name: 'Error', + message: 'REJECTED', }); - assert.strictEqual(await env.MyService.rejectingPromiseProperty.catch(err => { - assert.strictEqual(err.message, "REJECTED"); - return 234; - }), 234); - assert.strictEqual(await env.MyService.rejectingPromiseProperty.then(() => 432, err => { - assert.strictEqual(err.message, "REJECTED"); - return 234; - }), 234); - - let getByName = name => { + assert.strictEqual( + await env.MyService.rejectingPromiseProperty.catch((err) => { + assert.strictEqual(err.message, 'REJECTED'); + return 234; + }), + 234 + ); + assert.strictEqual( + await env.MyService.rejectingPromiseProperty.then( + () => 432, + (err) => { + assert.strictEqual(err.message, 'REJECTED'); + return 234; + } + ), + 234 + ); + + let getByName = (name) => { return env.MyService.getRpcMethodForTestOnly(name); }; // Check getRpcMethodForTestOnly() actually works. - assert.strictEqual(await getByName("twoArgsMethod")(2, 3), 18); + assert.strictEqual(await getByName('twoArgsMethod')(2, 3), 18); // Check we cannot call reserved methods. - await assert.rejects(() => getByName("constructor")(), { - name: "TypeError", - message: "'constructor' is a reserved method and cannot be called over RPC." + await assert.rejects(() => getByName('constructor')(), { + name: 'TypeError', + message: + "'constructor' is a reserved method and cannot be called over RPC.", }); - await assert.rejects(() => getByName("fetch")(), { - name: "TypeError", - message: "'fetch' is a reserved method and cannot be called over RPC." + await assert.rejects(() => getByName('fetch')(), { + name: 'TypeError', + message: "'fetch' is a reserved method and cannot be called over RPC.", }); // Check we cannot call methods of Object. - await assert.rejects(() => getByName("toString")(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"toString\"." + await assert.rejects(() => getByName('toString')(), { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "toString".', }); - await assert.rejects(() => getByName("hasOwnProperty")(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"hasOwnProperty\"." + await assert.rejects(() => getByName('hasOwnProperty')(), { + name: 'TypeError', + message: + 'The RPC receiver does not implement the method "hasOwnProperty".', }); // Check we cannot access `env` or `ctx`. - await assert.rejects(() => getByName("env")(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"env\"." + await assert.rejects(() => getByName('env')(), { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "env".', }); - await assert.rejects(() => getByName("ctx")(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"ctx\"." + await assert.rejects(() => getByName('ctx')(), { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "ctx".', }); // Check what happens if we access something that's actually declared as a property on the // class. The difference in error message proves to us that `env` and `ctx` weren't visible at // all, which is what we want. - await assert.rejects(() => getByName("nonFunctionProperty")(), { - name: "TypeError", - message: "\"nonFunctionProperty\" is not a function." + await assert.rejects(() => getByName('nonFunctionProperty')(), { + name: 'TypeError', + message: '"nonFunctionProperty" is not a function.', }); - await assert.rejects(() => getByName("nonFunctionProperty").foo(), { - name: "TypeError", - message: "\"nonFunctionProperty.foo\" is not a function." + await assert.rejects(() => getByName('nonFunctionProperty').foo(), { + name: 'TypeError', + message: '"nonFunctionProperty.foo" is not a function.', }); // Check that we can't access contents of a property that is a class but not derived from // RpcTarget. await assert.rejects(() => env.MyService.objectProperty.nonRpc.foo(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"nonRpc\"." + name: 'TypeError', + message: 'The RPC receiver does not implement the method "nonRpc".', }); await assert.rejects(() => env.MyService.objectProperty.nonRpc.bar.baz(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"nonRpc\"." + name: 'TypeError', + message: 'The RPC receiver does not implement the method "nonRpc".', }); await assert.rejects(() => env.MyService.objectProperty.nullPrototype.foo, { - name: "TypeError", - message: "The RPC receiver does not implement the method \"nullPrototype\"." + name: 'TypeError', + message: + 'The RPC receiver does not implement the method "nullPrototype".', }); // Extra-paranoid check that we can't access methods on env or ctx. - await assert.rejects(() => env.MyService.objectProperty.env.MyService.noArgsMethod(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"env\"." - }); + await assert.rejects( + () => env.MyService.objectProperty.env.MyService.noArgsMethod(), + { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "env".', + } + ); await assert.rejects(() => env.MyService.objectProperty.ctx.waitUntil(), { - name: "TypeError", - message: "The RPC receiver does not implement the method \"ctx\"." + name: 'TypeError', + message: 'The RPC receiver does not implement the method "ctx".', }); // Can't serialize instances of classes that aren't derived from RpcTarget. await assert.rejects(() => env.MyService.getNonRpcClass(), { - name: "DataCloneError", - message: 'Could not serialize object of type "NonRpcClass". This type does not support ' + - 'serialization.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "NonRpcClass". This type does not support ' + + 'serialization.', }); await assert.rejects(() => env.MyService.getNullPrototypeObject(), { - name: "DataCloneError", - message: 'Could not serialize object of type "Object". This type does not support ' + - 'serialization.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "Object". This type does not support ' + + 'serialization.', }); }, -} +}; export let namedActorBinding = { async test(controller, env, ctx) { - let id = env.MyActor.idFromName("foo"); + let id = env.MyActor.idFromName('foo'); let stub = env.MyActor.get(id); assert.strictEqual(await stub.increment(5), 5); assert.strictEqual(await stub.increment(2), 7); assert.strictEqual(await stub.increment(8), 15); }, -} +}; // Test that if the actor class doesn't extend `DurableObject`, we don't allow RPC. export let actorWithoutExtendsRejectsRpc = { async test(controller, env, ctx) { - let id = env.ActorNoExtends.idFromName("foo"); + let id = env.ActorNoExtends.idFromName('foo'); let stub = env.ActorNoExtends.get(id); // fetch() works. - let resp = await stub.fetch("http://foo"); - assert.strictEqual(await resp.text(), "from ActorNoExtends"); + let resp = await stub.fetch('http://foo'); + assert.strictEqual(await resp.text(), 'from ActorNoExtends'); // RPC does not. await assert.rejects(() => stub.foo(), { - name: "TypeError", + name: 'TypeError', message: - "The receiving Durable Object does not support RPC, because its class was not declared " + - "with `extends DurableObject`. In order to enable RPC, make sure your class " + - "extends the special class `DurableObject`, which can be imported from the module " + - "\"cloudflare:workers\"." + 'The receiving Durable Object does not support RPC, because its class was not declared ' + + 'with `extends DurableObject`. In order to enable RPC, make sure your class ' + + 'extends the special class `DurableObject`, which can be imported from the module ' + + '"cloudflare:workers".', }); }, -} +}; // Test calling the default export when it is a class. export let defaultExportClass = { async test(controller, env, ctx) { - let resp = await env.defaultExport.fetch("http://foo"); - assert.strictEqual(await resp.text(), "default service 12"); + let resp = await env.defaultExport.fetch('http://foo'); + assert.strictEqual(await resp.text(), 'default service 12'); }, -} +}; export let loopbackJsRpcTarget = { async test(controller, env, ctx) { @@ -703,20 +755,20 @@ export let loopbackJsRpcTarget = { assert.strictEqual(await stub.increment(5), 9); assert.strictEqual(await stub.increment(7), 16); - assert.strictEqual(await stub.fetch(true, 123, "baz"), "16 true 123 baz"); + assert.strictEqual(await stub.fetch(true, 123, 'baz'), '16 true 123 baz'); assert.strictEqual(counter.disposed, false); stub[Symbol.dispose](); await assert.rejects(stub.increment(2), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); await counter.onDisposed(); assert.strictEqual(counter.disposed, true); }, -} +}; export let sendStubOverRpc = { async test(controller, env, ctx) { @@ -726,13 +778,13 @@ export let sendStubOverRpc = { assert.strictEqual(await env.MyService.incrementCounter(stub, 5), 9); await assert.rejects(() => stub.increment(7), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); assert.strictEqual(await stubDup.increment(7), 16); }, -} +}; export let receiveStubOverRpc = { async test(controller, env, ctx) { @@ -744,29 +796,35 @@ export let receiveStubOverRpc = { let promise1 = stub.increment(6); let promise2 = stub.increment(4); let promise3 = stub.increment(3); - assert.deepEqual(await Promise.all([promise1, promise2, promise3]), [15, 19, 22]); + assert.deepEqual( + await Promise.all([promise1, promise2, promise3]), + [15, 19, 22] + ); }, -} +}; export let promisePipelining = { async test(controller, env, ctx) { assert.strictEqual(await env.MyService.makeCounter(12).increment(3), 15); assert.strictEqual(await env.MyService.getAnObject(5).foo, 128); - assert.strictEqual(await env.MyService.getAnObject(5).counter.increment(7), 12); + assert.strictEqual( + await env.MyService.getAnObject(5).counter.increment(7), + 12 + ); }, -} +}; export let disposal = { async test(controller, env, ctx) { // Call function that returns plain stub. Dispose it. { - let counter = await env.MyService.makeCounter(12) + let counter = await env.MyService.makeCounter(12); assert.strictEqual(await counter.increment(3), 15); counter[Symbol.dispose](); await assert.rejects(counter.increment(2), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); } @@ -778,8 +836,8 @@ export let disposal = { obj[Symbol.dispose](); await assert.rejects(obj.counter.increment(2), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); } @@ -801,8 +859,8 @@ export let disposal = { // But after the call, the stub is disposed. await assert.rejects(obj.incrementOriginal(), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); // The duplicate we created in the call still works though. @@ -814,12 +872,12 @@ export let disposal = { // But of course, disposing the return value overall breaks everything. obj[Symbol.dispose](); await assert.rejects(obj.counter.increment(2), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); await assert.rejects(obj.incrementDup(7), { - name: "Error", - message: "RPC stub used after being disposed." + name: 'Error', + message: 'RPC stub used after being disposed.', }); await counter.onDisposed(); @@ -845,15 +903,15 @@ export let disposal = { // If we abort the server's I/O context, though, then the counter is disposed. await assert.rejects(obj.abort(), { - name: "RangeError", - message: "foo bar abort reason" + name: 'RangeError', + message: 'foo bar abort reason', }); await counter.onDisposed(); assert.strictEqual(counter.disposed, true); } }, -} +}; export let crossContextSharingDoesntWork = { async test(controller, env, ctx) { @@ -871,16 +929,19 @@ export let crossContextSharingDoesntWork = { // tied to an I/O context. Awaiting the property actually initiates a new RPC session from // whatever context performed teh await. globalRpcPromise = env.MyService.nonFunctionProperty; - assert.strictEqual(JSON.stringify(await env.MyService.tryUseGlobalRpcPromise()), '{"foo":123}'); + assert.strictEqual( + JSON.stringify(await env.MyService.tryUseGlobalRpcPromise()), + '{"foo":123}' + ); // OK, now let's look at cases that do NOT work. These all produce the same error. let expectedError = { - name: "Error", + name: 'Error', message: - "Cannot perform I/O on behalf of a different request. I/O objects (such as streams, " + - "request/response bodies, and others) created in the context of one request handler " + - "cannot be accessed from a different request's handler. This is a limitation of " + - "Cloudflare Workers which allows us to improve overall performance." + 'Cannot perform I/O on behalf of a different request. I/O objects (such as streams, ' + + 'request/response bodies, and others) created in the context of one request handler ' + + "cannot be accessed from a different request's handler. This is a limitation of " + + 'Cloudflare Workers which allows us to improve overall performance.', }; // A promise which resolves to a value that contains a stub. The stub cannot be used from a @@ -892,23 +953,23 @@ export let crossContextSharingDoesntWork = { globalRpcPromise = env.MyService.makeCounter(12); await assert.rejects(() => env.MyService.tryUseGlobalRpcPromise(), { - name: "Error", + name: 'Error', message: - "Cannot perform I/O on behalf of a different request. I/O objects (such as streams, " + - "request/response bodies, and others) created in the context of one request handler " + - "cannot be accessed from a different request's handler. This is a limitation of " + - "Cloudflare Workers which allows us to improve overall performance. (I/O type: Client)" + 'Cannot perform I/O on behalf of a different request. I/O objects (such as streams, ' + + 'request/response bodies, and others) created in the context of one request handler ' + + "cannot be accessed from a different request's handler. This is a limitation of " + + 'Cloudflare Workers which allows us to improve overall performance. (I/O type: Client)', }); // Pipelining on someone else's promise straight-up doesn't work. await assert.rejects(() => env.MyService.tryUseGlobalRpcPromisePipeline(), { - name: "Error", + name: 'Error', message: - "Cannot perform I/O on behalf of a different request. I/O objects (such as streams, " + - "request/response bodies, and others) created in the context of one request handler " + - "cannot be accessed from a different request's handler. This is a limitation of " + - "Cloudflare Workers which allows us to improve overall performance. " + - "(I/O type: JsRpcPromise)" + 'Cannot perform I/O on behalf of a different request. I/O objects (such as streams, ' + + 'request/response bodies, and others) created in the context of one request handler ' + + "cannot be accessed from a different request's handler. This is a limitation of " + + 'Cloudflare Workers which allows us to improve overall performance. ' + + '(I/O type: JsRpcPromise)', }); // Now let's try accessing a JsRpcProperty, where the property is NOT a direct property of a @@ -918,25 +979,25 @@ export let crossContextSharingDoesntWork = { globalRpcPromise = env.MyService.getAnObject(5).counter; await assert.rejects(() => env.MyService.tryUseGlobalRpcPromise(), { - name: "Error", + name: 'Error', message: - "Cannot perform I/O on behalf of a different request. I/O objects (such as streams, " + - "request/response bodies, and others) created in the context of one request handler " + - "cannot be accessed from a different request's handler. This is a limitation of " + - "Cloudflare Workers which allows us to improve overall performance. (I/O type: Pipeline)" + 'Cannot perform I/O on behalf of a different request. I/O objects (such as streams, ' + + 'request/response bodies, and others) created in the context of one request handler ' + + "cannot be accessed from a different request's handler. This is a limitation of " + + 'Cloudflare Workers which allows us to improve overall performance. (I/O type: Pipeline)', }); await assert.rejects(() => env.MyService.tryUseGlobalRpcPromisePipeline(), { - name: "Error", + name: 'Error', message: - "Cannot perform I/O on behalf of a different request. I/O objects (such as streams, " + - "request/response bodies, and others) created in the context of one request handler " + - "cannot be accessed from a different request's handler. This is a limitation of " + - "Cloudflare Workers which allows us to improve overall performance. " + - "(I/O type: JsRpcPromise)" + 'Cannot perform I/O on behalf of a different request. I/O objects (such as streams, ' + + 'request/response bodies, and others) created in the context of one request handler ' + + "cannot be accessed from a different request's handler. This is a limitation of " + + 'Cloudflare Workers which allows us to improve overall performance. ' + + '(I/O type: JsRpcPromise)', }); }, -} +}; export let waitUntilWorks = { async test(controller, env, ctx) { @@ -945,8 +1006,8 @@ export let waitUntilWorks = { assert.strictEqual(globalWaitUntilPromise instanceof Promise, true); await globalWaitUntilPromise; - } -} + }, +}; function stripDispose(obj) { assert.deepEqual(!!obj[Symbol.dispose], true); @@ -959,76 +1020,107 @@ export let serializeRpcPromiseOrProprety = { // What happens if we actually try to serialize a JsRpcPromise or JsRpcProperty? Let's make // sure these aren't, for instance, treated as functions because they are callable. - let func = () => {return {x: 123};}; - func.foo = {x: 456}; + let func = () => { + return { x: 123 }; + }; + func.foo = { x: 456 }; // If we directly return returning a JsRpcPromise, the system automatically awaits it on the // server side because it's a thenable. - assert.deepEqual(stripDispose(await env.MyService.getRpcPromise(func)), {x: 123}) + assert.deepEqual(stripDispose(await env.MyService.getRpcPromise(func)), { + x: 123, + }); // Pipelining also works. - assert.strictEqual(await env.MyService.getRpcPromise(func).x, 123) + assert.strictEqual(await env.MyService.getRpcPromise(func).x, 123); // If a JsRpcPromise appears somewhere in the serialization tree, it'll just fail serialization. // NOTE: We could choose to make this work later. await assert.rejects(() => env.MyService.getNestedRpcPromise(func), { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcPromise". This type does not support ' + - 'serialization.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcPromise". This type does not support ' + + 'serialization.', }); await assert.rejects(() => env.MyService.getNestedRpcPromise(func).value, { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcPromise". This type does not support ' + - 'serialization.' - }); - await assert.rejects(() => env.MyService.getNestedRpcPromise(func).value.x, { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcPromise". This type does not support ' + - 'serialization.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcPromise". This type does not support ' + + 'serialization.', }); + await assert.rejects( + () => env.MyService.getNestedRpcPromise(func).value.x, + { + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcPromise". This type does not support ' + + 'serialization.', + } + ); // Things get a little weird when we return a stub which itself has properties that reflect // our RPC promise. If we await fetch the JsRpcPromise itself, this works, again because // somewhere along the line V8 says "oh look a thenable" and awaits it, before it can be // subject to serialization. That's fine. - assert.deepEqual(stripDispose(await env.MyService.getRemoteNestedRpcPromise(func).value), - {x: 123}); - await assert.rejects(() => env.MyService.getRemoteNestedRpcPromise(func).value.x, { - name: "TypeError", - message: 'The RPC receiver does not implement the method "value".' - }); + assert.deepEqual( + stripDispose(await env.MyService.getRemoteNestedRpcPromise(func).value), + { x: 123 } + ); + await assert.rejects( + () => env.MyService.getRemoteNestedRpcPromise(func).value.x, + { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "value".', + } + ); // The story is similar for a JsRpcProperty -- though the implementation details differ. - assert.deepEqual(stripDispose(await env.MyService.getRpcProperty(func)), {x: 456}) - assert.strictEqual(await env.MyService.getRpcProperty(func).x, 456) + assert.deepEqual(stripDispose(await env.MyService.getRpcProperty(func)), { + x: 456, + }); + assert.strictEqual(await env.MyService.getRpcProperty(func).x, 456); await assert.rejects(() => env.MyService.getNestedRpcProperty(func), { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcProperty". This type does not support ' + - 'serialization.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcProperty". This type does not support ' + + 'serialization.', }); await assert.rejects(() => env.MyService.getNestedRpcProperty(func).value, { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcProperty". This type does not support ' + - 'serialization.' - }); - await assert.rejects(() => env.MyService.getNestedRpcProperty(func).value.x, { - name: "DataCloneError", - message: 'Could not serialize object of type "RpcProperty". This type does not support ' + - 'serialization.' - }); - - assert.deepEqual(stripDispose(await env.MyService.getRemoteNestedRpcProperty(func).value), - {x: 456}); - await assert.rejects(() => env.MyService.getRemoteNestedRpcProperty(func).value.x, { - name: "TypeError", - message: 'The RPC receiver does not implement the method "value".' - }); - await assert.rejects(() => env.MyService.getRemoteNestedRpcProperty(func).value(), { - name: "TypeError", - message: '"value" is not a function.' + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcProperty". This type does not support ' + + 'serialization.', }); + await assert.rejects( + () => env.MyService.getNestedRpcProperty(func).value.x, + { + name: 'DataCloneError', + message: + 'Could not serialize object of type "RpcProperty". This type does not support ' + + 'serialization.', + } + ); + + assert.deepEqual( + stripDispose(await env.MyService.getRemoteNestedRpcProperty(func).value), + { x: 456 } + ); + await assert.rejects( + () => env.MyService.getRemoteNestedRpcProperty(func).value.x, + { + name: 'TypeError', + message: 'The RPC receiver does not implement the method "value".', + } + ); + await assert.rejects( + () => env.MyService.getRemoteNestedRpcProperty(func).value(), + { + name: 'TypeError', + message: '"value" is not a function.', + } + ); }, -} +}; export let streams = { async test(controller, env, ctx) { @@ -1037,7 +1129,7 @@ export let streams = { let { readable, writable } = new IdentityTransformStream(); let promise = env.MyService.writeToStream(writable); let text = await new Response(readable).text(); - assert.strictEqual(text, "foo, bar, baz!"); + assert.strictEqual(text, 'foo, bar, baz!'); await promise; } @@ -1047,7 +1139,7 @@ export let streams = { const { promise, resolve } = Promise.withResolvers(); const writable = new WritableStream({ write(chunk) { - result += dec.decode(chunk, {stream: true}); + result += dec.decode(chunk, { stream: true }); }, close() { result += dec.decode(); @@ -1056,7 +1148,7 @@ export let streams = { }); const p1 = env.MyService.writeToStream(writable); await promise; - assert.strictEqual(result, "foo, bar, baz!"); + assert.strictEqual(result, 'foo, bar, baz!'); await p1; } @@ -1100,16 +1192,18 @@ export let streams = { write(chunk) {}, abort(reason) { resolve(reason); - } + }, }); await env.MyService.writeToStreamAbort(writable); const reason = await promise; // TODO(someday): The reason should be the error that was passed to abort on the // remote side, but we currently do not propagate this. We end up with a generic // disconnection error instead, which certainly not ideal. - assert.strictEqual(reason.message, - 'WritableStream received over RPC was disconnected because the remote execution ' + - 'context has endeded.'); + assert.strictEqual( + reason.message, + 'WritableStream received over RPC was disconnected because the remote execution ' + + 'context has endeded.' + ); } // TODO(someday): Is there any way to construct an encoded WritableStream? Only system @@ -1122,29 +1216,31 @@ export let streams = { let writer = writable.getWriter(); let enc = new TextEncoder(); - await writer.write(enc.encode("foo, ")); - await writer.write(enc.encode("bar, ")); - await writer.write(enc.encode("baz!")); + await writer.write(enc.encode('foo, ')); + await writer.write(enc.encode('bar, ')); + await writer.write(enc.encode('baz!')); await writer.close(); - assert.strictEqual(await promise, "foo, bar, baz!"); + assert.strictEqual(await promise, 'foo, bar, baz!'); } // Send a JS-backed ReadableStream. { let controller; let readable = new ReadableStream({ - start(c) { controller = c; } + start(c) { + controller = c; + }, }); let promise = env.MyService.readFromStream(readable); let enc = new TextEncoder(); - controller.enqueue(enc.encode("foo, ")); - controller.enqueue(enc.encode("bar, ")); - controller.enqueue(enc.encode("baz!")); + controller.enqueue(enc.encode('foo, ')); + controller.enqueue(enc.encode('bar, ')); + controller.enqueue(enc.encode('baz!')); controller.close(); - assert.strictEqual(await promise, "foo, bar, baz!"); + assert.strictEqual(await promise, 'foo, bar, baz!'); } // Send streams that are locked. @@ -1153,25 +1249,25 @@ export let streams = { let writer = writable.getWriter(); let enc = new TextEncoder(); - writer.write(enc.encode("foo")); + writer.write(enc.encode('foo')); let reader = readable.getReader(); assert.rejects(env.MyService.writeToStream(writable), { - name: "TypeError", - message: "The WritableStream has been locked to a writer." + name: 'TypeError', + message: 'The WritableStream has been locked to a writer.', }); assert.rejects(env.MyService.readFromStream(readable), { - name: "TypeError", - message: "The ReadableStream has been locked to a reader." + name: 'TypeError', + message: 'The ReadableStream has been locked to a reader.', }); // Verify the streams still work. let dec = new TextDecoder(); - assert.strictEqual(dec.decode((await reader.read()).value), "foo"); + assert.strictEqual(dec.decode((await reader.read()).value), 'foo'); - writer.write(enc.encode("bar")); - assert.strictEqual(dec.decode((await reader.read()).value), "bar"); + writer.write(enc.encode('bar')); + assert.strictEqual(dec.decode((await reader.read()).value), 'bar'); writer.close(); assert.strictEqual((await reader.read()).done, true); @@ -1181,14 +1277,20 @@ export let streams = { { let readable = await env.MyService.returnReadableStream(); let text = await new Response(readable).text(); - assert.strictEqual(text, "foo, bar, baz!"); + assert.strictEqual(text, 'foo, bar, baz!'); } // Receive multiple ReadableStreams. { let readables = await env.MyService.returnMultipleReadableStreams(); - assert.strictEqual(await new Response(readables[0]).text(), "foo, bar, baz!"); - assert.strictEqual(await new Response(readables[1]).text(), "foo, bar, baz!"); + assert.strictEqual( + await new Response(readables[0]).text(), + 'foo, bar, baz!' + ); + assert.strictEqual( + await new Response(readables[1]).text(), + 'foo, bar, baz!' + ); } // Send ReadableStream, but fail to fully write it. @@ -1198,40 +1300,42 @@ export let streams = { let writer = writable.getWriter(); let enc = new TextEncoder(); - await writer.write(enc.encode("foo, ")); - await writer.write(enc.encode("bar, ")); - await writer.write(enc.encode("baz!")); - await writer.abort("foo"); + await writer.write(enc.encode('foo, ')); + await writer.write(enc.encode('bar, ')); + await writer.write(enc.encode('baz!')); + await writer.abort('foo'); await assert.rejects(promise, { - name: "Error", + name: 'Error', // TODO(someday): Propagate the actual error. - message: "ReadableStream received over RPC disconnected prematurely." + message: 'ReadableStream received over RPC disconnected prematurely.', }); } // Send fixed-length ReadableStream. { - let { readable, writable } = new FixedLengthStream("foo, bar, baz!".length); + let { readable, writable } = new FixedLengthStream( + 'foo, bar, baz!'.length + ); let promise = env.MyService.readFromStream(readable); let writer = writable.getWriter(); let enc = new TextEncoder(); - await writer.write(enc.encode("foo, ")); - await writer.write(enc.encode("bar, ")); - await writer.write(enc.encode("baz!")); + await writer.write(enc.encode('foo, ')); + await writer.write(enc.encode('bar, ')); + await writer.write(enc.encode('baz!')); await writer.close(); - assert.strictEqual(await promise, "foo, bar, baz!"); + assert.strictEqual(await promise, 'foo, bar, baz!'); } // Send an encoded ReadableStream { - let gzippedResp = await env.self.fetch("http://foo/gzip"); + let gzippedResp = await env.self.fetch('http://foo/gzip'); let text = await env.MyService.readFromStream(gzippedResp.body); - assert.strictEqual(text, "this text was gzipped"); + assert.strictEqual(text, 'this text was gzipped'); } // Round trip streams. @@ -1245,22 +1349,22 @@ export let streams = { let writer = writable.getWriter(); let enc = new TextEncoder(); - await writer.write(enc.encode("foo, ")); - await writer.write(enc.encode("bar, ")); - await writer.write(enc.encode("baz!")); + await writer.write(enc.encode('foo, ')); + await writer.write(enc.encode('bar, ')); + await writer.write(enc.encode('baz!')); await writer.close(); - assert.strictEqual(await readPromise, "foo, bar, baz!"); + assert.strictEqual(await readPromise, 'foo, bar, baz!'); } // Perform an HTTP request whose response uses a ReadableStream obtained over RPC. { - let resp = await env.self.fetch("http://foo/stream-from-rpc"); + let resp = await env.self.fetch('http://foo/stream-from-rpc'); - assert.strictEqual(await resp.text(), "foo, bar, baz!"); + assert.strictEqual(await resp.text(), 'foo, bar, baz!'); } - } -} + }, +}; export let serializeHttpTypes = { async test(controller, env, ctx) { @@ -1274,55 +1378,63 @@ export let serializeHttpTypes = { assert.strictEqual(headers instanceof Headers, true); // Awkwardly, there's actually no API to get the non-lowercased header names. - assert.deepEqual([...headers], [ - ["content-length", "123"], - ["corge", "!@#"], - ["foo", "bar"], - ["set-cookie", "abc"], - ["set-cookie", "def"], - ]); - - assert.deepEqual(headers.getSetCookie(), ["abc", "def"]); + assert.deepEqual( + [...headers], + [ + ['content-length', '123'], + ['corge', '!@#'], + ['foo', 'bar'], + ['set-cookie', 'abc'], + ['set-cookie', 'def'], + ] + ); + + assert.deepEqual(headers.getSetCookie(), ['abc', 'def']); } { let req = await env.MyService.returnRequest(); - assert.strictEqual(req.url, "http://my-url.com"); - assert.strictEqual(req.method, "PUT"); - assert.strictEqual(req.headers.get("Accept-Encoding"), "bazzip"); - assert.strictEqual(req.headers.get("Foo"), "Bar"); - assert.strictEqual(req.redirect, "manual"); + assert.strictEqual(req.url, 'http://my-url.com'); + assert.strictEqual(req.method, 'PUT'); + assert.strictEqual(req.headers.get('Accept-Encoding'), 'bazzip'); + assert.strictEqual(req.headers.get('Foo'), 'Bar'); + assert.strictEqual(req.redirect, 'manual'); - assert.strictEqual(await req.text(), "Hello every body!"); + assert.strictEqual(await req.text(), 'Hello every body!'); assert.deepEqual(req.cf, { abc: 123, - hello: "goodbye", + hello: 'goodbye', }); } // Check that a Request with an AbortSignal can't be sent. (We should fix this someday, by // making AbortSignal itself RPC-compatible.) - await assert.rejects(env.MyService.roundTrip( - new Request("http://foo", {signal: AbortSignal.timeout(100)})), { - name: "DataCloneError", - message: 'Could not serialize object of type "AbortSignal". This type does not support ' + - 'serialization.' - }); + await assert.rejects( + env.MyService.roundTrip( + new Request('http://foo', { signal: AbortSignal.timeout(100) }) + ), + { + name: 'DataCloneError', + message: + 'Could not serialize object of type "AbortSignal". This type does not support ' + + 'serialization.', + } + ); { let req = await env.MyService.returnResponse(); assert.strictEqual(req.status, 404); - assert.strictEqual(req.statusText, "Not Found"); - assert.strictEqual(req.headers.get("Content-Type"), "abc"); - assert.deepEqual(req.cf, {foo: 123, bar: "def"}); + assert.strictEqual(req.statusText, 'Not Found'); + assert.strictEqual(req.headers.get('Content-Type'), 'abc'); + assert.deepEqual(req.cf, { foo: 123, bar: 'def' }); - assert.strictEqual(await req.text(), "Response body!"); + assert.strictEqual(await req.text(), 'Response body!'); } - } -} + }, +}; // Test that exceptions thrown from async native functions have a proper stack trace. (This is // not specific to RPC but RPC is a convenient place to test it since we can easily define the @@ -1336,10 +1448,10 @@ export let testAsyncStackTrace = { await env.MyService.throwingMethod(); } catch (e) { // verify stack trace was produced - assert.strictEqual(e.stack.includes("at async Object.test"), true); + assert.strictEqual(e.stack.includes('at async Object.test'), true); } - } -} + }, +}; // Test that exceptions thrown over RPC have the .remote property. export let testExceptionProperties = { @@ -1348,10 +1460,10 @@ export let testExceptionProperties = { await env.MyService.throwingMethod(); } catch (e) { assert.strictEqual(e.remote, true); - assert.strictEqual(e.message, "METHOD THREW"); + assert.strictEqual(e.message, 'METHOD THREW'); } - } -} + }, +}; // Test that get(), put(), and delete() are valid RPC method names, not hijacked by Fetcher. export let canUseGetPutDelete = { @@ -1359,8 +1471,8 @@ export let canUseGetPutDelete = { assert.strictEqual(await env.MyService.get(12), 13); assert.strictEqual(await env.MyService.put(5, 7), 12); assert.strictEqual(await env.MyService.delete(3), 2); - } -} + }, +}; // Test that stubs can still be used after logging them. export let logging = { @@ -1371,16 +1483,16 @@ export let logging = { assert.strictEqual(await stub.increment(1), 2); console.log(stub); assert.strictEqual(await stub.increment(1), 3); - } -} + }, +}; // DOMException is structured cloneable export let domExceptionClone = { test() { - const de1 = new DOMException("hello", "NotAllowedError"); + const de1 = new DOMException('hello', 'NotAllowedError'); // custom own properties on the instance are not preserved... - de1.foo = "ignored"; + de1.foo = 'ignored'; const de2 = structuredClone(de1); assert.strictEqual(de1.name, de2.name); @@ -1390,5 +1502,5 @@ export let domExceptionClone = { assert.notStrictEqual(de1, de2); assert.notStrictEqual(de1.foo, de2.foo); assert.strictEqual(de2.foo, undefined); - } -} + }, +}; diff --git a/src/workerd/api/tests/memory-cache-test.js b/src/workerd/api/tests/memory-cache-test.js index 3646067e848..0aeda6bde53 100644 --- a/src/workerd/api/tests/memory-cache-test.js +++ b/src/workerd/api/tests/memory-cache-test.js @@ -1,7 +1,4 @@ -import { - strictEqual, - ok, -} from 'node:assert'; +import { strictEqual, ok } from 'node:assert'; export const basic = { async test(ctrl, env) { @@ -17,7 +14,7 @@ export const basic = { strictEqual(value, 'bar'); strictEqual(value, value2); strictEqual(fallbackCalled, 1); - } + }, }; export const keysTooLarge = { @@ -35,13 +32,16 @@ export const keysTooLarge = { for (const key of ['a'.repeat(2049), 'ä'.repeat(1025)]) { await env.CACHE.read(key, async (k) => { throw new Error('should not be called'); - }).then(() => { - throw new Error('should have rejected'); - }, err => { - strictEqual(err.message, 'Key too large.'); - }); + }).then( + () => { + throw new Error('should have rejected'); + }, + (err) => { + strictEqual(err.message, 'Key too large.'); + } + ); } - } + }, }; export const valueNotSerializable = { @@ -63,7 +63,7 @@ export const valueNotSerializable = { } catch (err) { strictEqual(err.message, 'failed to serialize function'); } - } + }, }; export const evictionsHappen = { @@ -85,20 +85,26 @@ export const evictionsHappen = { }); // At this point, 'bar' should have been evicted. strictEqual(await env.CACHE2.read('bar'), undefined); - } + }, }; export const evictionsHappenValueSize = { async test(ctrl, env) { - strictEqual(await env.CACHE3.read('foo', async (key) => { - return { value: 'a'.repeat(495) }; - }), 'a'.repeat(495)); + strictEqual( + await env.CACHE3.read('foo', async (key) => { + return { value: 'a'.repeat(495) }; + }), + 'a'.repeat(495) + ); strictEqual(await env.CACHE3.read('foo'), 'a'.repeat(495)); - strictEqual(await env.CACHE3.read('bar', async (key) => { - return { value: 'a'.repeat(500) }; - }), 'a'.repeat(500)); + strictEqual( + await env.CACHE3.read('bar', async (key) => { + return { value: 'a'.repeat(500) }; + }), + 'a'.repeat(500) + ); strictEqual(await env.CACHE3.read('bar'), undefined); @@ -109,22 +115,26 @@ export const evictionsHappenValueSize = { strictEqual(await env.CACHE3.read(`${n}`), 'a'.repeat(100)); } strictEqual(await env.CACHE3.read('bar'), undefined); - } + }, }; export const concurrentReads = { async test(ctrl, env) { const promises = []; - promises.push(env.CACHE.read('qux', () => { - return { value: 'qux' }; - })); - promises.push(env.CACHE.read('qux', () => { - throw new Error('should not have been called'); - })); + promises.push( + env.CACHE.read('qux', () => { + return { value: 'qux' }; + }) + ); + promises.push( + env.CACHE.read('qux', () => { + throw new Error('should not have been called'); + }) + ); const results = await Promise.allSettled(promises); strictEqual(results[0].value, 'qux'); strictEqual(results[1].value, 'qux'); - } + }, }; export const delayedFallback = { @@ -134,7 +144,7 @@ export const delayedFallback = { return { value: 123 }; }); strictEqual(foo, 123); - } + }, }; export const expiredEviction = { @@ -145,7 +155,7 @@ export const expiredEviction = { strictEqual(ret, 'foo'); await scheduler.wait(600); strictEqual(await env.CACHE.read('expires'), undefined); - } + }, }; export const fallbackThrows = { @@ -176,7 +186,7 @@ export const fallbackThrows = { } catch (err) { strictEqual(err.message, 'foo'); } - } + }, }; export const fallbackQueueMicrotask = { @@ -189,38 +199,46 @@ export const fallbackQueueMicrotask = { return promise; }); strictEqual(ret, 'xyz'); - } + }, }; export const fallbackChainingOnError = { async test(ctrl, env) { const promises = []; - promises.push(env.CACHE.read('fallback', () => { - throw new Error('foo'); - })); - promises.push(env.CACHE.read('fallback', () => { - return { value: 'bar' }; - })); + promises.push( + env.CACHE.read('fallback', () => { + throw new Error('foo'); + }) + ); + promises.push( + env.CACHE.read('fallback', () => { + return { value: 'bar' }; + }) + ); const results = await Promise.allSettled(promises); // The first one failed. strictEqual(results[0].reason.message, 'foo'); // The second one succeeded. strictEqual(results[1].value, 'bar'); - } -} + }, +}; export const fallbackNotLocked = { async test(ctrl, env) { // Test that one long running fallback does not block another one. const promises = []; - promises.push(env.CACHE.read('aaa', async () => { - await scheduler.wait(500); - return { value: 'aaa' }; - })); - promises.push(env.CACHE.read('bbb', async () => { - return { value: 'bbb' }; - })); + promises.push( + env.CACHE.read('aaa', async () => { + await scheduler.wait(500); + return { value: 'aaa' }; + }) + ); + promises.push( + env.CACHE.read('bbb', async () => { + return { value: 'bbb' }; + }) + ); const raced = await Promise.race(promises); strictEqual(raced, 'bbb'); - } + }, }; diff --git a/src/workerd/api/tests/module-test.js b/src/workerd/api/tests/module-test.js index c5b99fed648..9eb007c62d9 100644 --- a/src/workerd/api/tests/module-test.js +++ b/src/workerd/api/tests/module-test.js @@ -7,5 +7,5 @@ export const basics = { if (assert !== assert2 && assert !== assert3) { throw new Error('bad things happened'); } - } + }, }; diff --git a/src/workerd/api/tests/navigator-beacon-test.js b/src/workerd/api/tests/navigator-beacon-test.js index fe72cd0508e..fe6027ecc19 100644 --- a/src/workerd/api/tests/navigator-beacon-test.js +++ b/src/workerd/api/tests/navigator-beacon-test.js @@ -1,7 +1,4 @@ -import { - ok, - strictEqual, -} from 'node:assert'; +import { ok, strictEqual } from 'node:assert'; const enc = new TextEncoder(); @@ -11,19 +8,24 @@ ok(!navigator.sendBeacon('http://example.org', 'does not work')); export const navigatorBeaconTest = { async test(ctrl, env, ctx) { ok(navigator.sendBeacon('http://example.org', 'beacon')); - ok(navigator.sendBeacon('http://example.org', new ReadableStream({ - start(c) { - c.enqueue(enc.encode('beacon')); - c.close(); - } - }))); + ok( + navigator.sendBeacon( + 'http://example.org', + new ReadableStream({ + start(c) { + c.enqueue(enc.encode('beacon')); + c.close(); + }, + }) + ) + ); ok(navigator.sendBeacon('http://example.org', enc.encode('beacon'))); - } + }, }; export default { async fetch(req, env) { strictEqual(await req.text(), 'beacon'); return new Response(null, { status: 204 }); - } + }, }; diff --git a/src/workerd/api/tests/reporterror-test.js b/src/workerd/api/tests/reporterror-test.js index 34e436a3af1..9cbedda85a7 100644 --- a/src/workerd/api/tests/reporterror-test.js +++ b/src/workerd/api/tests/reporterror-test.js @@ -25,8 +25,9 @@ addEventListener('error', handler); reportError('boom'); throws(() => reportError(), { - message: "Failed to execute 'reportError' on 'ServiceWorkerGlobalScope': " + - "parameter 1 is not of type 'JsValue'." + message: + "Failed to execute 'reportError' on 'ServiceWorkerGlobalScope': " + + "parameter 1 is not of type 'JsValue'.", }); export const reportErrorTest = { @@ -37,5 +38,5 @@ export const reportErrorTest = { // is make sure the basic API is working and that the mock fn was called. reportError(boom); strictEqual(handler.mock.calls.length, 2); - } + }, }; diff --git a/src/workerd/api/tests/response-json.js b/src/workerd/api/tests/response-json.js index 8f5d07b30b7..c923dafaf62 100644 --- a/src/workerd/api/tests/response-json.js +++ b/src/workerd/api/tests/response-json.js @@ -1,66 +1,62 @@ -import { - strictEqual, - ok, - deepStrictEqual, - throws, -} from 'node:assert'; +import { strictEqual, ok, deepStrictEqual, throws } from 'node:assert'; export const basics = { async test() { - const response = Response.json({a:1}); + const response = Response.json({ a: 1 }); ok(response instanceof Response); - strictEqual(response.headers.get('content-type'), - 'application/json'); + strictEqual(response.headers.get('content-type'), 'application/json'); strictEqual(await response.text(), '{"a":1}'); - } + }, }; export const headers = { async test() { - const response = Response.json({a:1}, { - headers: [['content-type', 'abc']] - }); + const response = Response.json( + { a: 1 }, + { + headers: [['content-type', 'abc']], + } + ); ok(response instanceof Response); strictEqual(response.headers.get('content-type'), 'abc'); - deepStrictEqual(await response.json(), {a: 1}); - } + deepStrictEqual(await response.json(), { a: 1 }); + }, }; export const headers2 = { async test() { const headers = new Headers(); headers.set('content-type', 'abc'); - const response = Response.json({a:1}, { headers }); + const response = Response.json({ a: 1 }, { headers }); ok(response instanceof Response); strictEqual(response.headers.get('content-type'), 'abc'); - deepStrictEqual(await response.json(), {a: 1}); - } + deepStrictEqual(await response.json(), { a: 1 }); + }, }; export const headers3 = { async test() { const other = new Response(); other.headers.set('content-type', 'abc'); - const response = Response.json({a:1}, other); + const response = Response.json({ a: 1 }, other); ok(response instanceof Response); strictEqual(response.headers.get('content-type'), 'abc'); - deepStrictEqual(await response.json(), {a: 1}); - } + deepStrictEqual(await response.json(), { a: 1 }); + }, }; export const headers4 = { async test() { - const response = Response.json({a:1}, {}); + const response = Response.json({ a: 1 }, {}); ok(response instanceof Response); - strictEqual(response.headers.get('content-type'), - 'application/json'); - deepStrictEqual(await response.json(), {a: 1}); - } + strictEqual(response.headers.get('content-type'), 'application/json'); + deepStrictEqual(await response.json(), { a: 1 }); + }, }; export const notJsonSerializable = { async test() { // Some values are not JSON serializable... - throws(() => Response.json({a:1n})); - } + throws(() => Response.json({ a: 1n })); + }, }; diff --git a/src/workerd/api/tests/scheduler-test.js b/src/workerd/api/tests/scheduler-test.js index 5342e9a45dc..53d6d9019ca 100644 --- a/src/workerd/api/tests/scheduler-test.js +++ b/src/workerd/api/tests/scheduler-test.js @@ -1,8 +1,4 @@ -import { - deepStrictEqual, - strictEqual, - ok, -} from 'node:assert'; +import { deepStrictEqual, strictEqual, ok } from 'node:assert'; // Test for the Event and EventTarget standard Web API implementations. // The implementation for these are in api/basics.{h|c++} @@ -60,7 +56,7 @@ export const wait = { // globalThis.scheduler can be monkeypatched over... scheduler = 'foo'; strictEqual(globalThis.scheduler, 'foo'); - } + }, }; export default { @@ -71,6 +67,6 @@ export default { scheduler.wait(10).then(() => { globalThis.longWait = true; }); - return new Response("not waiting"); - } + return new Response('not waiting'); + }, }; diff --git a/src/workerd/api/tests/streams-test.js b/src/workerd/api/tests/streams-test.js index 640d1c307c1..4a6d4749712 100644 --- a/src/workerd/api/tests/streams-test.js +++ b/src/workerd/api/tests/streams-test.js @@ -1,8 +1,4 @@ -import { - strictEqual, - ok, - deepStrictEqual, -} from 'node:assert'; +import { strictEqual, ok, deepStrictEqual } from 'node:assert'; const enc = new TextEncoder(); @@ -15,11 +11,12 @@ export const rs = { start(c) { c.enqueue(enc.encode('hellohello')); c.close(); - } - }) + }, + }), }); - for await (const _ of resp.body) {} - } + for await (const _ of resp.body) { + } + }, }; export const ts = { @@ -32,10 +29,11 @@ export const ts = { writer.close(); const resp = await env.subrequest.fetch('http://example.org', { method: 'POST', - body: readable + body: readable, }); - for await (const _ of resp.body) {} - } + for await (const _ of resp.body) { + } + }, }; export const byobMin = { @@ -43,7 +41,9 @@ export const byobMin = { let controller; const rs = new ReadableStream({ type: 'bytes', - start(c) { controller = c; } + start(c) { + controller = c; + }, }); async function handleRead(readable) { @@ -67,7 +67,7 @@ export const byobMin = { strictEqual(results[0].status, 'fulfilled'); strictEqual(results[1].status, 'fulfilled'); - } + }, }; export const cancelReadsOnReleaseLock = { @@ -78,12 +78,15 @@ export const cancelReadsOnReleaseLock = { const result = await Promise.allSettled([read, reader.releaseLock()]); strictEqual(result[0].status, 'rejected'); - strictEqual(result[0].reason.message, 'This ReadableStream reader has been released.'); + strictEqual( + result[0].reason.message, + 'This ReadableStream reader has been released.' + ); strictEqual(result[1].status, 'fulfilled'); // Make sure we can still get another reader const reader2 = rs.getReader(); - } + }, }; export const cancelWriteOnReleaseLock = { @@ -91,7 +94,7 @@ export const cancelWriteOnReleaseLock = { const ws = new WritableStream({ write() { return new Promise(() => {}); - } + }, }); const writer = ws.getWriter(); // This first write is just to start the write queue so that the @@ -104,12 +107,15 @@ export const cancelWriteOnReleaseLock = { writer.releaseLock(), ]); strictEqual(results[0].status, 'rejected'); - strictEqual(results[0].reason.message, 'This WritableStream writer has been released.'); + strictEqual( + results[0].reason.message, + 'This WritableStream writer has been released.' + ); strictEqual(results[1].status, 'fulfilled'); // Make sure we can still get another writer const writer2 = ws.getWriter(); - } + }, }; export const readAllTextRequestSmall = { @@ -119,12 +125,15 @@ export const readAllTextRequestSmall = { c.enqueue(enc.encode('hello ')); c.enqueue(enc.encode('world!')); c.close(); - } + }, + }); + const request = new Request('http://example.org', { + method: 'POST', + body: rs, }); - const request = new Request('http://example.org', { method: 'POST', body: rs }); const text = await request.text(); strictEqual(text, 'hello world!'); - } + }, }; export const readAllTextResponseSmall = { @@ -134,12 +143,12 @@ export const readAllTextResponseSmall = { c.enqueue(enc.encode('hello ')); c.enqueue(enc.encode('world!')); c.close(); - } + }, }); const response = new Response(rs); const text = await response.text(); strictEqual(text, 'hello world!'); - } + }, }; export const readAllTextRequestBig = { @@ -161,13 +170,16 @@ export const readAllTextRequestBig = { const chunk = chunks.shift(); check += chunk; c.enqueue(enc.encode(chunk)); - } + }, + }); + const request = new Request('http://example.org', { + method: 'POST', + body: rs, }); - const request = new Request('http://example.org', { method: 'POST', body: rs }); const text = await request.text(); strictEqual(text.length, check.length); strictEqual(text, check); - } + }, }; export const readAllTextResponseBig = { @@ -190,14 +202,14 @@ export const readAllTextResponseBig = { const chunk = chunks.shift(); check += chunk; c.enqueue(enc.encode(chunk)); - } + }, }); const response = new Response(rs); const promise = response.text(); const text = await promise; strictEqual(text.length, check.length); strictEqual(text, check); - } + }, }; export const readAllTextFailedPull = { @@ -206,7 +218,7 @@ export const readAllTextFailedPull = { async pull(c) { await scheduler.wait(10); throw new Error('boom'); - } + }, }); const response = new Response(rs); const promise = response.text(); @@ -216,7 +228,7 @@ export const readAllTextFailedPull = { } catch (err) { strictEqual(err.message, 'boom'); } - } + }, }; export const readAllTextFailedStart = { @@ -225,7 +237,7 @@ export const readAllTextFailedStart = { async start(c) { await scheduler.wait(10); throw new Error('boom'); - } + }, }); const response = new Response(rs); const promise = response.text(); @@ -235,7 +247,7 @@ export const readAllTextFailedStart = { } catch (err) { strictEqual(err.message, 'boom'); } - } + }, }; export const readAllTextFailed = { @@ -244,7 +256,7 @@ export const readAllTextFailed = { async start(c) { await scheduler.wait(10); c.error(new Error('boom')); - } + }, }); const response = new Response(rs); ok(!rs.locked); @@ -256,7 +268,7 @@ export const readAllTextFailed = { } catch (err) { strictEqual(err.message, 'boom'); } - } + }, }; export const tsCancel = { @@ -271,7 +283,7 @@ export const tsCancel = { strictEqual(reason, 'boom'); await scheduler.wait(10); cancelCalled = true; - } + }, }); ok(!cancelCalled); await readable.cancel('boom'); @@ -285,7 +297,7 @@ export const tsCancel = { strictEqual(reason, 'boom'); await scheduler.wait(10); cancelCalled = true; - } + }, }); ok(!cancelCalled); await writable.abort('boom'); @@ -296,7 +308,7 @@ export const tsCancel = { const { writable } = new TransformStream({ async cancel(reason) { throw new Error('boomy'); - } + }, }); try { await writable.abort('boom'); @@ -305,7 +317,7 @@ export const tsCancel = { strictEqual(err.message, 'boomy'); } } - } + }, }; export const writableStreamGcTraceFinishes = { @@ -313,7 +325,7 @@ export const writableStreamGcTraceFinishes = { // TODO(soon): We really need better testing for gc visitation. const ws = new WritableStream(); gc(); - } + }, }; export const readableStreamFromAsyncGenerator = { @@ -323,14 +335,14 @@ export const readableStreamFromAsyncGenerator = { yield 'hello'; await scheduler.wait(10); yield 'world'; - }; + } const rs = ReadableStream.from(gen()); const chunks = []; for await (const chunk of rs) { chunks.push(chunk); } deepStrictEqual(chunks, ['hello', 'world']); - } + }, }; export const readableStreamFromSyncGenerator = { @@ -341,7 +353,7 @@ export const readableStreamFromSyncGenerator = { chunks.push(chunk); } deepStrictEqual(chunks, ['hello', 'world']); - } + }, }; export const readableStreamFromSyncGenerator2 = { @@ -356,7 +368,7 @@ export const readableStreamFromSyncGenerator2 = { chunks.push(chunk); } deepStrictEqual(chunks, ['hello', 'world']); - } + }, }; export const readableStreamFromAsyncCanceled = { @@ -371,7 +383,7 @@ export const readableStreamFromAsyncCanceled = { } finally { strictEqual(count, 1); } - }; + } const rs = ReadableStream.from(gen()); const chunks = []; for await (const chunk of rs) { @@ -379,15 +391,15 @@ export const readableStreamFromAsyncCanceled = { return; } deepStrictEqual(chunks, ['hello']); - } + }, }; export const readableStreamFromThrowingAsyncGen = { async test() { async function* gen() { - yield 'hello'; - throw new Error('boom'); - }; + yield 'hello'; + throw new Error('boom'); + } const rs = ReadableStream.from(gen()); const chunks = []; try { @@ -399,19 +411,19 @@ export const readableStreamFromThrowingAsyncGen = { strictEqual(err.message, 'boom'); } deepStrictEqual(chunks, ['hello']); - } + }, }; export const readableStreamFromNoopAsyncGen = { async test() { - async function* gen() {}; + async function* gen() {} const rs = ReadableStream.from(gen()); const chunks = []; for await (const chunk of rs) { chunks.push(chunk); } deepStrictEqual(chunks, []); - } + }, }; export const abortWriterAfterGc = { @@ -424,7 +436,7 @@ export const abortWriterAfterGc = { const writer = getWriter(); gc(); await writer.abort(); - } + }, }; export const finalReadOnInternalStreamReturnsBuffer = { @@ -445,12 +457,12 @@ export const finalReadOnInternalStreamReturnsBuffer = { ok(result.value instanceof Uint8Array); strictEqual(result.value.byteLength, 0); strictEqual(result.value.buffer.byteLength, 10); - } + }, }; export default { async fetch(request, env) { strictEqual(request.headers.get('content-length'), '10'); return new Response(request.body); - } + }, }; diff --git a/src/workerd/api/tests/unsafe-test.js b/src/workerd/api/tests/unsafe-test.js index bbfe2a6137c..6803445ee88 100644 --- a/src/workerd/api/tests/unsafe-test.js +++ b/src/workerd/api/tests/unsafe-test.js @@ -1,28 +1,28 @@ -import { strictEqual, ok, throws } from "node:assert"; +import { strictEqual, ok, throws } from 'node:assert'; export const basics = { test(ctx, env) { - strictEqual(env.unsafe.eval("1"), 1); + strictEqual(env.unsafe.eval('1'), 1); // eval does not capture outer scope. let m = 1; - throws(() => env.unsafe.eval("m")); + throws(() => env.unsafe.eval('m')); - throws(() => env.unsafe.eval(' throw new Error("boom"); ', "foo"), { - message: "boom", + throws(() => env.unsafe.eval(' throw new Error("boom"); ', 'foo'), { + message: 'boom', stack: /at foo/, }); // Regular dynamic eval is still not allowed - throws(() => eval("")); + throws(() => eval('')); }, }; export const newFunction = { test(ctx, env) { - const fn = env.unsafe.newFunction("return m", "bar", "m"); + const fn = env.unsafe.newFunction('return m', 'bar', 'm'); strictEqual(fn.length, 1); - strictEqual(fn.name, "bar"); + strictEqual(fn.name, 'bar'); strictEqual(fn(), undefined); strictEqual(fn(1), 1); strictEqual(fn(fn), fn); @@ -31,9 +31,9 @@ export const newFunction = { export const newAsyncFunction = { async test(ctx, env) { - const fn = env.unsafe.newAsyncFunction("return await m", "bar", "m"); + const fn = env.unsafe.newAsyncFunction('return await m', 'bar', 'm'); strictEqual(fn.length, 1); - strictEqual(fn.name, "bar"); + strictEqual(fn.name, 'bar'); strictEqual(await fn(), undefined); strictEqual(await fn(1), 1); strictEqual(await fn(fn), fn); @@ -43,9 +43,9 @@ export const newAsyncFunction = { export const newAsyncFunction2 = { async test(ctx, env) { - const fn = env.unsafe.newAsyncFunction("return await arguments[0]"); + const fn = env.unsafe.newAsyncFunction('return await arguments[0]'); strictEqual(fn.length, 0); - strictEqual(fn.name, "anonymous"); + strictEqual(fn.name, 'anonymous'); strictEqual(await fn(), undefined); strictEqual(await fn(1), 1); strictEqual(await fn(fn), fn); @@ -65,7 +65,9 @@ export const newWasmModule = { throws(() => env.unsafe.newWasmModule(new Uint8Array([]))); // Test that we can successully construct a minimal valid Wasm module: magic // number 0asm + version - const result = env.unsafe.newWasmModule(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0])); + const result = env.unsafe.newWasmModule( + new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0]) + ); strictEqual(result.constructor, WebAssembly.Module); }, }; diff --git a/src/workerd/api/tests/url-test.js b/src/workerd/api/tests/url-test.js index cea23610eab..d2c9a41aadd 100644 --- a/src/workerd/api/tests/url-test.js +++ b/src/workerd/api/tests/url-test.js @@ -1,123 +1,124 @@ -import { - deepStrictEqual, - strictEqual, - ok, - fail, - throws, -} from 'node:assert'; +import { deepStrictEqual, strictEqual, ok, fail, throws } from 'node:assert'; export const constructAndGet = { test() { - const cases = [ { - 'input': 'https://capnproto.org', - 'pathname': '/', - 'comment': 'special URL, 0-component path' + input: 'https://capnproto.org', + pathname: '/', + comment: 'special URL, 0-component path', }, { - 'input': 'https://capnproto.org/', - 'pathname': '/', - 'comment': 'special URL, 1-component path with empty terminal component' + input: 'https://capnproto.org/', + pathname: '/', + comment: 'special URL, 1-component path with empty terminal component', }, { - 'input': 'https://capnproto.org/foo', - 'pathname': '/foo', - 'comment': 'special URL, 1-component path' + input: 'https://capnproto.org/foo', + pathname: '/foo', + comment: 'special URL, 1-component path', }, { - 'input': 'https://capnproto.org/foo/', - 'pathname': '/foo/', - 'comment': 'special URL, 2-component path with empty terminal component' + input: 'https://capnproto.org/foo/', + pathname: '/foo/', + comment: 'special URL, 2-component path with empty terminal component', }, { - 'input': 'https://capnproto.org/%2F', - 'pathname': '/%2F', - 'comment': 'encoded slash can be a path component' + input: 'https://capnproto.org/%2F', + pathname: '/%2F', + comment: 'encoded slash can be a path component', }, { - 'input': 'https://capnproto.org//', - 'pathname': '//', - 'comment': '// in path is not collapsed' + input: 'https://capnproto.org//', + pathname: '//', + comment: '// in path is not collapsed', }, { - 'input': 'https://capnproto.org/./', - 'pathname': '/', - 'comment': '/./ in path is collapsed' + input: 'https://capnproto.org/./', + pathname: '/', + comment: '/./ in path is collapsed', }, { - 'input': 'https://capnproto.org/?<>', - 'search': '?%3C%3E', - 'comment': 'angle brackets in search get percent-encoded' + input: 'https://capnproto.org/?<>', + search: '?%3C%3E', + comment: 'angle brackets in search get percent-encoded', }, { - 'input': 'https://capnproto.org/??', - 'search': '??', - 'comment': 'question mark in search does not get percent-encoded' + input: 'https://capnproto.org/??', + search: '??', + comment: 'question mark in search does not get percent-encoded', }, { - 'input': 'https://capnproto.org/?foo', - 'search': '?foo', - 'href': 'https://capnproto.org/?foo', - 'comment': 'No-valued/empty-valued query parameters are preserved round-trip' + input: 'https://capnproto.org/?foo', + search: '?foo', + href: 'https://capnproto.org/?foo', + comment: + 'No-valued/empty-valued query parameters are preserved round-trip', }, { - 'input': 'https://capnproto.org/?foo=', - 'search': '?foo=', - 'href': 'https://capnproto.org/?foo=', - 'comment': 'No-valued/empty-valued query parameters are preserved round-trip' + input: 'https://capnproto.org/?foo=', + search: '?foo=', + href: 'https://capnproto.org/?foo=', + comment: + 'No-valued/empty-valued query parameters are preserved round-trip', }, { - 'input': 'https://capnproto.org/?foo=&bar', - 'search': '?foo=&bar', - 'href': 'https://capnproto.org/?foo=&bar', - 'comment': 'No-valued/empty-valued query parameters are preserved round-trip' + input: 'https://capnproto.org/?foo=&bar', + search: '?foo=&bar', + href: 'https://capnproto.org/?foo=&bar', + comment: + 'No-valued/empty-valued query parameters are preserved round-trip', }, { - 'input': 'https://capnproto.org/?foo&bar=', - 'search': '?foo&bar=', - 'href': 'https://capnproto.org/?foo&bar=', - 'comment': 'No-valued/empty-valued query parameters are preserved round-trip' + input: 'https://capnproto.org/?foo&bar=', + search: '?foo&bar=', + href: 'https://capnproto.org/?foo&bar=', + comment: + 'No-valued/empty-valued query parameters are preserved round-trip', }, { - 'input': 'https://capnproto.org/?foo+bar=baz+qux', - 'search': '?foo+bar=baz+qux', - 'comment': 'pluses in search do not get percent-encoded' + input: 'https://capnproto.org/?foo+bar=baz+qux', + search: '?foo+bar=baz+qux', + comment: 'pluses in search do not get percent-encoded', }, { - 'input': 'https://capnproto.org/?😺', - 'search': '?%F0%9F%98%BA', - 'comment': 'cat emoji in search gets percent-encoded' + input: 'https://capnproto.org/?😺', + search: '?%F0%9F%98%BA', + comment: 'cat emoji in search gets percent-encoded', }, { - 'input': 'https://capnproto.org/#😺', - 'hash': '#%F0%9F%98%BA', - 'comment': 'cat emoji in hash gets percent-encoded' + input: 'https://capnproto.org/#😺', + hash: '#%F0%9F%98%BA', + comment: 'cat emoji in hash gets percent-encoded', }, { - 'input': 'https://capnproto.org:443/', - 'href': 'https://capnproto.org/', - 'comment': 'Parsing a URL with an explicit scheme-default port ignores the port' + input: 'https://capnproto.org:443/', + href: 'https://capnproto.org/', + comment: + 'Parsing a URL with an explicit scheme-default port ignores the port', }, { - 'input': 'https://capnproto.org:/', - 'href': 'https://capnproto.org/', - 'comment': 'Parsing a URL with a ":" but no port ignores port' + input: 'https://capnproto.org:/', + href: 'https://capnproto.org/', + comment: 'Parsing a URL with a ":" but no port ignores port', }, { - 'input': 'http://foo/bar;baz@qux', - 'href': 'http://foo/bar;baz@qux', - 'comment': 'URL path components are encoded with the path percent encode set' + input: 'http://foo/bar;baz@qux', + href: 'http://foo/bar;baz@qux', + comment: + 'URL path components are encoded with the path percent encode set', }, { - 'input': 'https://jam_com.helpusersvote.net/', - 'href': 'https://jam_com.helpusersvote.net/', - 'comment': 'Underscores are allowed in hostnames' + input: 'https://jam_com.helpusersvote.net/', + href: 'https://jam_com.helpusersvote.net/', + comment: 'Underscores are allowed in hostnames', }, { - 'input': 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', - 'href': 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', - 'comment': 'Encoded percent signs in userinfo, path, query, and fragment get round-tripped' + input: + 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', + href: 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', + comment: + 'Encoded percent signs in userinfo, path, query, and fragment get round-tripped', }, ]; @@ -125,8557 +126,8599 @@ export const constructAndGet = { ['pathname', 'search', 'hash', 'href'].forEach((attribute) => { const url = new URL(test.input); if (test[attribute] !== undefined) { - strictEqual(url[attribute], test[attribute], `${test.input}: ${test.comment}`); + strictEqual( + url[attribute], + test[attribute], + `${test.input}: ${test.comment}` + ); } }); }); - } + }, }; export const constructSetAndGet = { test() { const cases = { - 'protocol': [ + protocol: [ + { + href: 'https://example.com/', + new_value: 'http', + expected: { + href: 'http://example.com/', + }, + comment: 'Setting scheme on URL with null port does not change port', + }, + { + href: 'https://example.com:80/', + new_value: 'http', + expected: { + href: 'http://example.com/', + }, + comment: + 'Setting scheme on URL with port that is the new scheme-default port nulls out port', + }, + { + href: 'https://example.com:1234/', + new_value: 'http', + expected: { + href: 'http://example.com:1234/', + }, + comment: + 'Setting scheme on URL with non-scheme-default port preserves port', + }, + ], + search: [ + { + href: 'https://capnproto.org/', + new_value: '#', + expected: { + href: 'https://capnproto.org/?%23', + search: '?%23', + }, + }, + { + href: 'https://capnproto.org/', + new_value: '#=#', + expected: { + href: 'https://capnproto.org/?%23=%23', + search: '?%23=%23', + }, + }, + ], + host: [ + { + href: 'https://example.com/', + new_value: 'foo.example.com:', + expected: { + href: 'https://foo.example.com/', + }, + comment: 'Setting host with ":" but no port ignores port', + }, + { + href: 'https://example.com/', + new_value: 'foo.example.com:80', + expected: { + href: 'https://foo.example.com:80/', + }, + comment: 'Setting host with non-scheme-default port sets port', + }, + { + href: 'https://example.com:1234/', + new_value: 'foo.example.com:443', + expected: { + href: 'https://foo.example.com/', + }, + comment: 'Setting host with scheme-default port nulls out port', + }, + { + href: 'https://example.com/', + new_value: 'foo.example.com:443', + expected: { + href: 'https://foo.example.com/', + }, + comment: 'Setting host with scheme-default port nulls out port', + }, + ], + port: [ + { + href: 'https://example.com/', + new_value: '443', + expected: { + href: 'https://example.com/', + }, + comment: 'Setting port to scheme-default port is a no-op', + }, + { + href: 'https://example.com:1234/', + new_value: '443', + expected: { + href: 'https://example.com/', + }, + comment: 'Setting port to scheme-default port nulls out port', + }, + { + href: 'https://example.com/', + new_value: '1234', + expected: { + href: 'https://example.com:1234/', + }, + comment: 'Setting port to non-scheme-default port adopts port', + }, + { + href: 'https://example.com:80/', + new_value: '1234', + expected: { + href: 'https://example.com:1234/', + }, + comment: 'Setting port to non-scheme-default port adopts port', + }, + { + href: 'https://example.com:1234/', + new_value: '', + expected: { + href: 'https://example.com/', + }, + comment: 'Setting port to the empty string nulls out port', + }, + ], + hostname: [ + { + href: 'http://example.com/path/to/something?query=foo#hash', + new_value: 'newexample.com', + expected: { + href: 'http://newexample.com/path/to/something?query=foo#hash', + }, + }, + ], + }; + + for (const attribute in cases) { + cases[attribute].forEach((test) => { + const url = new URL(test.href); + url[attribute] = test.new_value; + for (const a in test.expected) { + strictEqual( + url[a], + test.expected[a], + `${test.href}: ${test.comment}` + ); + } + }); + } + }, +}; + +export const urlSearchParamsStringifyBehavior = { + test() { + const url = new URL('https://example.com/?foo&bar=&baz=qux'); + strictEqual(url.href, 'https://example.com/?foo&bar=&baz=qux'); + strictEqual(url.search, '?foo&bar=&baz=qux'); + strictEqual(url.searchParams.toString(), 'foo=&bar=&baz=qux'); + }, +}; + +export const urlSearchParamsForEach = { + test() { + let searchParams = new URLSearchParams(''); + searchParams.forEach(() => { + fail('Should not have been called'); + }); + + const foreachOutput = []; + searchParams = new URLSearchParams('key1=value1&key2=value2'); + strictEqual(searchParams.size, 2); + let pushed = false; + searchParams.forEach((val, key) => { + foreachOutput.push([key, val]); + if (!pushed) { + // We can add params within this loop but it's not really safe + // because it will cause the loop to run forever if we're not + // careful. + pushed = true; + searchParams.set('key3', 'value3'); + } + }); + deepStrictEqual(foreachOutput, [ + ['key1', 'value1'], + ['key2', 'value2'], + ['key3', 'value3'], + ]); + strictEqual(searchParams.size, 3); + + // Calling forEach with no argument throws + throws(() => searchParams.forEach()); + + // Calling forEach with wrong arguments throws + throws(() => searchParams.forEach(1)); + + // This can be overridden by the second argument + searchParams.forEach(function () { + strictEqual(this, 1); + }, 1); + + // Propagates errors + throws(() => + searchParams.forEach(() => { + throw new Error('boom'); + }) + ); + }, +}; + +export const urlSearchParamsInit1 = { + test() { + const search1 = new URLSearchParams('a=b'); + const search2 = new URLSearchParams(search1); + strictEqual(search1.toString(), search2.toString()); + }, +}; + +export const urlSearchParamsInit2 = { + test() { + const search1 = new URLSearchParams('a=b'); + search1[Symbol.iterator] = function* () { + yield ['y', 'z']; + }; + const search2 = new URLSearchParams(search1); + ok(!search2.has('a')); + ok(search2.has('y')); + strictEqual(search2.get('y'), 'z'); + }, +}; + +export const urlSearchParamsInit3 = { + test() { + // If the initializer has a deleted iterator, then it's + // contents are ignored but can still be interpreted as + // a dictionary. + const search1 = new URLSearchParams('a=b'); + search1[Symbol.iterator] = undefined; + search1.y = 'z'; + const search2 = new URLSearchParams(search1); + ok(!search2.has('a')); + ok(search2.has('y')); + strictEqual(search2.get('y'), 'z'); + }, +}; + +export const urlSearchParamsInit4 = { + test() { + const formdata = new FormData(); + formdata.append('a', 'b'); + ok(formdata.has('a')); + const search2 = new URLSearchParams(formdata); + ok(search2.has('a')); + strictEqual(search2.get('a'), 'b'); + }, +}; + +export const urlSearchParamsInit5 = { + test() { + const formdata = new FormData(); + formdata.append('a', 'b'); + formdata[Symbol.iterator] = undefined; + const search2 = new URLSearchParams(formdata); + ok(!search2.has('a')); + }, +}; + +export const urlToJson = { + test() { + const url = new URL('https://example.com'); + strictEqual(JSON.stringify(url), '"https://example.com/"'); + }, +}; + +export const urlSearchParamsSet = { + test() { + const url = new URL('https://example.com?c=d'); + url.searchParams.set('a', 'b'); + strictEqual(url.searchParams.size, 2); + url.searchParams.delete('c'); + strictEqual(url.searchParams.size, 1); + ok(url.searchParams.has('a')); + ok(!url.searchParams.has('c')); + ok(url.searchParams.has('a', 'b')); + ok(!url.searchParams.has('a', 'c')); + url.searchParams.delete('a', 'c'); + ok(url.searchParams.has('a')); + }, +}; + +export const urlConstructorTests = { + test() { + const cases = [ + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js', + { + input: 'http://example\t.\norg', + base: 'http://example.org/foo/bar', + href: 'http://example.org/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'C|/', + base: 'file://host/dir/file', + href: 'file://host/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'C|\n/', + base: 'file://host/dir/file', + href: 'file://host/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'https://:@test', + base: 'about:blank', + href: 'https://test/', + origin: 'https://test', + protocol: 'https:', + username: '', + password: '', + host: 'test', + hostname: 'test', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'non-special://test:@test/x', + base: 'about:blank', + href: 'non-special://test@test/x', + origin: 'null', + protocol: 'non-special:', + username: 'test', + password: '', + host: 'test', + hostname: 'test', + port: '', + pathname: '/x', + search: '', + hash: '', + }, + { + input: 'non-special://:@test/x', + base: 'about:blank', + href: 'non-special://test/x', + origin: 'null', + protocol: 'non-special:', + username: '', + password: '', + host: 'test', + hostname: 'test', + port: '', + pathname: '/x', + search: '', + hash: '', + }, + { + input: 'http:foo.com', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/foo.com', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/foo.com', + search: '', + hash: '', + }, + { + input: '\t :foo.com \n', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:foo.com', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:foo.com', + search: '', + hash: '', + }, + { + input: ' foo.com ', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/foo.com', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/foo.com', + search: '', + hash: '', + }, + { + input: 'a:\t foo.com', + base: 'http://example.org/foo/bar', + href: 'a: foo.com', + origin: 'null', + protocol: 'a:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: ' foo.com', + search: '', + hash: '', + }, + { + input: 'http://f:21/ b ? d # e ', + base: 'http://example.org/foo/bar', + href: 'http://f:21/%20b%20?%20d%20#%20e', + origin: 'http://f:21', + protocol: 'http:', + username: '', + password: '', + host: 'f:21', + hostname: 'f', + port: '21', + pathname: '/%20b%20', + search: '?%20d%20', + hash: '#%20e', + }, + { + input: 'lolscheme:x x#x x', + base: 'about:blank', + href: 'lolscheme:x x#x%20x', + protocol: 'lolscheme:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'x x', + search: '', + hash: '#x%20x', + }, + { + input: 'http://f:/c', + base: 'http://example.org/foo/bar', + href: 'http://f/c', + origin: 'http://f', + protocol: 'http:', + username: '', + password: '', + host: 'f', + hostname: 'f', + port: '', + pathname: '/c', + search: '', + hash: '', + }, + { + input: 'http://f:0/c', + base: 'http://example.org/foo/bar', + href: 'http://f:0/c', + origin: 'http://f:0', + protocol: 'http:', + username: '', + password: '', + host: 'f:0', + hostname: 'f', + port: '0', + pathname: '/c', + search: '', + hash: '', + }, + { + input: 'http://f:00000000000000/c', + base: 'http://example.org/foo/bar', + href: 'http://f:0/c', + origin: 'http://f:0', + protocol: 'http:', + username: '', + password: '', + host: 'f:0', + hostname: 'f', + port: '0', + pathname: '/c', + search: '', + hash: '', + }, + { + input: 'http://f:00000000000000000000080/c', + base: 'http://example.org/foo/bar', + href: 'http://f/c', + origin: 'http://f', + protocol: 'http:', + username: '', + password: '', + host: 'f', + hostname: 'f', + port: '', + pathname: '/c', + search: '', + hash: '', + }, + { + input: 'http://f:b/c', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://f: /c', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://f:\n/c', + base: 'http://example.org/foo/bar', + href: 'http://f/c', + origin: 'http://f', + protocol: 'http:', + username: '', + password: '', + host: 'f', + hostname: 'f', + port: '', + pathname: '/c', + search: '', + hash: '', + }, + { + input: 'http://f:fifty-two/c', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://f:999999/c', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'non-special://f:999999/c', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://f: 21 / b ? d # e ', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: '', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '', + }, + { + input: ' \t', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '', + }, + { + input: ':foo.com/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:foo.com/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:foo.com/', + search: '', + hash: '', + }, + { + input: ':foo.com\\', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:foo.com/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:foo.com/', + search: '', + hash: '', + }, + { + input: ':', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:', + search: '', + hash: '', + }, + { + input: ':a', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:a', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:a', + search: '', + hash: '', + }, + { + input: ':/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:/', + search: '', + hash: '', + }, + { + input: ':\\', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:/', + search: '', + hash: '', + }, + { + input: ':#', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:#', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:', + search: '', + hash: '', + }, + { + input: '#', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar#', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '', + }, + { + input: '#/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar#/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '#/', + }, + { + input: '#\\', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar#\\', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '#\\', + }, + { + input: '#;?', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar#;?', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '#;?', + }, + { + input: '?', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar?', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '', + }, + { + input: '/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: ':23', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:23', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:23', + search: '', + hash: '', + }, + { + input: '/:23', + base: 'http://example.org/foo/bar', + href: 'http://example.org/:23', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/:23', + search: '', + hash: '', + }, + { + input: '::', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/::', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/::', + search: '', + hash: '', + }, + { + input: '::23', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/::23', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/::23', + search: '', + hash: '', + }, + { + input: 'foo://', + base: 'http://example.org/foo/bar', + href: 'foo://', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '', + search: '', + hash: '', + }, + { + input: 'http://a:b@c:29/d', + base: 'http://example.org/foo/bar', + href: 'http://a:b@c:29/d', + origin: 'http://c:29', + protocol: 'http:', + username: 'a', + password: 'b', + host: 'c:29', + hostname: 'c', + port: '29', + pathname: '/d', + search: '', + hash: '', + }, + { + input: 'http::@c:29', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/:@c:29', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/:@c:29', + search: '', + hash: '', + }, + { + input: 'http://&a:foo(b]c@d:2/', + base: 'http://example.org/foo/bar', + href: 'http://&a:foo(b%5Dc@d:2/', + origin: 'http://d:2', + protocol: 'http:', + username: '&a', + password: 'foo(b%5Dc', + host: 'd:2', + hostname: 'd', + port: '2', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://::@c@d:2', + base: 'http://example.org/foo/bar', + href: 'http://:%3A%40c@d:2/', + origin: 'http://d:2', + protocol: 'http:', + username: '', + password: '%3A%40c', + host: 'd:2', + hostname: 'd', + port: '2', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://foo.com:b@d/', + base: 'http://example.org/foo/bar', + href: 'http://foo.com:b@d/', + origin: 'http://d', + protocol: 'http:', + username: 'foo.com', + password: 'b', + host: 'd', + hostname: 'd', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://foo.com/\\@', + base: 'http://example.org/foo/bar', + href: 'http://foo.com//@', + origin: 'http://foo.com', + protocol: 'http:', + username: '', + password: '', + host: 'foo.com', + hostname: 'foo.com', + port: '', + pathname: '//@', + search: '', + hash: '', + }, + { + input: 'http:\\\\foo.com\\', + base: 'http://example.org/foo/bar', + href: 'http://foo.com/', + origin: 'http://foo.com', + protocol: 'http:', + username: '', + password: '', + host: 'foo.com', + hostname: 'foo.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:\\\\a\\b:c\\d@foo.com\\', + base: 'http://example.org/foo/bar', + href: 'http://a/b:c/d@foo.com/', + origin: 'http://a', + protocol: 'http:', + username: '', + password: '', + host: 'a', + hostname: 'a', + port: '', + pathname: '/b:c/d@foo.com/', + search: '', + hash: '', + }, + { + input: 'foo:/', + base: 'http://example.org/foo/bar', + href: 'foo:/', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'foo:/bar.com/', + base: 'http://example.org/foo/bar', + href: 'foo:/bar.com/', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/bar.com/', + search: '', + hash: '', + }, + { + input: 'foo://///////', + base: 'http://example.org/foo/bar', + href: 'foo://///////', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '///////', + search: '', + hash: '', + }, + { + input: 'foo://///////bar.com/', + base: 'http://example.org/foo/bar', + href: 'foo://///////bar.com/', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '///////bar.com/', + search: '', + hash: '', + }, + { + input: 'foo:////://///', + base: 'http://example.org/foo/bar', + href: 'foo:////://///', + origin: 'null', + protocol: 'foo:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//://///', + search: '', + hash: '', + }, + { + input: 'c:/foo', + base: 'http://example.org/foo/bar', + href: 'c:/foo', + origin: 'null', + protocol: 'c:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/foo', + search: '', + hash: '', + }, + { + input: '//foo/bar', + base: 'http://example.org/foo/bar', + href: 'http://foo/bar', + origin: 'http://foo', + protocol: 'http:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/bar', + search: '', + hash: '', + }, + { + input: 'http://foo/path;a??e#f#g', + base: 'http://example.org/foo/bar', + href: 'http://foo/path;a??e#f#g', + origin: 'http://foo', + protocol: 'http:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/path;a', + search: '??e', + hash: '#f#g', + }, + { + input: 'http://foo/abcd?efgh?ijkl', + base: 'http://example.org/foo/bar', + href: 'http://foo/abcd?efgh?ijkl', + origin: 'http://foo', + protocol: 'http:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/abcd', + search: '?efgh?ijkl', + hash: '', + }, + { + input: 'http://foo/abcd#foo?bar', + base: 'http://example.org/foo/bar', + href: 'http://foo/abcd#foo?bar', + origin: 'http://foo', + protocol: 'http:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/abcd', + search: '', + hash: '#foo?bar', + }, + { + input: '[61:24:74]:98', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/[61:24:74]:98', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/[61:24:74]:98', + search: '', + hash: '', + }, + { + input: 'http:[61:27]/:foo', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/[61:27]/:foo', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/[61:27]/:foo', + search: '', + hash: '', + }, + { + input: 'http://[1::2]:3:4', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://2001::1', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://2001::1]', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://2001::1]:80', + base: 'http://example.org/foo/bar', + failure: true, + }, + { + input: 'http://[2001::1]', + base: 'http://example.org/foo/bar', + href: 'http://[2001::1]/', + origin: 'http://[2001::1]', + protocol: 'http:', + username: '', + password: '', + host: '[2001::1]', + hostname: '[2001::1]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://[::127.0.0.1]', + base: 'http://example.org/foo/bar', + href: 'http://[::7f00:1]/', + origin: 'http://[::7f00:1]', + protocol: 'http:', + username: '', + password: '', + host: '[::7f00:1]', + hostname: '[::7f00:1]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://[0:0:0:0:0:0:13.1.68.3]', + base: 'http://example.org/foo/bar', + href: 'http://[::d01:4403]/', + origin: 'http://[::d01:4403]', + protocol: 'http:', + username: '', + password: '', + host: '[::d01:4403]', + hostname: '[::d01:4403]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://[2001::1]:80', + base: 'http://example.org/foo/bar', + href: 'http://[2001::1]/', + origin: 'http://[2001::1]', + protocol: 'http:', + username: '', + password: '', + host: '[2001::1]', + hostname: '[2001::1]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/example.com/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/example.com/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'ftp:/example.com/', + base: 'http://example.org/foo/bar', + href: 'ftp://example.com/', + origin: 'ftp://example.com', + protocol: 'ftp:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https:/example.com/', + base: 'http://example.org/foo/bar', + href: 'https://example.com/', + origin: 'https://example.com', + protocol: 'https:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'madeupscheme:/example.com/', + base: 'http://example.org/foo/bar', + href: 'madeupscheme:/example.com/', + origin: 'null', + protocol: 'madeupscheme:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'file:/example.com/', + base: 'http://example.org/foo/bar', + href: 'file:///example.com/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'file://example:1/', + base: 'about:blank', + failure: true, + }, + { + input: 'file://example:test/', + base: 'about:blank', + failure: true, + }, + { + input: 'file://example%/', + base: 'about:blank', + failure: true, + }, + { + input: 'file://[example]/', + base: 'about:blank', + failure: true, + }, + { + input: 'ftps:/example.com/', + base: 'http://example.org/foo/bar', + href: 'ftps:/example.com/', + origin: 'null', + protocol: 'ftps:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'gopher:/example.com/', + base: 'http://example.org/foo/bar', + href: 'gopher:/example.com/', + protocol: 'gopher:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'ws:/example.com/', + base: 'http://example.org/foo/bar', + href: 'ws://example.com/', + origin: 'ws://example.com', + protocol: 'ws:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss:/example.com/', + base: 'http://example.org/foo/bar', + href: 'wss://example.com/', + origin: 'wss://example.com', + protocol: 'wss:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'data:/example.com/', + base: 'http://example.org/foo/bar', + href: 'data:/example.com/', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'javascript:/example.com/', + base: 'http://example.org/foo/bar', + href: 'javascript:/example.com/', + origin: 'null', + protocol: 'javascript:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'mailto:/example.com/', + base: 'http://example.org/foo/bar', + href: 'mailto:/example.com/', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'http:example.com/', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/example.com/', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/example.com/', + search: '', + hash: '', + }, + { + input: 'ftp:example.com/', + base: 'http://example.org/foo/bar', + href: 'ftp://example.com/', + origin: 'ftp://example.com', + protocol: 'ftp:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https:example.com/', + base: 'http://example.org/foo/bar', + href: 'https://example.com/', + origin: 'https://example.com', + protocol: 'https:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'madeupscheme:example.com/', + base: 'http://example.org/foo/bar', + href: 'madeupscheme:example.com/', + origin: 'null', + protocol: 'madeupscheme:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'ftps:example.com/', + base: 'http://example.org/foo/bar', + href: 'ftps:example.com/', + origin: 'null', + protocol: 'ftps:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'gopher:example.com/', + base: 'http://example.org/foo/bar', + href: 'gopher:example.com/', + protocol: 'gopher:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'ws:example.com/', + base: 'http://example.org/foo/bar', + href: 'ws://example.com/', + origin: 'ws://example.com', + protocol: 'ws:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss:example.com/', + base: 'http://example.org/foo/bar', + href: 'wss://example.com/', + origin: 'wss://example.com', + protocol: 'wss:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'data:example.com/', + base: 'http://example.org/foo/bar', + href: 'data:example.com/', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'javascript:example.com/', + base: 'http://example.org/foo/bar', + href: 'javascript:example.com/', + origin: 'null', + protocol: 'javascript:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'mailto:example.com/', + base: 'http://example.org/foo/bar', + href: 'mailto:example.com/', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: '/a/b/c', + base: 'http://example.org/foo/bar', + href: 'http://example.org/a/b/c', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/a/b/c', + search: '', + hash: '', + }, + { + input: '/a/ /c', + base: 'http://example.org/foo/bar', + href: 'http://example.org/a/%20/c', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/a/%20/c', + search: '', + hash: '', + }, + { + input: '/a%2fc', + base: 'http://example.org/foo/bar', + href: 'http://example.org/a%2fc', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/a%2fc', + search: '', + hash: '', + }, + { + input: '/a/%2f/c', + base: 'http://example.org/foo/bar', + href: 'http://example.org/a/%2f/c', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/a/%2f/c', + search: '', + hash: '', + }, + { + input: '#β', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar#%CE%B2', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + hash: '#%CE%B2', + }, + { + input: 'data:text/html,test#test', + base: 'http://example.org/foo/bar', + href: 'data:text/html,test#test', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'text/html,test', + search: '', + hash: '#test', + }, + { + input: 'tel:1234567890', + base: 'http://example.org/foo/bar', + href: 'tel:1234567890', + origin: 'null', + protocol: 'tel:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '1234567890', + search: '', + hash: '', + }, + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html', + { + input: 'file:c:\\foo\\bar.html', + base: 'file:///tmp/mock/path', + href: 'file:///c:/foo/bar.html', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/c:/foo/bar.html', + search: '', + hash: '', + }, + { + input: ' File:c|////foo\\bar.html', + base: 'file:///tmp/mock/path', + href: 'file:///c:////foo/bar.html', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/c:////foo/bar.html', + search: '', + hash: '', + }, + { + input: 'C|/foo/bar', + base: 'file:///tmp/mock/path', + href: 'file:///C:/foo/bar', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/foo/bar', + search: '', + hash: '', + }, + { + input: '/C|\\foo\\bar', + base: 'file:///tmp/mock/path', + href: 'file:///C:/foo/bar', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/foo/bar', + search: '', + hash: '', + }, + { + input: '//C|/foo/bar', + base: 'file:///tmp/mock/path', + href: 'file:///C:/foo/bar', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/foo/bar', + search: '', + hash: '', + }, + { + input: '//server/file', + base: 'file:///tmp/mock/path', + href: 'file://server/file', + protocol: 'file:', + username: '', + password: '', + host: 'server', + hostname: 'server', + port: '', + pathname: '/file', + search: '', + hash: '', + }, + { + input: '\\\\server\\file', + base: 'file:///tmp/mock/path', + href: 'file://server/file', + protocol: 'file:', + username: '', + password: '', + host: 'server', + hostname: 'server', + port: '', + pathname: '/file', + search: '', + hash: '', + }, + { + input: '/\\server/file', + base: 'file:///tmp/mock/path', + href: 'file://server/file', + protocol: 'file:', + username: '', + password: '', + host: 'server', + hostname: 'server', + port: '', + pathname: '/file', + search: '', + hash: '', + }, + { + input: 'file:///foo/bar.txt', + base: 'file:///tmp/mock/path', + href: 'file:///foo/bar.txt', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/foo/bar.txt', + search: '', + hash: '', + }, + { + input: 'file:///home/me', + base: 'file:///tmp/mock/path', + href: 'file:///home/me', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/home/me', + search: '', + hash: '', + }, + { + input: '//', + base: 'file:///tmp/mock/path', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '///', + base: 'file:///tmp/mock/path', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '///test', + base: 'file:///tmp/mock/path', + href: 'file:///test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '', + hash: '', + }, + { + input: 'file://test', + base: 'file:///tmp/mock/path', + href: 'file://test/', + protocol: 'file:', + username: '', + password: '', + host: 'test', + hostname: 'test', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file://localhost', + base: 'file:///tmp/mock/path', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file://localhost/', + base: 'file:///tmp/mock/path', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file://localhost/test', + base: 'file:///tmp/mock/path', + href: 'file:///test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '', + hash: '', + }, + { + input: 'test', + base: 'file:///tmp/mock/path', + href: 'file:///tmp/mock/test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/tmp/mock/test', + search: '', + hash: '', + }, + { + input: 'file:test', + base: 'file:///tmp/mock/path', + href: 'file:///tmp/mock/test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/tmp/mock/test', + search: '', + hash: '', + }, + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js', + { + input: 'http://example.com/././foo', + base: 'about:blank', + href: 'http://example.com/foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo', + search: '', + hash: '', + }, + { + input: 'http://example.com/./.foo', + base: 'about:blank', + href: 'http://example.com/.foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/.foo', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/.', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/./', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar/..', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar/../', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/..bar', + base: 'about:blank', + href: 'http://example.com/foo/..bar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/..bar', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar/../ton', + base: 'about:blank', + href: 'http://example.com/foo/ton', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/ton', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar/../ton/../../a', + base: 'about:blank', + href: 'http://example.com/a', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/a', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/../../..', + base: 'about:blank', + href: 'http://example.com/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/../../../ton', + base: 'about:blank', + href: 'http://example.com/ton', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/ton', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/%2e', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/%2e%2', + base: 'about:blank', + href: 'http://example.com/foo/%2e%2', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/%2e%2', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar', + base: 'about:blank', + href: 'http://example.com/%2e.bar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%2e.bar', + search: '', + hash: '', + }, + { + input: 'http://example.com////../..', + base: 'about:blank', + href: 'http://example.com//', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '//', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar//../..', + base: 'about:blank', + href: 'http://example.com/foo/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo/bar//..', + base: 'about:blank', + href: 'http://example.com/foo/bar/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo/bar/', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo', + base: 'about:blank', + href: 'http://example.com/foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo', + search: '', + hash: '', + }, + { + input: 'http://example.com/%20foo', + base: 'about:blank', + href: 'http://example.com/%20foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%20foo', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%', + base: 'about:blank', + href: 'http://example.com/foo%', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%2', + base: 'about:blank', + href: 'http://example.com/foo%2', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%2', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%2zbar', + base: 'about:blank', + href: 'http://example.com/foo%2zbar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%2zbar', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%2©zbar', + base: 'about:blank', + href: 'http://example.com/foo%2%C3%82%C2%A9zbar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%2%C3%82%C2%A9zbar', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%41%7a', + base: 'about:blank', + href: 'http://example.com/foo%41%7a', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%41%7a', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo\t\u0091%91', + base: 'about:blank', + href: 'http://example.com/foo%C2%91%91', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%C2%91%91', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo%00%51', + base: 'about:blank', + href: 'http://example.com/foo%00%51', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foo%00%51', + search: '', + hash: '', + }, + { + input: 'http://example.com/(%28:%3A%29)', + base: 'about:blank', + href: 'http://example.com/(%28:%3A%29)', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/(%28:%3A%29)', + search: '', + hash: '', + }, + { + input: 'http://example.com/%3A%3a%3C%3c', + base: 'about:blank', + href: 'http://example.com/%3A%3a%3C%3c', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%3A%3a%3C%3c', + search: '', + hash: '', + }, + { + input: 'http://example.com/foo\tbar', + base: 'about:blank', + href: 'http://example.com/foobar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/foobar', + search: '', + hash: '', + }, + { + input: 'http://example.com\\\\foo\\\\bar', + base: 'about:blank', + href: 'http://example.com//foo//bar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '//foo//bar', + search: '', + hash: '', + }, + { + input: 'http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd', + base: 'about:blank', + href: 'http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%7Ffp3%3Eju%3Dduvgw%3Dd', + search: '', + hash: '', + }, + { + input: 'http://example.com/@asdf%40', + base: 'about:blank', + href: 'http://example.com/@asdf%40', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/@asdf%40', + search: '', + hash: '', + }, + { + input: 'http://example.com/你好你好', + base: 'about:blank', + href: 'http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD', + search: '', + hash: '', + }, + { + input: 'http://example.com/‥/foo', + base: 'about:blank', + href: 'http://example.com/%E2%80%A5/foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%E2%80%A5/foo', + search: '', + hash: '', + }, + { + input: 'http://example.com//foo', + base: 'about:blank', + href: 'http://example.com/%EF%BB%BF/foo', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%EF%BB%BF/foo', + search: '', + hash: '', + }, + { + input: 'http://example.com/‮/foo/‭/bar', + base: 'about:blank', + href: 'http://example.com/%E2%80%AE/foo/%E2%80%AD/bar', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/%E2%80%AE/foo/%E2%80%AD/bar', + search: '', + hash: '', + }, + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js', + { + input: 'http://www.google.com/foo?bar=baz#', + base: 'about:blank', + href: 'http://www.google.com/foo?bar=baz#', + origin: 'http://www.google.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.google.com', + hostname: 'www.google.com', + port: '', + pathname: '/foo', + search: '?bar=baz', + hash: '', + }, + { + input: 'http://www.google.com/foo?bar=baz# »', + base: 'about:blank', + href: 'http://www.google.com/foo?bar=baz#%20%C2%BB', + origin: 'http://www.google.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.google.com', + hostname: 'www.google.com', + port: '', + pathname: '/foo', + search: '?bar=baz', + hash: '#%20%C2%BB', + }, + { + input: 'data:test# »', + base: 'about:blank', + href: 'data:test#%20%C2%BB', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'test', + search: '', + hash: '#%20%C2%BB', + }, + { + input: 'http://www.google.com', + base: 'about:blank', + href: 'http://www.google.com/', + origin: 'http://www.google.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.google.com', + hostname: 'www.google.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://192.0x00A80001', + base: 'about:blank', + href: 'http://192.168.0.1/', + origin: 'http://192.168.0.1', + protocol: 'http:', + username: '', + password: '', + host: '192.168.0.1', + hostname: '192.168.0.1', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://www/foo%2Ehtml', + base: 'about:blank', + href: 'http://www/foo%2Ehtml', + origin: 'http://www', + protocol: 'http:', + username: '', + password: '', + host: 'www', + hostname: 'www', + port: '', + pathname: '/foo%2Ehtml', + search: '', + hash: '', + }, + { + input: 'http://www/foo/%2E/html', + base: 'about:blank', + href: 'http://www/foo/html', + origin: 'http://www', + protocol: 'http:', + username: '', + password: '', + host: 'www', + hostname: 'www', + port: '', + pathname: '/foo/html', + search: '', + hash: '', + }, + { + input: 'http://user:pass@/', + base: 'about:blank', + failure: true, + }, + { + input: 'http://%25DOMAIN:foobar@foodomain.com/', + base: 'about:blank', + href: 'http://%25DOMAIN:foobar@foodomain.com/', + origin: 'http://foodomain.com', + protocol: 'http:', + username: '%25DOMAIN', + password: 'foobar', + host: 'foodomain.com', + hostname: 'foodomain.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:\\\\www.google.com\\foo', + base: 'about:blank', + href: 'http://www.google.com/foo', + origin: 'http://www.google.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.google.com', + hostname: 'www.google.com', + port: '', + pathname: '/foo', + search: '', + hash: '', + }, + { + input: 'http://foo:80/', + base: 'about:blank', + href: 'http://foo/', + origin: 'http://foo', + protocol: 'http:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://foo:81/', + base: 'about:blank', + href: 'http://foo:81/', + origin: 'http://foo:81', + protocol: 'http:', + username: '', + password: '', + host: 'foo:81', + hostname: 'foo', + port: '81', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'httpa://foo:80/', + base: 'about:blank', + href: 'httpa://foo:80/', + origin: 'null', + protocol: 'httpa:', + username: '', + password: '', + host: 'foo:80', + hostname: 'foo', + port: '80', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://foo:-80/', + base: 'about:blank', + failure: true, + }, + { + input: 'https://foo:443/', + base: 'about:blank', + href: 'https://foo/', + origin: 'https://foo', + protocol: 'https:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https://foo:80/', + base: 'about:blank', + href: 'https://foo:80/', + origin: 'https://foo:80', + protocol: 'https:', + username: '', + password: '', + host: 'foo:80', + hostname: 'foo', + port: '80', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ftp://foo:21/', + base: 'about:blank', + href: 'ftp://foo/', + origin: 'ftp://foo', + protocol: 'ftp:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ftp://foo:80/', + base: 'about:blank', + href: 'ftp://foo:80/', + origin: 'ftp://foo:80', + protocol: 'ftp:', + username: '', + password: '', + host: 'foo:80', + hostname: 'foo', + port: '80', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'gopher://foo:70/', + base: 'about:blank', + href: 'gopher://foo:70/', + protocol: 'gopher:', + username: '', + password: '', + host: 'foo:70', + hostname: 'foo', + port: '70', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'gopher://foo:443/', + base: 'about:blank', + href: 'gopher://foo:443/', + protocol: 'gopher:', + username: '', + password: '', + host: 'foo:443', + hostname: 'foo', + port: '443', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ws://foo:80/', + base: 'about:blank', + href: 'ws://foo/', + origin: 'ws://foo', + protocol: 'ws:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ws://foo:81/', + base: 'about:blank', + href: 'ws://foo:81/', + origin: 'ws://foo:81', + protocol: 'ws:', + username: '', + password: '', + host: 'foo:81', + hostname: 'foo', + port: '81', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ws://foo:443/', + base: 'about:blank', + href: 'ws://foo:443/', + origin: 'ws://foo:443', + protocol: 'ws:', + username: '', + password: '', + host: 'foo:443', + hostname: 'foo', + port: '443', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ws://foo:815/', + base: 'about:blank', + href: 'ws://foo:815/', + origin: 'ws://foo:815', + protocol: 'ws:', + username: '', + password: '', + host: 'foo:815', + hostname: 'foo', + port: '815', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss://foo:80/', + base: 'about:blank', + href: 'wss://foo:80/', + origin: 'wss://foo:80', + protocol: 'wss:', + username: '', + password: '', + host: 'foo:80', + hostname: 'foo', + port: '80', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss://foo:81/', + base: 'about:blank', + href: 'wss://foo:81/', + origin: 'wss://foo:81', + protocol: 'wss:', + username: '', + password: '', + host: 'foo:81', + hostname: 'foo', + port: '81', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss://foo:443/', + base: 'about:blank', + href: 'wss://foo/', + origin: 'wss://foo', + protocol: 'wss:', + username: '', + password: '', + host: 'foo', + hostname: 'foo', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss://foo:815/', + base: 'about:blank', + href: 'wss://foo:815/', + origin: 'wss://foo:815', + protocol: 'wss:', + username: '', + password: '', + host: 'foo:815', + hostname: 'foo', + port: '815', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/example.com/', + base: 'about:blank', + href: 'http://example.com/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ftp:/example.com/', + base: 'about:blank', + href: 'ftp://example.com/', + origin: 'ftp://example.com', + protocol: 'ftp:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https:/example.com/', + base: 'about:blank', + href: 'https://example.com/', + origin: 'https://example.com', + protocol: 'https:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'madeupscheme:/example.com/', + base: 'about:blank', + href: 'madeupscheme:/example.com/', + origin: 'null', + protocol: 'madeupscheme:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'file:/example.com/', + base: 'about:blank', + href: 'file:///example.com/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'ftps:/example.com/', + base: 'about:blank', + href: 'ftps:/example.com/', + origin: 'null', + protocol: 'ftps:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'gopher:/example.com/', + base: 'about:blank', + href: 'gopher:/example.com/', + protocol: 'gopher:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'ws:/example.com/', + base: 'about:blank', + href: 'ws://example.com/', + origin: 'ws://example.com', + protocol: 'ws:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss:/example.com/', + base: 'about:blank', + href: 'wss://example.com/', + origin: 'wss://example.com', + protocol: 'wss:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'data:/example.com/', + base: 'about:blank', + href: 'data:/example.com/', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'javascript:/example.com/', + base: 'about:blank', + href: 'javascript:/example.com/', + origin: 'null', + protocol: 'javascript:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'mailto:/example.com/', + base: 'about:blank', + href: 'mailto:/example.com/', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/example.com/', + search: '', + hash: '', + }, + { + input: 'http:example.com/', + base: 'about:blank', + href: 'http://example.com/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ftp:example.com/', + base: 'about:blank', + href: 'ftp://example.com/', + origin: 'ftp://example.com', + protocol: 'ftp:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https:example.com/', + base: 'about:blank', + href: 'https://example.com/', + origin: 'https://example.com', + protocol: 'https:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'madeupscheme:example.com/', + base: 'about:blank', + href: 'madeupscheme:example.com/', + origin: 'null', + protocol: 'madeupscheme:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'ftps:example.com/', + base: 'about:blank', + href: 'ftps:example.com/', + origin: 'null', + protocol: 'ftps:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'gopher:example.com/', + base: 'about:blank', + href: 'gopher:example.com/', + protocol: 'gopher:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'ws:example.com/', + base: 'about:blank', + href: 'ws://example.com/', + origin: 'ws://example.com', + protocol: 'ws:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'wss:example.com/', + base: 'about:blank', + href: 'wss://example.com/', + origin: 'wss://example.com', + protocol: 'wss:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'data:example.com/', + base: 'about:blank', + href: 'data:example.com/', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'javascript:example.com/', + base: 'about:blank', + href: 'javascript:example.com/', + origin: 'null', + protocol: 'javascript:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + { + input: 'mailto:example.com/', + base: 'about:blank', + href: 'mailto:example.com/', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'example.com/', + search: '', + hash: '', + }, + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html', + { + input: 'http:@www.example.com', + base: 'about:blank', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/@www.example.com', + base: 'about:blank', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://@www.example.com', + base: 'about:blank', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:a:b@www.example.com', + base: 'about:blank', + href: 'http://a:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/a:b@www.example.com', + base: 'about:blank', + href: 'http://a:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://a:b@www.example.com', + base: 'about:blank', + href: 'http://a:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://@pple.com', + base: 'about:blank', + href: 'http://pple.com/', + origin: 'http://pple.com', + protocol: 'http:', + username: '', + password: '', + host: 'pple.com', + hostname: 'pple.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http::b@www.example.com', + base: 'about:blank', + href: 'http://:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/:b@www.example.com', + base: 'about:blank', + href: 'http://:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://:b@www.example.com', + base: 'about:blank', + href: 'http://:b@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: 'b', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/:@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http://user@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:/@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http://@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'https:@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:a:b@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:/a:b@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http://a:b@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http::@/www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:a:@www.example.com', + base: 'about:blank', + href: 'http://a@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:/a:@www.example.com', + base: 'about:blank', + href: 'http://a@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://a:@www.example.com', + base: 'about:blank', + href: 'http://a@www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: 'a', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://www.@pple.com', + base: 'about:blank', + href: 'http://www.@pple.com/', + origin: 'http://pple.com', + protocol: 'http:', + username: 'www.', + password: '', + host: 'pple.com', + hostname: 'pple.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http:@:www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http:/@:www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http://@:www.example.com', + base: 'about:blank', + failure: true, + }, + { + input: 'http://:@www.example.com', + base: 'about:blank', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + '# Others', + { + input: '/', + base: 'http://www.example.com/test', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '/test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/test.txt', + search: '', + hash: '', + }, + { + input: '.', + base: 'http://www.example.com/test', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '..', + base: 'http://www.example.com/test', + href: 'http://www.example.com/', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/test.txt', + search: '', + hash: '', + }, + { + input: './test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/test.txt', + search: '', + hash: '', + }, + { + input: '../test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/test.txt', + search: '', + hash: '', + }, + { + input: '../aaa/test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/aaa/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/aaa/test.txt', + search: '', + hash: '', + }, + { + input: '../../test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/test.txt', + search: '', + hash: '', + }, + { + input: '中/test.txt', + base: 'http://www.example.com/test', + href: 'http://www.example.com/%E4%B8%AD/test.txt', + origin: 'http://www.example.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example.com', + hostname: 'www.example.com', + port: '', + pathname: '/%E4%B8%AD/test.txt', + search: '', + hash: '', + }, + { + input: 'http://www.example2.com', + base: 'http://www.example.com/test', + href: 'http://www.example2.com/', + origin: 'http://www.example2.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example2.com', + hostname: 'www.example2.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '//www.example2.com', + base: 'http://www.example.com/test', + href: 'http://www.example2.com/', + origin: 'http://www.example2.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.example2.com', + hostname: 'www.example2.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file:...', + base: 'http://www.example.com/test', + href: 'file:///...', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/...', + search: '', + hash: '', + }, + { + input: 'file:..', + base: 'http://www.example.com/test', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file:a', + base: 'http://www.example.com/test', + href: 'file:///a', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/a', + search: '', + hash: '', + }, + '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html', + 'Basic canonicalization, uppercase should be converted to lowercase', + { + input: 'http://ExAmPlE.CoM', + base: 'http://other.com/', + href: 'http://example.com/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://example example.com', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://Goo%20 goo%7C|.com', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[]', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[:]', + base: 'http://other.com/', + failure: true, + }, + 'U+3000 is mapped to U+0020 (space) which is disallowed', + { + input: 'http://GOO\u00a0\u3000goo.com', + base: 'http://other.com/', + failure: true, + }, + 'Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored', + { + input: 'http://GOO\u200b\u2060\ufeffgoo.com', + base: 'http://other.com/', + href: 'http://googoo.com/', + origin: 'http://googoo.com', + protocol: 'http:', + username: '', + password: '', + host: 'googoo.com', + hostname: 'googoo.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Leading and trailing C0 control or space', + { + input: '\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ', + base: 'about:blank', + href: 'http://example.com/', + origin: 'http://example.com', + protocol: 'http:', + username: '', + password: '', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)', + { + input: 'http://www.foo。bar.com', + base: 'http://other.com/', + href: 'http://www.foo.bar.com/', + origin: 'http://www.foo.bar.com', + protocol: 'http:', + username: '', + password: '', + host: 'www.foo.bar.com', + hostname: 'www.foo.bar.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0', + { + input: 'http://\ufdd0zyx.com', + base: 'http://other.com/', + failure: true, + }, + 'This is the same as previous but escaped', + { + input: 'http://%ef%b7%90zyx.com', + base: 'http://other.com/', + failure: true, + }, + 'U+FFFD', + { + input: 'https://\ufffd', + base: 'about:blank', + failure: true, + }, + { + input: 'https://%EF%BF%BD', + base: 'about:blank', + failure: true, + }, + { + input: 'https://x/\ufffd?\ufffd#\ufffd', + base: 'about:blank', + href: 'https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD', + origin: 'https://x', + protocol: 'https:', + username: '', + password: '', + host: 'x', + hostname: 'x', + port: '', + pathname: '/%EF%BF%BD', + search: '?%EF%BF%BD', + hash: '#%EF%BF%BD', + }, + "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", + { + input: 'http://Go.com', + base: 'http://other.com/', + href: 'http://go.com/', + origin: 'http://go.com', + protocol: 'http:', + username: '', + password: '', + host: 'go.com', + hostname: 'go.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257', + { + input: 'http://%41.com', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://%ef%bc%85%ef%bc%94%ef%bc%91.com', + base: 'http://other.com/', + failure: true, + }, + '...%00 in fullwidth should fail (also as escaped UTF-8 input)', + { + input: 'http://%00.com', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://%ef%bc%85%ef%bc%90%ef%bc%90.com', + base: 'http://other.com/', + failure: true, + }, + 'Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN', + { + input: 'http://你好你好', + base: 'http://other.com/', + href: 'http://xn--6qqa088eba/', + origin: 'http://xn--6qqa088eba', + protocol: 'http:', + username: '', + password: '', + host: 'xn--6qqa088eba', + hostname: 'xn--6qqa088eba', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https://faß.ExAmPlE/', + base: 'about:blank', + href: 'https://xn--fa-hia.example/', + origin: 'https://xn--fa-hia.example', + protocol: 'https:', + username: '', + password: '', + host: 'xn--fa-hia.example', + hostname: 'xn--fa-hia.example', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'sc://faß.ExAmPlE/', + base: 'about:blank', + href: 'sc://fa%C3%9F.ExAmPlE/', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'fa%C3%9F.ExAmPlE', + hostname: 'fa%C3%9F.ExAmPlE', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191', + { + input: 'http://%zz%66%a.com', + base: 'http://other.com/', + failure: true, + }, + 'If we get an invalid character that has been escaped.', + { + input: 'http://%25', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://hello%00', + base: 'http://other.com/', + failure: true, + }, + 'Escaped numbers should be treated like IP addresses if they are.', + { + input: 'http://%30%78%63%30%2e%30%32%35%30.01', + base: 'http://other.com/', + href: 'http://192.168.0.1/', + origin: 'http://192.168.0.1', + protocol: 'http:', + username: '', + password: '', + host: '192.168.0.1', + hostname: '192.168.0.1', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://%30%78%63%30%2e%30%32%35%30.01%2e', + base: 'http://other.com/', + href: 'http://192.168.0.1/', + origin: 'http://192.168.0.1', + protocol: 'http:', + username: '', + password: '', + host: '192.168.0.1', + hostname: '192.168.0.1', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://192.168.0.257', + base: 'http://other.com/', + failure: true, + }, + 'Invalid escaping in hosts causes failure', + { + input: 'http://%3g%78%63%30%2e%30%32%35%30%2E.01', + base: 'http://other.com/', + failure: true, + }, + 'A space in a host causes failure', + { + input: 'http://192.168.0.1 hello', + base: 'http://other.com/', + failure: true, + }, + { + input: 'https://x x:12', + base: 'about:blank', + failure: true, + }, + 'Fullwidth and escaped UTF-8 fullwidth should still be treated as IP', + { + input: 'http://0Xc0.0250.01', + base: 'http://other.com/', + href: 'http://192.168.0.1/', + origin: 'http://192.168.0.1', + protocol: 'http:', + username: '', + password: '', + host: '192.168.0.1', + hostname: '192.168.0.1', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Domains with empty labels', + { + input: 'http://./', + base: 'about:blank', + href: 'http://./', + origin: 'http://.', + protocol: 'http:', + username: '', + password: '', + host: '.', + hostname: '.', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://../', + base: 'about:blank', + href: 'http://../', + origin: 'http://..', + protocol: 'http:', + username: '', + password: '', + host: '..', + hostname: '..', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Broken IPv6', + { + input: 'http://[www.google.com]/', + base: 'about:blank', + failure: true, + }, + { + input: 'http://[google.com]', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[::1.2.3.4x]', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[::1.2.3.]', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[::1.2.]', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://[::1.]', + base: 'http://other.com/', + failure: true, + }, + 'Misc Unicode', + { + input: 'http://foo:💩@example.com/bar', + base: 'http://other.com/', + href: 'http://foo:%F0%9F%92%A9@example.com/bar', + origin: 'http://example.com', + protocol: 'http:', + username: 'foo', + password: '%F0%9F%92%A9', + host: 'example.com', + hostname: 'example.com', + port: '', + pathname: '/bar', + search: '', + hash: '', + }, + '# resolving a fragment against any scheme succeeds', + { + input: '#', + base: 'test:test', + href: 'test:test#', + origin: 'null', + protocol: 'test:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'test', + search: '', + hash: '', + }, + { + input: '#x', + base: 'mailto:x@x.com', + href: 'mailto:x@x.com#x', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'x@x.com', + search: '', + hash: '#x', + }, + { + input: '#x', + base: 'data:,', + href: 'data:,#x', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: ',', + search: '', + hash: '#x', + }, + { + input: '#x', + base: 'about:blank', + href: 'about:blank#x', + origin: 'null', + protocol: 'about:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'blank', + search: '', + hash: '#x', + }, + { + input: '#', + base: 'test:test?test', + href: 'test:test?test#', + origin: 'null', + protocol: 'test:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'test', + search: '?test', + hash: '', + }, + '# multiple @ in authority state', + { + input: 'https://@test@test@example:800/', + base: 'http://doesnotmatter/', + href: 'https://%40test%40test@example:800/', + origin: 'https://example:800', + protocol: 'https:', + username: '%40test%40test', + password: '', + host: 'example:800', + hostname: 'example', + port: '800', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https://@@@example', + base: 'http://doesnotmatter/', + href: 'https://%40%40@example/', + origin: 'https://example', + protocol: 'https:', + username: '%40%40', + password: '', + host: 'example', + hostname: 'example', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'non-az-09 characters', + { + input: 'http://`{}:`{}@h/`{}?`{}', + base: 'http://doesnotmatter/', + href: 'http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}', + origin: 'http://h', + protocol: 'http:', + username: '%60%7B%7D', + password: '%60%7B%7D', + host: 'h', + hostname: 'h', + port: '', + pathname: '/%60%7B%7D', + search: '?`{}', + hash: '', + }, + '# Credentials in base', + { + input: '/some/path', + base: 'http://user@example.org/smth', + href: 'http://user@example.org/some/path', + origin: 'http://example.org', + protocol: 'http:', + username: 'user', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/some/path', + search: '', + hash: '', + }, + { + input: '', + base: 'http://user:pass@example.org:21/smth', + href: 'http://user:pass@example.org:21/smth', + origin: 'http://example.org:21', + protocol: 'http:', + username: 'user', + password: 'pass', + host: 'example.org:21', + hostname: 'example.org', + port: '21', + pathname: '/smth', + search: '', + hash: '', + }, + { + input: '/some/path', + base: 'http://user:pass@example.org:21/smth', + href: 'http://user:pass@example.org:21/some/path', + origin: 'http://example.org:21', + protocol: 'http:', + username: 'user', + password: 'pass', + host: 'example.org:21', + hostname: 'example.org', + port: '21', + pathname: '/some/path', + search: '', + hash: '', + }, + '# a set of tests designed by zcorpan for relative URLs with unknown schemes', + { + input: 'i', + base: 'sc:sd', + failure: true, + }, + { + input: 'i', + base: 'sc:sd/sd', + failure: true, + }, + { + input: 'i', + base: 'sc:/pa/pa', + href: 'sc:/pa/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/i', + search: '', + hash: '', + }, + { + input: 'i', + base: 'sc://ho/pa', + href: 'sc://ho/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'ho', + hostname: 'ho', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: 'i', + base: 'sc:///pa/pa', + href: 'sc:///pa/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/i', + search: '', + hash: '', + }, + { + input: '../i', + base: 'sc:sd', + failure: true, + }, + { + input: '../i', + base: 'sc:sd/sd', + failure: true, + }, + { + input: '../i', + base: 'sc:/pa/pa', + href: 'sc:/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '../i', + base: 'sc://ho/pa', + href: 'sc://ho/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'ho', + hostname: 'ho', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '../i', + base: 'sc:///pa/pa', + href: 'sc:///i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '/i', + base: 'sc:sd', + failure: true, + }, + { + input: '/i', + base: 'sc:sd/sd', + failure: true, + }, + { + input: '/i', + base: 'sc:/pa/pa', + href: 'sc:/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '/i', + base: 'sc://ho/pa', + href: 'sc://ho/i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'ho', + hostname: 'ho', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '/i', + base: 'sc:///pa/pa', + href: 'sc:///i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/i', + search: '', + hash: '', + }, + { + input: '?i', + base: 'sc:sd', + failure: true, + }, + { + input: '?i', + base: 'sc:sd/sd', + failure: true, + }, + { + input: '?i', + base: 'sc:/pa/pa', + href: 'sc:/pa/pa?i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/pa', + search: '?i', + hash: '', + }, + { + input: '?i', + base: 'sc://ho/pa', + href: 'sc://ho/pa?i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'ho', + hostname: 'ho', + port: '', + pathname: '/pa', + search: '?i', + hash: '', + }, + { + input: '?i', + base: 'sc:///pa/pa', + href: 'sc:///pa/pa?i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/pa', + search: '?i', + hash: '', + }, + { + input: '#i', + base: 'sc:sd', + href: 'sc:sd#i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'sd', + search: '', + hash: '#i', + }, + { + input: '#i', + base: 'sc:sd/sd', + href: 'sc:sd/sd#i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'sd/sd', + search: '', + hash: '#i', + }, + { + input: '#i', + base: 'sc:/pa/pa', + href: 'sc:/pa/pa#i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/pa', + search: '', + hash: '#i', + }, + { + input: '#i', + base: 'sc://ho/pa', + href: 'sc://ho/pa#i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: 'ho', + hostname: 'ho', + port: '', + pathname: '/pa', + search: '', + hash: '#i', + }, + { + input: '#i', + base: 'sc:///pa/pa', + href: 'sc:///pa/pa#i', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pa/pa', + search: '', + hash: '#i', + }, + '# make sure that relative URL logic works on known typically non-relative schemes too', + { + input: 'about:/../', + base: 'about:blank', + href: 'about:/', + origin: 'null', + protocol: 'about:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'data:/../', + base: 'about:blank', + href: 'data:/', + origin: 'null', + protocol: 'data:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'javascript:/../', + base: 'about:blank', + href: 'javascript:/', + origin: 'null', + protocol: 'javascript:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'mailto:/../', + base: 'about:blank', + href: 'mailto:/', + origin: 'null', + protocol: 'mailto:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + '# unknown schemes and their hosts', + { + input: 'sc://ñ.test/', + base: 'about:blank', + href: 'sc://%C3%B1.test/', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1.test', + hostname: '%C3%B1.test', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'sc://\u0000/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc:// /', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://%/', + base: 'about:blank', + href: 'sc://%/', + protocol: 'sc:', + username: '', + password: '', + host: '%', + hostname: '%', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'sc://@/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://te@s:t@/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://:/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://:12/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://[/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://\\/', + base: 'about:blank', + failure: true, + }, + { + input: 'sc://]/', + base: 'about:blank', + failure: true, + }, + { + input: 'x', + base: 'sc://ñ', + href: 'sc://%C3%B1/x', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '/x', + search: '', + hash: '', + }, + '# unknown schemes and backslashes', + { + input: 'sc:\\../', + base: 'about:blank', + href: 'sc:\\../', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '\\../', + search: '', + hash: '', + }, + '# unknown scheme with path looking like a password', + { + input: 'sc::a@example.net', + base: 'about:blank', + href: 'sc::a@example.net', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: ':a@example.net', + search: '', + hash: '', + }, + '# unknown scheme with bogus percent-encoding', + { + input: 'wow:%NBD', + base: 'about:blank', + href: 'wow:%NBD', + origin: 'null', + protocol: 'wow:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '%NBD', + search: '', + hash: '', + }, + { + input: 'wow:%1G', + base: 'about:blank', + href: 'wow:%1G', + origin: 'null', + protocol: 'wow:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '%1G', + search: '', + hash: '', + }, + '# Hosts and percent-encoding', + { + input: 'ftp://example.com%80/', + base: 'about:blank', + failure: true, + }, + { + input: 'ftp://example.com%A0/', + base: 'about:blank', + failure: true, + }, + { + input: 'https://example.com%80/', + base: 'about:blank', + failure: true, + }, + { + input: 'https://example.com%A0/', + base: 'about:blank', + failure: true, + }, + { + input: 'ftp://%e2%98%83', + base: 'about:blank', + href: 'ftp://xn--n3h/', + origin: 'ftp://xn--n3h', + protocol: 'ftp:', + username: '', + password: '', + host: 'xn--n3h', + hostname: 'xn--n3h', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'https://%e2%98%83', + base: 'about:blank', + href: 'https://xn--n3h/', + origin: 'https://xn--n3h', + protocol: 'https:', + username: '', + password: '', + host: 'xn--n3h', + hostname: 'xn--n3h', + port: '', + pathname: '/', + search: '', + hash: '', + }, + '# tests from jsdom/whatwg-url designed for code coverage', + { + input: 'http://127.0.0.1:10100/relative_import.html', + base: 'about:blank', + href: 'http://127.0.0.1:10100/relative_import.html', + origin: 'http://127.0.0.1:10100', + protocol: 'http:', + username: '', + password: '', + host: '127.0.0.1:10100', + hostname: '127.0.0.1', + port: '10100', + pathname: '/relative_import.html', + search: '', + hash: '', + }, + { + input: 'http://facebook.com/?foo=%7B%22abc%22', + base: 'about:blank', + href: 'http://facebook.com/?foo=%7B%22abc%22', + origin: 'http://facebook.com', + protocol: 'http:', + username: '', + password: '', + host: 'facebook.com', + hostname: 'facebook.com', + port: '', + pathname: '/', + search: '?foo=%7B%22abc%22', + hash: '', + }, + { + input: 'https://localhost:3000/jqueryui@1.2.3', + base: 'about:blank', + href: 'https://localhost:3000/jqueryui@1.2.3', + origin: 'https://localhost:3000', + protocol: 'https:', + username: '', + password: '', + host: 'localhost:3000', + hostname: 'localhost', + port: '3000', + pathname: '/jqueryui@1.2.3', + search: '', + hash: '', + }, + '# tab/LF/CR', + { + input: + 'h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg', + base: 'about:blank', + href: 'http://host:9000/path?query#frag', + origin: 'http://host:9000', + protocol: 'http:', + username: '', + password: '', + host: 'host:9000', + hostname: 'host', + port: '9000', + pathname: '/path', + search: '?query', + hash: '#frag', + }, + '# Stringification of URL.searchParams', + { + input: '?a=b&c=d', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar?a=b&c=d', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '?a=b&c=d', + searchParams: 'a=b&c=d', + hash: '', + }, + { + input: '??a=b&c=d', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar??a=b&c=d', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '??a=b&c=d', + searchParams: '%3Fa=b&c=d', + hash: '', + }, + '# Scheme only', + { + input: 'http:', + base: 'http://example.org/foo/bar', + href: 'http://example.org/foo/bar', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/foo/bar', + search: '', + searchParams: '', + hash: '', + }, + { + input: 'http:', + base: 'https://example.org/foo/bar', + failure: true, + }, + { + input: 'sc:', + base: 'https://example.org/foo/bar', + href: 'sc:', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '', + search: '', + searchParams: '', + hash: '', + }, + '# Percent encoding of fragments', + { + input: 'http://foo.bar/baz?qux#foo\bbar', + base: 'about:blank', + href: 'http://foo.bar/baz?qux#foo%08bar', + origin: 'http://foo.bar', + protocol: 'http:', + username: '', + password: '', + host: 'foo.bar', + hostname: 'foo.bar', + port: '', + pathname: '/baz', + search: '?qux', + searchParams: 'qux=', + hash: '#foo%08bar', + }, + '# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)', + { + input: 'http://192.168.257', + base: 'http://other.com/', + href: 'http://192.168.1.1/', + origin: 'http://192.168.1.1', + protocol: 'http:', + username: '', + password: '', + host: '192.168.1.1', + hostname: '192.168.1.1', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://192.168.257.com', + base: 'http://other.com/', + href: 'http://192.168.257.com/', + origin: 'http://192.168.257.com', + protocol: 'http:', + username: '', + password: '', + host: '192.168.257.com', + hostname: '192.168.257.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://256', + base: 'http://other.com/', + href: 'http://0.0.1.0/', + origin: 'http://0.0.1.0', + protocol: 'http:', + username: '', + password: '', + host: '0.0.1.0', + hostname: '0.0.1.0', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://256.com', + base: 'http://other.com/', + href: 'http://256.com/', + origin: 'http://256.com', + protocol: 'http:', + username: '', + password: '', + host: '256.com', + hostname: '256.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://999999999', + base: 'http://other.com/', + href: 'http://59.154.201.255/', + origin: 'http://59.154.201.255', + protocol: 'http:', + username: '', + password: '', + host: '59.154.201.255', + hostname: '59.154.201.255', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://999999999.com', + base: 'http://other.com/', + href: 'http://999999999.com/', + origin: 'http://999999999.com', + protocol: 'http:', + username: '', + password: '', + host: '999999999.com', + hostname: '999999999.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://10000000000', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://10000000000.com', + base: 'http://other.com/', + href: 'http://10000000000.com/', + origin: 'http://10000000000.com', + protocol: 'http:', + username: '', + password: '', + host: '10000000000.com', + hostname: '10000000000.com', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://4294967295', + base: 'http://other.com/', + href: 'http://255.255.255.255/', + origin: 'http://255.255.255.255', + protocol: 'http:', + username: '', + password: '', + host: '255.255.255.255', + hostname: '255.255.255.255', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://4294967296', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://0xffffffff', + base: 'http://other.com/', + href: 'http://255.255.255.255/', + origin: 'http://255.255.255.255', + protocol: 'http:', + username: '', + password: '', + host: '255.255.255.255', + hostname: '255.255.255.255', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://0xffffffff1', + base: 'http://other.com/', + failure: true, + }, + { + input: 'http://256.256.256.256', + base: 'http://other.com/', + failure: true, + }, + { + input: 'https://0x.0x.0', + base: 'about:blank', + href: 'https://0.0.0.0/', + origin: 'https://0.0.0.0', + protocol: 'https:', + username: '', + password: '', + host: '0.0.0.0', + hostname: '0.0.0.0', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)', + { + input: 'https://0x100000000/test', + base: 'about:blank', + failure: true, + }, + { + input: 'https://256.0.0.1/test', + base: 'about:blank', + failure: true, + }, + "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", + { + input: 'file:///C%3A/', + base: 'about:blank', + href: 'file:///C%3A/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C%3A/', + search: '', + hash: '', + }, + { + input: 'file:///C%7C/', + base: 'about:blank', + href: 'file:///C%7C/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C%7C/', + search: '', + hash: '', + }, + '# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)', + { + input: 'pix/submit.gif', + base: 'file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html', + href: 'file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: + '/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif', + search: '', + hash: '', + }, + { + input: '..', + base: 'file:///C:/', + href: 'file:///C:/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: '..', + base: 'file:///', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + '# More file URL tests by zcorpan and annevk', + { + input: '/', + base: 'file:///C:/a/b', + href: 'file:///C:/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: '//d:', + base: 'file:///C:/a/b', + href: 'file:///d:', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/d:', + search: '', + hash: '', + }, + { + input: '//d:/..', + base: 'file:///C:/a/b', + href: 'file:///d:/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/d:/', + search: '', + hash: '', + }, + { + input: '..', + base: 'file:///ab:/', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '..', + base: 'file:///1:/', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '', + base: 'file:///test?test#test', + href: 'file:///test?test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?test', + hash: '', + }, + { + input: 'file:', + base: 'file:///test?test#test', + href: 'file:///test?test', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?test', + hash: '', + }, + { + input: '?x', + base: 'file:///test?test#test', + href: 'file:///test?x', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?x', + hash: '', + }, + { + input: 'file:?x', + base: 'file:///test?test#test', + href: 'file:///test?x', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?x', + hash: '', + }, + { + input: '#x', + base: 'file:///test?test#test', + href: 'file:///test?test#x', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?test', + hash: '#x', + }, + { + input: 'file:#x', + base: 'file:///test?test#test', + href: 'file:///test?test#x', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test', + search: '?test', + hash: '#x', + }, + '# File URLs and many (back)slashes', + { + input: 'file:\\\\//', + base: 'about:blank', + href: 'file:////', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '', + hash: '', + }, + { + input: 'file:\\\\\\\\', + base: 'about:blank', + href: 'file:////', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '', + hash: '', + }, + { + input: 'file:\\\\\\\\?fox', + base: 'about:blank', + href: 'file:////?fox', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '?fox', + hash: '', + }, + { + input: 'file:\\\\\\\\#guppy', + base: 'about:blank', + href: 'file:////#guppy', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '', + hash: '#guppy', + }, + { + input: 'file://spider///', + base: 'about:blank', + href: 'file://spider///', + protocol: 'file:', + username: '', + password: '', + host: 'spider', + hostname: 'spider', + port: '', + pathname: '///', + search: '', + hash: '', + }, + { + input: 'file:\\\\localhost//', + base: 'about:blank', + href: 'file:////', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '', + hash: '', + }, + { + input: 'file:///localhost//cat', + base: 'about:blank', + href: 'file:///localhost//cat', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/localhost//cat', + search: '', + hash: '', + }, + { + input: 'file://\\/localhost//cat', + base: 'about:blank', + href: 'file:////localhost//cat', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//localhost//cat', + search: '', + hash: '', + }, + { + input: 'file://localhost//a//../..//', + base: 'about:blank', + href: 'file://///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '///', + search: '', + hash: '', + }, + { + input: '/////mouse', + base: 'file:///elephant', + href: 'file://///mouse', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '///mouse', + search: '', + hash: '', + }, + { + input: '\\//pig', + base: 'file://lion/', + href: 'file:///pig', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/pig', + search: '', + hash: '', + }, + { + input: '\\/localhost//pig', + base: 'file://lion/', + href: 'file:////pig', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//pig', + search: '', + hash: '', + }, + { + input: '//localhost//pig', + base: 'file://lion/', + href: 'file:////pig', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//pig', + search: '', + hash: '', + }, + { + input: '/..//localhost//pig', + base: 'file://lion/', + href: 'file://lion//localhost//pig', + protocol: 'file:', + username: '', + password: '', + host: 'lion', + hostname: 'lion', + port: '', + pathname: '//localhost//pig', + search: '', + hash: '', + }, + { + input: 'file://', + base: 'file://ape/', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + '# File URLs with non-empty hosts', + { + input: '/rooibos', + base: 'file://tea/', + href: 'file://tea/rooibos', + protocol: 'file:', + username: '', + password: '', + host: 'tea', + hostname: 'tea', + port: '', + pathname: '/rooibos', + search: '', + hash: '', + }, + { + input: '/?chai', + base: 'file://tea/', + href: 'file://tea/?chai', + protocol: 'file:', + username: '', + password: '', + host: 'tea', + hostname: 'tea', + port: '', + pathname: '/', + search: '?chai', + hash: '', + }, + "# Windows drive letter handling with the 'file:' base URL", + { + input: 'C|', + base: 'file://host/dir/file', + href: 'file://host/C:', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:', + search: '', + hash: '', + }, + { + input: 'C|#', + base: 'file://host/dir/file', + href: 'file://host/C:#', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:', + search: '', + hash: '', + }, + { + input: 'C|?', + base: 'file://host/dir/file', + href: 'file://host/C:?', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:', + search: '', + hash: '', + }, + { + input: 'C|/', + base: 'file://host/dir/file', + href: 'file://host/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'C|\n/', + base: 'file://host/dir/file', + href: 'file://host/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'C|\\', + base: 'file://host/dir/file', + href: 'file://host/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'C', + base: 'file://host/dir/file', + href: 'file://host/dir/C', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/dir/C', + search: '', + hash: '', + }, + { + input: 'C|a', + base: 'file://host/dir/file', + href: 'file://host/dir/C|a', + protocol: 'file:', + username: '', + password: '', + host: 'host', + hostname: 'host', + port: '', + pathname: '/dir/C|a', + search: '', + hash: '', + }, + '# Windows drive letter quirk with not empty host', + { + input: 'file://example.net/C:/', + base: 'about:blank', + href: 'file://example.net/C:/', + protocol: 'file:', + username: '', + password: '', + host: 'example.net', + hostname: 'example.net', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'file://1.2.3.4/C:/', + base: 'about:blank', + href: 'file://1.2.3.4/C:/', + protocol: 'file:', + username: '', + password: '', + host: '1.2.3.4', + hostname: '1.2.3.4', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'file://[1::8]/C:/', + base: 'about:blank', + href: 'file://[1::8]/C:/', + protocol: 'file:', + username: '', + password: '', + host: '[1::8]', + hostname: '[1::8]', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + '# Windows drive letter quirk (no host)', + { + input: 'file:/C|/', + base: 'about:blank', + href: 'file:///C:/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + { + input: 'file://C|/', + base: 'about:blank', + href: 'file:///C:/', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/C:/', + search: '', + hash: '', + }, + '# file URLs without base URL by Rimas Misevičius', + { + input: 'file:', + base: 'about:blank', + href: 'file:///', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'file:?q=v', + base: 'about:blank', + href: 'file:///?q=v', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '?q=v', + hash: '', + }, + { + input: 'file:#frag', + base: 'about:blank', + href: 'file:///#frag', + protocol: 'file:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '#frag', + }, + '# IPv6 tests', + { + input: 'http://[1:0::]', + base: 'http://example.net/', + href: 'http://[1::]/', + origin: 'http://[1::]', + protocol: 'http:', + username: '', + password: '', + host: '[1::]', + hostname: '[1::]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://[0:1:2:3:4:5:6:7:8]', + base: 'http://example.net/', + failure: true, + }, + { + input: 'https://[0::0::0]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:.0]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:0:]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:1:2:3:4:5:6:7.0.0.0.1]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:1.00.0.0.0]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:1.290.0.0.0]', + base: 'about:blank', + failure: true, + }, + { + input: 'https://[0:1.23.23]', + base: 'about:blank', + failure: true, + }, + '# Empty host', + { + input: 'http://?', + base: 'about:blank', + failure: true, + }, + { + input: 'http://#', + base: 'about:blank', + failure: true, + }, + '# Non-special-URL path tests', + { + input: 'sc://ñ', + base: 'about:blank', + href: 'sc://%C3%B1', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '', + search: '', + hash: '', + }, + { + input: 'sc://ñ?x', + base: 'about:blank', + href: 'sc://%C3%B1?x', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '', + search: '?x', + hash: '', + }, + { + input: 'sc://ñ#x', + base: 'about:blank', + href: 'sc://%C3%B1#x', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '', + search: '', + hash: '#x', + }, + { + input: '#x', + base: 'sc://ñ', + href: 'sc://%C3%B1#x', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '', + search: '', + hash: '#x', + }, + { + input: '?x', + base: 'sc://ñ', + href: 'sc://%C3%B1?x', + origin: 'null', + protocol: 'sc:', + username: '', + password: '', + host: '%C3%B1', + hostname: '%C3%B1', + port: '', + pathname: '', + search: '?x', + hash: '', + }, + { + input: 'sc://?', + base: 'about:blank', + href: 'sc://?', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '', + search: '', + hash: '', + }, + { + input: 'sc://#', + base: 'about:blank', + href: 'sc://#', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '', + search: '', + hash: '', + }, + { + input: '///', + base: 'sc://x/', + href: 'sc:///', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: '////', + base: 'sc://x/', + href: 'sc:////', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//', + search: '', + hash: '', + }, + { + input: '////x/', + base: 'sc://x/', + href: 'sc:////x/', + protocol: 'sc:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '//x/', + search: '', + hash: '', + }, + { + input: 'tftp://foobar.com/someconfig;mode=netascii', + base: 'about:blank', + href: 'tftp://foobar.com/someconfig;mode=netascii', + origin: 'null', + protocol: 'tftp:', + username: '', + password: '', + host: 'foobar.com', + hostname: 'foobar.com', + port: '', + pathname: '/someconfig;mode=netascii', + search: '', + hash: '', + }, + { + input: 'telnet://user:pass@foobar.com:23/', + base: 'about:blank', + href: 'telnet://user:pass@foobar.com:23/', + origin: 'null', + protocol: 'telnet:', + username: 'user', + password: 'pass', + host: 'foobar.com:23', + hostname: 'foobar.com', + port: '23', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'ut2004://10.10.10.10:7777/Index.ut2', + base: 'about:blank', + href: 'ut2004://10.10.10.10:7777/Index.ut2', + origin: 'null', + protocol: 'ut2004:', + username: '', + password: '', + host: '10.10.10.10:7777', + hostname: '10.10.10.10', + port: '7777', + pathname: '/Index.ut2', + search: '', + hash: '', + }, + { + input: 'redis://foo:bar@somehost:6379/0?baz=bam&qux=baz', + base: 'about:blank', + href: 'redis://foo:bar@somehost:6379/0?baz=bam&qux=baz', + origin: 'null', + protocol: 'redis:', + username: 'foo', + password: 'bar', + host: 'somehost:6379', + hostname: 'somehost', + port: '6379', + pathname: '/0', + search: '?baz=bam&qux=baz', + hash: '', + }, + { + input: 'rsync://foo@host:911/sup', + base: 'about:blank', + href: 'rsync://foo@host:911/sup', + origin: 'null', + protocol: 'rsync:', + username: 'foo', + password: '', + host: 'host:911', + hostname: 'host', + port: '911', + pathname: '/sup', + search: '', + hash: '', + }, + { + input: 'git://github.com/foo/bar.git', + base: 'about:blank', + href: 'git://github.com/foo/bar.git', + origin: 'null', + protocol: 'git:', + username: '', + password: '', + host: 'github.com', + hostname: 'github.com', + port: '', + pathname: '/foo/bar.git', + search: '', + hash: '', + }, + { + input: 'irc://myserver.com:6999/channel?passwd', + base: 'about:blank', + href: 'irc://myserver.com:6999/channel?passwd', + origin: 'null', + protocol: 'irc:', + username: '', + password: '', + host: 'myserver.com:6999', + hostname: 'myserver.com', + port: '6999', + pathname: '/channel', + search: '?passwd', + hash: '', + }, + { + input: 'dns://fw.example.org:9999/foo.bar.org?type=TXT', + base: 'about:blank', + href: 'dns://fw.example.org:9999/foo.bar.org?type=TXT', + origin: 'null', + protocol: 'dns:', + username: '', + password: '', + host: 'fw.example.org:9999', + hostname: 'fw.example.org', + port: '9999', + pathname: '/foo.bar.org', + search: '?type=TXT', + hash: '', + }, + { + input: 'ldap://localhost:389/ou=People,o=JNDITutorial', + base: 'about:blank', + href: 'ldap://localhost:389/ou=People,o=JNDITutorial', + origin: 'null', + protocol: 'ldap:', + username: '', + password: '', + host: 'localhost:389', + hostname: 'localhost', + port: '389', + pathname: '/ou=People,o=JNDITutorial', + search: '', + hash: '', + }, + { + input: 'git+https://github.com/foo/bar', + base: 'about:blank', + href: 'git+https://github.com/foo/bar', + origin: 'null', + protocol: 'git+https:', + username: '', + password: '', + host: 'github.com', + hostname: 'github.com', + port: '', + pathname: '/foo/bar', + search: '', + hash: '', + }, + { + input: 'urn:ietf:rfc:2648', + base: 'about:blank', + href: 'urn:ietf:rfc:2648', + origin: 'null', + protocol: 'urn:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'ietf:rfc:2648', + search: '', + hash: '', + }, + { + input: 'tag:joe@example.org,2001:foo/bar', + base: 'about:blank', + href: 'tag:joe@example.org,2001:foo/bar', + origin: 'null', + protocol: 'tag:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'joe@example.org,2001:foo/bar', + search: '', + hash: '', + }, + '# percent encoded hosts in non-special-URLs', + { + input: 'non-special://%E2%80%A0/', + base: 'about:blank', + href: 'non-special://%E2%80%A0/', + protocol: 'non-special:', + username: '', + password: '', + host: '%E2%80%A0', + hostname: '%E2%80%A0', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'non-special://H%4fSt/path', + base: 'about:blank', + href: 'non-special://H%4fSt/path', + protocol: 'non-special:', + username: '', + password: '', + host: 'H%4fSt', + hostname: 'H%4fSt', + port: '', + pathname: '/path', + search: '', + hash: '', + }, + '# IPv6 in non-special-URLs', + { + input: 'non-special://[1:2:0:0:5:0:0:0]/', + base: 'about:blank', + href: 'non-special://[1:2:0:0:5::]/', + protocol: 'non-special:', + username: '', + password: '', + host: '[1:2:0:0:5::]', + hostname: '[1:2:0:0:5::]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'non-special://[1:2:0:0:0:0:0:3]/', + base: 'about:blank', + href: 'non-special://[1:2::3]/', + protocol: 'non-special:', + username: '', + password: '', + host: '[1:2::3]', + hostname: '[1:2::3]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'non-special://[1:2::3]:80/', + base: 'about:blank', + href: 'non-special://[1:2::3]:80/', + protocol: 'non-special:', + username: '', + password: '', + host: '[1:2::3]:80', + hostname: '[1:2::3]', + port: '80', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'non-special://[:80/', + base: 'about:blank', + failure: true, + }, + { + input: 'blob:https://example.com:443/', + base: 'about:blank', + href: 'blob:https://example.com:443/', + origin: 'https://example.com', + protocol: 'blob:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'https://example.com:443/', + search: '', + hash: '', + }, + { + input: 'blob:d3958f5c-0777-0845-9dcf-2cb28783acaf', + base: 'about:blank', + href: 'blob:d3958f5c-0777-0845-9dcf-2cb28783acaf', + protocol: 'blob:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: 'd3958f5c-0777-0845-9dcf-2cb28783acaf', + search: '', + hash: '', + }, + 'Invalid IPv4 radix digits', + { + input: 'http://0x7f.0.0.0x7g', + base: 'about:blank', + href: 'http://0x7f.0.0.0x7g/', + origin: 'http://0x7f.0.0.0x7g', + protocol: 'http:', + username: '', + password: '', + host: '0x7f.0.0.0x7g', + hostname: '0x7f.0.0.0x7g', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://0X7F.0.0.0X7G', + base: 'about:blank', + href: 'http://0x7f.0.0.0x7g/', + origin: 'http://0x7f.0.0.0x7g', + protocol: 'http:', + username: '', + password: '', + host: '0x7f.0.0.0x7g', + hostname: '0x7f.0.0.0x7g', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Invalid IPv4 portion of IPv6 address', + { + input: 'http://[::127.0.0.0.1]', + base: 'about:blank', + failure: true, + }, + 'Uncompressed IPv6 addresses with 0', + { + input: 'http://[0:1:0:1:0:1:0:1]', + base: 'about:blank', + href: 'http://[0:1:0:1:0:1:0:1]/', + origin: 'http://[0:1:0:1:0:1:0:1]', + protocol: 'http:', + username: '', + password: '', + host: '[0:1:0:1:0:1:0:1]', + hostname: '[0:1:0:1:0:1:0:1]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + { + input: 'http://[1:0:1:0:1:0:1:0]', + base: 'about:blank', + href: 'http://[1:0:1:0:1:0:1:0]/', + origin: 'http://[1:0:1:0:1:0:1:0]', + protocol: 'http:', + username: '', + password: '', + host: '[1:0:1:0:1:0:1:0]', + hostname: '[1:0:1:0:1:0:1:0]', + port: '', + pathname: '/', + search: '', + hash: '', + }, + 'Percent-encoded query and fragment', + { + input: 'http://example.org/test?\u0022', + base: 'about:blank', + href: 'http://example.org/test?%22', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%22', + hash: '', + }, + { + input: 'http://example.org/test?\u0023', + base: 'about:blank', + href: 'http://example.org/test?#', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '', + hash: '', + }, + { + input: 'http://example.org/test?\u003C', + base: 'about:blank', + href: 'http://example.org/test?%3C', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%3C', + hash: '', + }, + { + input: 'http://example.org/test?\u003E', + base: 'about:blank', + href: 'http://example.org/test?%3E', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%3E', + hash: '', + }, + { + input: 'http://example.org/test?\u2323', + base: 'about:blank', + href: 'http://example.org/test?%E2%8C%A3', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%E2%8C%A3', + hash: '', + }, + { + input: 'http://example.org/test?%23%23', + base: 'about:blank', + href: 'http://example.org/test?%23%23', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%23%23', + hash: '', + }, + { + input: 'http://example.org/test?%GH', + base: 'about:blank', + href: 'http://example.org/test?%GH', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?%GH', + hash: '', + }, + { + input: 'http://example.org/test?a#%EF', + base: 'about:blank', + href: 'http://example.org/test?a#%EF', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?a', + hash: '#%EF', + }, + { + input: 'http://example.org/test?a#%GH', + base: 'about:blank', + href: 'http://example.org/test?a#%GH', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?a', + hash: '#%GH', + }, + 'Bad bases', + { + input: 'test-a.html', + base: 'a', + failure: true, + }, + { + input: 'test-a-slash.html', + base: 'a/', + failure: true, + }, + { + input: 'test-a-slash-slash.html', + base: 'a//', + failure: true, + }, + { + input: 'test-a-colon.html', + base: 'a:', + failure: true, + }, + { + input: 'test-a-colon-slash.html', + base: 'a:/', + href: 'a:/test-a-colon-slash.html', + protocol: 'a:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test-a-colon-slash.html', + search: '', + hash: '', + }, + { + input: 'test-a-colon-slash-slash.html', + base: 'a://', + href: 'a:///test-a-colon-slash-slash.html', + protocol: 'a:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test-a-colon-slash-slash.html', + search: '', + hash: '', + }, + { + input: 'test-a-colon-b.html', + base: 'a:b', + failure: true, + }, + { + input: 'test-a-colon-slash-b.html', + base: 'a:/b', + href: 'a:/test-a-colon-slash-b.html', + protocol: 'a:', + username: '', + password: '', + host: '', + hostname: '', + port: '', + pathname: '/test-a-colon-slash-b.html', + search: '', + hash: '', + }, + { + input: 'test-a-colon-slash-slash-b.html', + base: 'a://b', + href: 'a://b/test-a-colon-slash-slash-b.html', + protocol: 'a:', + username: '', + password: '', + host: 'b', + hostname: 'b', + port: '', + pathname: '/test-a-colon-slash-slash-b.html', + search: '', + hash: '', + }, + 'Null code point in fragment', + { + input: 'http://example.org/test?a#b\u0000c', + base: 'about:blank', + href: 'http://example.org/test?a#b%00c', + origin: 'http://example.org', + protocol: 'http:', + username: '', + password: '', + host: 'example.org', + hostname: 'example.org', + port: '', + pathname: '/test', + search: '?a', + hash: '#b%00c', + }, + ]; + + cases.forEach((test) => { + if (typeof test === 'string') return; + if (test.failure) { + throws(() => { + new URL(test.input, test.base || 'about:blank'); + }); + return; + } + const url = new URL(test.input, test.base || 'about:blank'); + strictEqual(url.href, test.href); + strictEqual(url.protocol, test.protocol); + strictEqual(url.username, test.username); + strictEqual(url.password, test.password); + strictEqual(url.host, test.host); + strictEqual(url.hostname, test.hostname); + strictEqual(url.port, test.port); + strictEqual(url.pathname, test.pathname); + strictEqual(url.search, test.search); + if ('searchParams' in test) { + strictEqual(url.searchParams.toString(), test.searchParams); + } + strictEqual(url.hash, test.hash); + if (test.origin == null) { + strictEqual(url.origin, 'null'); + } else { + strictEqual(url.origin, test.origin); + } + }); + }, +}; + +export const urlSetterTests = { + test() { + const cases = { + protocol: [ + { + comment: + 'The empty string is not a valid scheme. Setter leaves the URL unchanged.', + href: 'a://example.net', + new_value: '', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + href: 'a://example.net', + new_value: 'b', + expected: { + href: 'b://example.net', + protocol: 'b:', + }, + }, + { + href: 'javascript:alert(1)', + new_value: 'defuse', + expected: { + href: 'defuse:alert(1)', + protocol: 'defuse:', + }, + }, + { + comment: 'Upper-case ASCII is lower-cased', + href: 'a://example.net', + new_value: 'B', + expected: { + href: 'b://example.net', + protocol: 'b:', + }, + }, + { + comment: 'Non-ASCII is rejected', + href: 'a://example.net', + new_value: 'é', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + comment: 'No leading digit', + href: 'a://example.net', + new_value: '0b', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + comment: 'No leading punctuation', + href: 'a://example.net', + new_value: '+b', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + href: 'a://example.net', + new_value: 'bC0+-.', + expected: { + href: 'bc0+-.://example.net', + protocol: 'bc0+-.:', + }, + }, + { + comment: 'Only some punctuation is acceptable', + href: 'a://example.net', + new_value: 'b,c', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + comment: 'Non-ASCII is rejected', + href: 'a://example.net', + new_value: 'bé', + expected: { + href: 'a://example.net', + protocol: 'a:', + }, + }, + { + comment: + 'Can’t switch from URL containing username/password/port to file', + href: 'http://test@example.net', + new_value: 'file', + expected: { + href: 'http://test@example.net/', + protocol: 'http:', + }, + }, + { + href: 'gopher://example.net:1234', + new_value: 'file', + expected: { + href: 'gopher://example.net:1234', + protocol: 'gopher:', + }, + }, + { + href: 'wss://x:x@example.net:1234', + new_value: 'file', + expected: { + href: 'wss://x:x@example.net:1234/', + protocol: 'wss:', + }, + }, + { + comment: 'Can’t switch from file URL with no host', + href: 'file://localhost/', + new_value: 'http', + expected: { + href: 'file:///', + protocol: 'file:', + }, + }, + { + href: 'file:///test', + new_value: 'gopher', + expected: { + href: 'file:///test', + protocol: 'file:', + }, + }, + { + href: 'file:', + new_value: 'wss', + expected: { + href: 'file:///', + protocol: 'file:', + }, + }, + { + comment: 'Can’t switch from special scheme to non-special', + href: 'http://example.net', + new_value: 'b', + expected: { + href: 'http://example.net/', + protocol: 'http:', + }, + }, + { + href: 'file://hi/path', + new_value: 's', + expected: { + href: 'file://hi/path', + protocol: 'file:', + }, + }, + { + href: 'https://example.net', + new_value: 's', + expected: { + href: 'https://example.net/', + protocol: 'https:', + }, + }, + { + href: 'ftp://example.net', + new_value: 'test', + expected: { + href: 'ftp://example.net/', + protocol: 'ftp:', + }, + }, + { + comment: + 'Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.', + href: 'mailto:me@example.net', + new_value: 'http', + expected: { + href: 'mailto:me@example.net', + protocol: 'mailto:', + }, + }, + { + comment: 'Can’t switch from non-special scheme to special', + href: 'ssh://me@example.net', + new_value: 'http', + expected: { + href: 'ssh://me@example.net', + protocol: 'ssh:', + }, + }, + { + href: 'ssh://me@example.net', + new_value: 'gopher', + expected: { + href: 'gopher://me@example.net', + protocol: 'gopher:', + }, + }, + { + href: 'ssh://me@example.net', + new_value: 'file', + expected: { + href: 'ssh://me@example.net', + protocol: 'ssh:', + }, + }, + { + href: 'ssh://example.net', + new_value: 'file', + expected: { + href: 'ssh://example.net', + protocol: 'ssh:', + }, + }, + { + href: 'nonsense:///test', + new_value: 'https', + expected: { + href: 'nonsense:///test', + protocol: 'nonsense:', + }, + }, + { + comment: "Stuff after the first ':' is ignored", + href: 'http://example.net', + new_value: 'https:foo : bar', + expected: { + href: 'https://example.net/', + protocol: 'https:', + }, + }, + { + comment: "Stuff after the first ':' is ignored", + href: 'data:text/html,

Test', + new_value: 'view-source+data:foo : bar', + expected: { + href: 'view-source+data:text/html,

Test', + protocol: 'view-source+data:', + }, + }, + { + comment: 'Port is set to null if it is the default for new scheme.', + href: 'http://foo.com:443/', + new_value: 'https', + expected: { + href: 'https://foo.com/', + protocol: 'https:', + port: '', + }, + }, + ], + username: [ + { + comment: 'No host means no username', + href: 'file:///home/you/index.html', + new_value: 'me', + expected: { + href: 'file:///home/you/index.html', + username: '', + }, + }, + { + comment: 'No host means no username', + href: 'unix:/run/foo.socket', + new_value: 'me', + expected: { + href: 'unix:/run/foo.socket', + username: '', + }, + }, + { + comment: 'Cannot-be-a-base means no username', + href: 'mailto:you@example.net', + new_value: 'me', + expected: { + href: 'mailto:you@example.net', + username: '', + }, + }, + { + href: 'javascript:alert(1)', + new_value: 'wario', + expected: { + href: 'javascript:alert(1)', + username: '', + }, + }, + { + href: 'http://example.net', + new_value: 'me', + expected: { + href: 'http://me@example.net/', + username: 'me', + }, + }, + { + href: 'http://:secret@example.net', + new_value: 'me', + expected: { + href: 'http://me:secret@example.net/', + username: 'me', + }, + }, + { + href: 'http://me@example.net', + new_value: '', + expected: { + href: 'http://example.net/', + username: '', + }, + }, + { + href: 'http://me:secret@example.net', + new_value: '', + expected: { + href: 'http://:secret@example.net/', + username: '', + }, + }, + { + comment: 'UTF-8 percent encoding with the userinfo encode set.', + href: 'http://example.net', + new_value: + '\u0000\u0001\t\n\r\u001f !"#$%&\'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé', + expected: { + href: "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + username: + "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + }, + }, + { + comment: 'Bytes already percent-encoded are left as-is.', + href: 'http://example.net', + new_value: '%c3%89té', + expected: { + href: 'http://%c3%89t%C3%A9@example.net/', + username: '%c3%89t%C3%A9', + }, + }, + { + href: 'sc:///', + new_value: 'x', + expected: { + href: 'sc:///', + username: '', + }, + }, + { + href: 'javascript://x/', + new_value: 'wario', + expected: { + href: 'javascript://wario@x/', + username: 'wario', + }, + }, + { + href: 'file://test/', + new_value: 'test', + expected: { + href: 'file://test/', + username: '', + }, + }, + ], + password: [ + { + comment: 'No host means no password', + href: 'file:///home/me/index.html', + new_value: 'secret', + expected: { + href: 'file:///home/me/index.html', + password: '', + }, + }, + { + comment: 'No host means no password', + href: 'unix:/run/foo.socket', + new_value: 'secret', + expected: { + href: 'unix:/run/foo.socket', + password: '', + }, + }, + { + comment: 'Cannot-be-a-base means no password', + href: 'mailto:me@example.net', + new_value: 'secret', + expected: { + href: 'mailto:me@example.net', + password: '', + }, + }, + { + href: 'http://example.net', + new_value: 'secret', + expected: { + href: 'http://:secret@example.net/', + password: 'secret', + }, + }, + { + href: 'http://me@example.net', + new_value: 'secret', + expected: { + href: 'http://me:secret@example.net/', + password: 'secret', + }, + }, + { + href: 'http://:secret@example.net', + new_value: '', + expected: { + href: 'http://example.net/', + password: '', + }, + }, + { + href: 'http://me:secret@example.net', + new_value: '', + expected: { + href: 'http://me@example.net/', + password: '', + }, + }, + { + comment: 'UTF-8 percent encoding with the userinfo encode set.', + href: 'http://example.net', + new_value: + '\u0000\u0001\t\n\r\u001f !"#$%&\'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé', + expected: { + href: "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + password: + "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + }, + }, + { + comment: 'Bytes already percent-encoded are left as-is.', + href: 'http://example.net', + new_value: '%c3%89té', + expected: { + href: 'http://:%c3%89t%C3%A9@example.net/', + password: '%c3%89t%C3%A9', + }, + }, + { + href: 'sc:///', + new_value: 'x', + expected: { + href: 'sc:///', + password: '', + }, + }, + { + href: 'javascript://x/', + new_value: 'bowser', + expected: { + href: 'javascript://:bowser@x/', + password: 'bowser', + }, + }, + { + href: 'file://test/', + new_value: 'test', + expected: { + href: 'file://test/', + password: '', + }, + }, + ], + host: [ + { + comment: 'Non-special scheme', + href: 'sc://x/', + new_value: '\u0000', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + href: 'sc://x/', + new_value: '\u0009', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '\u000A', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '\u000D', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: ' ', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + href: 'sc://x/', + new_value: '#', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '/', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '?', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '@', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + href: 'sc://x/', + new_value: 'ß', + expected: { + href: 'sc://%C3%9F/', + host: '%C3%9F', + hostname: '%C3%9F', + }, + }, + { + comment: 'IDNA Nontransitional_Processing', + href: 'https://x/', + new_value: 'ß', + expected: { + href: 'https://xn--zca/', + host: 'xn--zca', + hostname: 'xn--zca', + }, + }, + { + comment: 'Cannot-be-a-base means no host', + href: 'mailto:me@example.net', + new_value: 'example.com', + expected: { + href: 'mailto:me@example.net', + host: '', + }, + }, + { + comment: 'Cannot-be-a-base means no password', + href: 'data:text/plain,Stuff', + new_value: 'example.net', + expected: { + href: 'data:text/plain,Stuff', + host: '', + }, + }, + { + href: 'http://example.net', + new_value: 'example.com:8080', + expected: { + href: 'http://example.com:8080/', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Port number is unchanged if not specified in the new value', + href: 'http://example.net:8080', + new_value: 'example.com', + expected: { + href: 'http://example.com:8080/', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Port number is unchanged if not specified', + href: 'http://example.net:8080', + new_value: 'example.com:', + expected: { + href: 'http://example.com:8080/', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'The empty host is not valid for special schemes', + href: 'http://example.net', + new_value: '', + expected: { + href: 'http://example.net/', + host: 'example.net', + }, + }, + { + comment: 'The empty host is OK for non-special schemes', + href: 'view-source+http://example.net/foo', + new_value: '', + expected: { + href: 'view-source+http:///foo', + host: '', + }, + }, + { + comment: 'Path-only URLs can gain a host', + href: 'a:/foo', + new_value: 'example.net', + expected: { + href: 'a://example.net/foo', + host: 'example.net', + }, + }, + { + comment: 'IPv4 address syntax is normalized', + href: 'http://example.net', + new_value: '0x7F000001:8080', + expected: { + href: 'http://127.0.0.1:8080/', + host: '127.0.0.1:8080', + hostname: '127.0.0.1', + port: '8080', + }, + }, + { + comment: 'IPv6 address syntax is normalized', + href: 'http://example.net', + new_value: '[::0:01]:2', + expected: { + href: 'http://[::1]:2/', + host: '[::1]:2', + hostname: '[::1]', + port: '2', + }, + }, + { + comment: 'Default port number is removed', + href: 'http://example.net', + new_value: 'example.com:80', + expected: { + href: 'http://example.com/', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Default port number is removed', + href: 'https://example.net', + new_value: 'example.com:443', + expected: { + href: 'https://example.com/', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: + 'Default port number is only removed for the relevant scheme', + href: 'https://example.net', + new_value: 'example.com:80', + expected: { + href: 'https://example.com:80/', + host: 'example.com:80', + hostname: 'example.com', + port: '80', + }, + }, + { + comment: 'Stuff after a / delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com/stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a / delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com:8080/stuff', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Stuff after a ? delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com?stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a ? delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com:8080?stuff', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Stuff after a # delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com#stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a # delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com:8080#stuff', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Stuff after a \\ delimiter is ignored for special schemes', + href: 'http://example.net/path', + new_value: 'example.com\\stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a \\ delimiter is ignored for special schemes', + href: 'http://example.net/path', + new_value: 'example.com:8080\\stuff', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: + '\\ is not a delimiter for non-special schemes, but still forbidden in hosts', + href: 'view-source+http://example.net/path', + new_value: 'example.com\\stuff', + expected: { + href: 'view-source+http://example.net/path', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'view-source+http://example.net/path', + new_value: 'example.com:8080stuff2', + expected: { + href: 'view-source+http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'http://example.net/path', + new_value: 'example.com:8080stuff2', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'http://example.net/path', + new_value: 'example.com:8080+2', + expected: { + href: 'http://example.com:8080/path', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'Port numbers are 16 bit integers', + href: 'http://example.net/path', + new_value: 'example.com:65535', + expected: { + href: 'http://example.com:65535/path', + host: 'example.com:65535', + hostname: 'example.com', + port: '65535', + }, + }, + { + comment: + 'Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.', + href: 'http://example.net/path', + new_value: 'example.com:65536', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Broken IPv6', + href: 'http://example.net/', + new_value: '[google.com]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.3.4x]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.3.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'file://y/', + new_value: 'x:123', + expected: { + href: 'file://y/', + host: 'y', + hostname: 'y', + port: '', + }, + }, + { + href: 'file://y/', + new_value: 'loc%41lhost', + expected: { + href: 'file:///', + host: '', + hostname: '', + port: '', + }, + }, + { + href: 'file://hi/x', + new_value: '', + expected: { + href: 'file:///x', + host: '', + hostname: '', + port: '', + }, + }, + { + href: 'sc://test@test/', + new_value: '', + expected: { + href: 'sc://test@test/', + host: 'test', + hostname: 'test', + username: 'test', + }, + }, + { + href: 'sc://test:12/', + new_value: '', + expected: { + href: 'sc://test:12/', + host: 'test:12', + hostname: 'test', + port: '12', + }, + }, + ], + + hostname: [ + { + comment: 'Non-special scheme', + href: 'sc://x/', + new_value: '\u0000', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + href: 'sc://x/', + new_value: '\u0009', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '\u000A', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '\u000D', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: ' ', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + href: 'sc://x/', + new_value: '#', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '/', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '?', + expected: { + href: 'sc:///', + host: '', + hostname: '', + }, + }, + { + href: 'sc://x/', + new_value: '@', + expected: { + href: 'sc://x/', + host: 'x', + hostname: 'x', + }, + }, + { + comment: 'Cannot-be-a-base means no host', + href: 'mailto:me@example.net', + new_value: 'example.com', + expected: { + href: 'mailto:me@example.net', + host: '', + hostname: '', + }, + }, + { + comment: 'Cannot-be-a-base means no password', + href: 'data:text/plain,Stuff', + new_value: 'example.net', + expected: { + href: 'data:text/plain,Stuff', + host: '', + hostname: '', + }, + }, + { + href: 'http://example.net:8080', + new_value: 'example.com', + expected: { + href: 'http://example.com:8080/', + host: 'example.com:8080', + hostname: 'example.com', + port: '8080', + }, + }, + { + comment: 'The empty host is not valid for special schemes', + href: 'http://example.net', + new_value: '', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + comment: 'The empty host is OK for non-special schemes', + href: 'view-source+http://example.net/foo', + new_value: '', + expected: { + href: 'view-source+http:///foo', + host: '', + hostname: '', + }, + }, + { + comment: 'Path-only URLs can gain a host', + href: 'a:/foo', + new_value: 'example.net', + expected: { + href: 'a://example.net/foo', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + comment: 'IPv4 address syntax is normalized', + href: 'http://example.net:8080', + new_value: '0x7F000001', + expected: { + href: 'http://127.0.0.1:8080/', + host: '127.0.0.1:8080', + hostname: '127.0.0.1', + port: '8080', + }, + }, + { + comment: 'IPv6 address syntax is normalized', + href: 'http://example.net', + new_value: '[::0:01]', + expected: { + href: 'http://[::1]/', + host: '[::1]', + hostname: '[::1]', + port: '', + }, + }, + { + comment: ': delimiter invalidates entire value', + href: 'http://example.net/path', + new_value: 'example.com:8080', + expected: { + href: 'http://example.net/path', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: ': delimiter invalidates entire value', + href: 'http://example.net:8080/path', + new_value: 'example.com:', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Stuff after a / delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com/stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a ? delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com?stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a # delimiter is ignored', + href: 'http://example.net/path', + new_value: 'example.com#stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: 'Stuff after a \\ delimiter is ignored for special schemes', + href: 'http://example.net/path', + new_value: 'example.com\\stuff', + expected: { + href: 'http://example.com/path', + host: 'example.com', + hostname: 'example.com', + port: '', + }, + }, + { + comment: + '\\ is not a delimiter for non-special schemes, but still forbidden in hosts', + href: 'view-source+http://example.net/path', + new_value: 'example.com\\stuff', + expected: { + href: 'view-source+http://example.net/path', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: 'Broken IPv6', + href: 'http://example.net/', + new_value: '[google.com]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.3.4x]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.3.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.2.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'http://example.net/', + new_value: '[::1.]', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + }, + }, + { + href: 'file://y/', + new_value: 'x:123', + expected: { + href: 'file://y/', + host: 'y', + hostname: 'y', + port: '', + }, + }, + { + href: 'file://y/', + new_value: 'loc%41lhost', + expected: { + href: 'file:///', + host: '', + hostname: '', + port: '', + }, + }, + { + href: 'file://hi/x', + new_value: '', + expected: { + href: 'file:///x', + host: '', + hostname: '', + port: '', + }, + }, + { + href: 'sc://test@test/', + new_value: '', + expected: { + href: 'sc://test@test/', + host: 'test', + hostname: 'test', + username: 'test', + }, + }, + { + href: 'sc://test:12/', + new_value: '', + expected: { + href: 'sc://test:12/', + host: 'test:12', + hostname: 'test', + port: '12', + }, + }, + ], + port: [ + { + href: 'http://example.net', + new_value: '8080', + expected: { + href: 'http://example.net:8080/', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Port number is removed if empty is the new value', + href: 'http://example.net:8080', + new_value: '', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: 'Default port number is removed', + href: 'http://example.net:8080', + new_value: '80', + expected: { + href: 'http://example.net/', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: 'Default port number is removed', + href: 'https://example.net:4433', + new_value: '443', + expected: { + href: 'https://example.net/', + host: 'example.net', + hostname: 'example.net', + port: '', + }, + }, + { + comment: + 'Default port number is only removed for the relevant scheme', + href: 'https://example.net', + new_value: '80', + expected: { + href: 'https://example.net:80/', + host: 'example.net:80', + hostname: 'example.net', + port: '80', + }, + }, + { + comment: 'Stuff after a / delimiter is ignored', + href: 'http://example.net/path', + new_value: '8080/stuff', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Stuff after a ? delimiter is ignored', + href: 'http://example.net/path', + new_value: '8080?stuff', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Stuff after a # delimiter is ignored', + href: 'http://example.net/path', + new_value: '8080#stuff', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Stuff after a \\ delimiter is ignored for special schemes', + href: 'http://example.net/path', + new_value: '8080\\stuff', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'view-source+http://example.net/path', + new_value: '8080stuff2', + expected: { + href: 'view-source+http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'http://example.net/path', + new_value: '8080stuff2', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: + 'Anything other than ASCII digit stops the port parser in a setter but is not an error', + href: 'http://example.net/path', + new_value: '8080+2', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Port numbers are 16 bit integers', + href: 'http://example.net/path', + new_value: '65535', + expected: { + href: 'http://example.net:65535/path', + host: 'example.net:65535', + hostname: 'example.net', + port: '65535', + }, + }, + { + comment: 'Port numbers are 16 bit integers, overflowing is an error', + href: 'http://example.net:8080/path', + new_value: '65536', + expected: { + href: 'http://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + comment: 'Port numbers are 16 bit integers, overflowing is an error', + href: 'non-special://example.net:8080/path', + new_value: '65536', + expected: { + href: 'non-special://example.net:8080/path', + host: 'example.net:8080', + hostname: 'example.net', + port: '8080', + }, + }, + { + href: 'file://test/', + new_value: '12', + expected: { + href: 'file://test/', + port: '', + }, + }, + { + href: 'file://localhost/', + new_value: '12', + expected: { + href: 'file:///', + port: '', + }, + }, + { + href: 'non-base:value', + new_value: '12', + expected: { + href: 'non-base:value', + port: '', + }, + }, + { + href: 'sc:///', + new_value: '12', + expected: { + href: 'sc:///', + port: '', + }, + }, + { + href: 'sc://x/', + new_value: '12', + expected: { + href: 'sc://x:12/', + port: '12', + }, + }, + { + href: 'javascript://x/', + new_value: '12', + expected: { + href: 'javascript://x:12/', + port: '12', + }, + }, + ], + pathname: [ + { + comment: 'Cannot-be-a-base don’t have a path', + href: 'mailto:me@example.net', + new_value: '/foo', + expected: { + href: 'mailto:me@example.net', + pathname: 'me@example.net', + }, + }, + { + href: 'unix:/run/foo.socket?timeout=10', + new_value: '/var/log/../run/bar.socket', + expected: { + href: 'unix:/var/run/bar.socket?timeout=10', + pathname: '/var/run/bar.socket', + }, + }, + { + href: 'https://example.net#nav', + new_value: 'home', + expected: { + href: 'https://example.net/home#nav', + pathname: '/home', + }, + }, + { + href: 'https://example.net#nav', + new_value: '../home', + expected: { + href: 'https://example.net/home#nav', + pathname: '/home', + }, + }, + { + comment: "\\ is a segment delimiter for 'special' URLs", + href: 'http://example.net/home?lang=fr#nav', + new_value: '\\a\\%2E\\b\\%2e.\\c', + expected: { + href: 'http://example.net/a/c?lang=fr#nav', + pathname: '/a/c', + }, + }, + { + comment: "\\ is *not* a segment delimiter for non-'special' URLs", + href: 'view-source+http://example.net/home?lang=fr#nav', + new_value: '\\a\\%2E\\b\\%2e.\\c', + expected: { + href: 'view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav', + pathname: '/\\a\\%2E\\b\\%2e.\\c', + }, + }, + { + comment: + 'UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.', + href: 'a:/', + new_value: + '\u0000\u0001\t\n\r\u001f !"#$%&\'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé', + expected: { + href: "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + pathname: + "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + }, + }, + { + comment: + 'Bytes already percent-encoded are left as-is, including %2E outside dotted segments.', + href: 'http://example.net', + new_value: '%2e%2E%c3%89té', + expected: { + href: 'http://example.net/%2e%2E%c3%89t%C3%A9', + pathname: '/%2e%2E%c3%89t%C3%A9', + }, + }, + { + comment: '? needs to be encoded', + href: 'http://example.net', + new_value: '?', + expected: { + href: 'http://example.net/%3F', + pathname: '/%3F', + }, + }, + { + comment: '# needs to be encoded', + href: 'http://example.net', + new_value: '#', + expected: { + href: 'http://example.net/%23', + pathname: '/%23', + }, + }, + { + comment: '? needs to be encoded, non-special scheme', + href: 'sc://example.net', + new_value: '?', + expected: { + href: 'sc://example.net/%3F', + pathname: '/%3F', + }, + }, + { + comment: '# needs to be encoded, non-special scheme', + href: 'sc://example.net', + new_value: '#', + expected: { + href: 'sc://example.net/%23', + pathname: '/%23', + }, + }, + { + comment: 'File URLs and (back)slashes', + href: 'file://monkey/', + new_value: '\\\\', + expected: { + href: 'file://monkey//', + pathname: '//', + }, + }, + { + comment: 'File URLs and (back)slashes', + href: 'file:///unicorn', + new_value: '//\\/', + expected: { + href: 'file://////', + pathname: '////', + }, + }, { - 'href': 'https://example.com/', - 'new_value': 'http', - 'expected': { - 'href': 'http://example.com/' + comment: 'File URLs and (back)slashes', + href: 'file:///unicorn', + new_value: '//monkey/..//', + expected: { + href: 'file://///', + pathname: '///', }, - 'comment': 'Setting scheme on URL with null port does not change port' }, + ], + search: [ { - 'href': 'https://example.com:80/', - 'new_value': 'http', - 'expected': { - 'href': 'http://example.com/' + href: 'https://example.net#nav', + new_value: 'lang=fr', + expected: { + href: 'https://example.net/?lang=fr#nav', + search: '?lang=fr', }, - 'comment': 'Setting scheme on URL with port that is the new scheme-default port nulls out port' }, { - 'href': 'https://example.com:1234/', - 'new_value': 'http', - 'expected': { - 'href': 'http://example.com:1234/' + href: 'https://example.net?lang=en-US#nav', + new_value: 'lang=fr', + expected: { + href: 'https://example.net/?lang=fr#nav', + search: '?lang=fr', + }, + }, + { + href: 'https://example.net?lang=en-US#nav', + new_value: '?lang=fr', + expected: { + href: 'https://example.net/?lang=fr#nav', + search: '?lang=fr', + }, + }, + { + href: 'https://example.net?lang=en-US#nav', + new_value: '??lang=fr', + expected: { + href: 'https://example.net/??lang=fr#nav', + search: '??lang=fr', + }, + }, + { + href: 'https://example.net?lang=en-US#nav', + new_value: '?', + expected: { + href: 'https://example.net/?#nav', + search: '', + }, + }, + { + href: 'https://example.net?lang=en-US#nav', + new_value: '', + expected: { + href: 'https://example.net/#nav', + search: '', }, - 'comment': 'Setting scheme on URL with non-scheme-default port preserves port' }, - ], - 'search': [ - { - 'href': 'https://capnproto.org/', - 'new_value': '#', - 'expected': { - 'href': 'https://capnproto.org/?%23', - 'search': '?%23' - } - }, - { - 'href': 'https://capnproto.org/', - 'new_value': '#=#', - 'expected': { - 'href': 'https://capnproto.org/?%23=%23', - 'search': '?%23=%23' - } - } - ], - 'host': [ { - 'href': 'https://example.com/', - 'new_value': 'foo.example.com:', - 'expected': { - 'href': 'https://foo.example.com/' + href: 'https://example.net?lang=en-US', + new_value: '', + expected: { + href: 'https://example.net/', + search: '', }, - 'comment': 'Setting host with ":" but no port ignores port' }, { - 'href': 'https://example.com/', - 'new_value': 'foo.example.com:80', - 'expected': { - 'href': 'https://foo.example.com:80/' + href: 'https://example.net', + new_value: '', + expected: { + href: 'https://example.net/', + search: '', }, - 'comment': 'Setting host with non-scheme-default port sets port' }, { - 'href': 'https://example.com:1234/', - 'new_value': 'foo.example.com:443', - 'expected': { - 'href': 'https://foo.example.com/' + comment: + 'UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.', + href: 'a:/', + new_value: + '\u0000\u0001\t\n\r\u001f !"#$%&\'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé', + expected: { + href: "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + search: + "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", }, - 'comment': 'Setting host with scheme-default port nulls out port' }, { - 'href': 'https://example.com/', - 'new_value': 'foo.example.com:443', - 'expected': { - 'href': 'https://foo.example.com/' + comment: 'Bytes already percent-encoded are left as-is', + href: 'http://example.net', + new_value: '%c3%89té', + expected: { + href: 'http://example.net/?%c3%89t%C3%A9', + search: '?%c3%89t%C3%A9', }, - 'comment': 'Setting host with scheme-default port nulls out port' }, ], - 'port': [ + hash: [ { - 'href': 'https://example.com/', - 'new_value': '443', - 'expected': { - 'href': 'https://example.com/' + href: 'https://example.net', + new_value: 'main', + expected: { + href: 'https://example.net/#main', + hash: '#main', }, - 'comment': 'Setting port to scheme-default port is a no-op' }, { - 'href': 'https://example.com:1234/', - 'new_value': '443', - 'expected': { - 'href': 'https://example.com/' + href: 'https://example.net#nav', + new_value: 'main', + expected: { + href: 'https://example.net/#main', + hash: '#main', }, - 'comment': 'Setting port to scheme-default port nulls out port' }, { - 'href': 'https://example.com/', - 'new_value': '1234', - 'expected': { - 'href': 'https://example.com:1234/' + href: 'https://example.net?lang=en-US', + new_value: '##nav', + expected: { + href: 'https://example.net/?lang=en-US##nav', + hash: '##nav', }, - 'comment': 'Setting port to non-scheme-default port adopts port' }, { - 'href': 'https://example.com:80/', - 'new_value': '1234', - 'expected': { - 'href': 'https://example.com:1234/' + href: 'https://example.net?lang=en-US#nav', + new_value: '#main', + expected: { + href: 'https://example.net/?lang=en-US#main', + hash: '#main', }, - 'comment': 'Setting port to non-scheme-default port adopts port' }, { - 'href': 'https://example.com:1234/', - 'new_value': '', - 'expected': { - 'href': 'https://example.com/' + href: 'https://example.net?lang=en-US#nav', + new_value: '#', + expected: { + href: 'https://example.net/?lang=en-US#', + hash: '', }, - 'comment': 'Setting port to the empty string nulls out port' }, - ], - 'hostname': [ { - 'href': 'http://example.com/path/to/something?query=foo#hash', - 'new_value': 'newexample.com', - 'expected': { - 'href': 'http://newexample.com/path/to/something?query=foo#hash' - } - } - ] - }; - - for (const attribute in cases) { - cases[attribute].forEach((test) => { - const url = new URL(test.href); - url[attribute] = test.new_value; - for (const a in test.expected) { - strictEqual(url[a], test.expected[a], `${test.href}: ${test.comment}`); - } - }); - } - } -}; - -export const urlSearchParamsStringifyBehavior = { - test() { - const url = new URL('https://example.com/?foo&bar=&baz=qux'); - strictEqual(url.href,'https://example.com/?foo&bar=&baz=qux'); - strictEqual(url.search, '?foo&bar=&baz=qux'); - strictEqual(url.searchParams.toString(), 'foo=&bar=&baz=qux'); - } -}; - -export const urlSearchParamsForEach = { - test() { - let searchParams = new URLSearchParams(''); - searchParams.forEach(() => { - fail('Should not have been called'); - }); - - const foreachOutput = []; - searchParams = new URLSearchParams('key1=value1&key2=value2'); - strictEqual(searchParams.size, 2); - let pushed = false; - searchParams.forEach((val, key) => { - foreachOutput.push([key,val]); - if (!pushed) { - // We can add params within this loop but it's not really safe - // because it will cause the loop to run forever if we're not - // careful. - pushed = true; - searchParams.set('key3', 'value3'); - } - }); - deepStrictEqual(foreachOutput, [['key1','value1'], - ['key2','value2'], - ['key3','value3']]); - strictEqual(searchParams.size, 3); - - // Calling forEach with no argument throws - throws(() => searchParams.forEach()); - - // Calling forEach with wrong arguments throws - throws(() => searchParams.forEach(1)); - - // This can be overridden by the second argument - searchParams.forEach(function() { - strictEqual(this, 1); - }, 1); - - // Propagates errors - throws(() => searchParams.forEach(() => { - throw new Error('boom'); - })); - } -}; - -export const urlSearchParamsInit1 = { - test() { - const search1 = new URLSearchParams('a=b'); - const search2 = new URLSearchParams(search1); - strictEqual(search1.toString(), search2.toString()); - } -}; - -export const urlSearchParamsInit2 = { - test() { - const search1 = new URLSearchParams('a=b'); - search1[Symbol.iterator] = function* () { - yield ['y', 'z']; - }; - const search2 = new URLSearchParams(search1); - ok(!search2.has('a')); - ok(search2.has('y')); - strictEqual(search2.get('y'), 'z'); - } -}; - -export const urlSearchParamsInit3 = { - test() { - // If the initializer has a deleted iterator, then it's - // contents are ignored but can still be interpreted as - // a dictionary. - const search1 = new URLSearchParams('a=b'); - search1[Symbol.iterator] = undefined; - search1.y = 'z'; - const search2 = new URLSearchParams(search1); - ok(!search2.has('a')); - ok(search2.has('y')); - strictEqual(search2.get('y'), 'z'); - } -}; - -export const urlSearchParamsInit4 = { - test() { - const formdata = new FormData(); - formdata.append('a', 'b'); - ok(formdata.has('a')); - const search2 = new URLSearchParams(formdata); - ok(search2.has('a')); - strictEqual(search2.get('a'), 'b'); - } -}; - -export const urlSearchParamsInit5 = { - test() { - const formdata = new FormData(); - formdata.append('a', 'b'); - formdata[Symbol.iterator] = undefined; - const search2 = new URLSearchParams(formdata); - ok(!search2.has('a')); - } -}; - -export const urlToJson = { - test() { - const url = new URL('https://example.com'); - strictEqual(JSON.stringify(url), '\"https://example.com/\"'); - } -}; - -export const urlSearchParamsSet = { - test() { - const url = new URL('https://example.com?c=d'); - url.searchParams.set('a', 'b'); - strictEqual(url.searchParams.size, 2); - url.searchParams.delete('c'); - strictEqual(url.searchParams.size, 1); - ok(url.searchParams.has('a')); - ok(!url.searchParams.has('c')); - ok(url.searchParams.has('a', 'b')); - ok(!url.searchParams.has('a', 'c')); - url.searchParams.delete('a', 'c'); - ok(url.searchParams.has('a')); - } -}; - -export const urlConstructorTests = { - test() { - const cases = [ - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", - { - "input": "http://example\t.\norg", - "base": "http://example.org/foo/bar", - "href": "http://example.org/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "C|/", - "base": "file://host/dir/file", - "href": "file://host/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C|\n/", - "base": "file://host/dir/file", - "href": "file://host/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "https://:@test", - "base": "about:blank", - "href": "https://test/", - "origin": "https://test", - "protocol": "https:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://test:@test/x", - "base": "about:blank", - "href": "non-special://test@test/x", - "origin": "null", - "protocol": "non-special:", - "username": "test", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - { - "input": "non-special://:@test/x", - "base": "about:blank", - "href": "non-special://test/x", - "origin": "null", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - { - "input": "http:foo.com", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/foo.com", - "search": "", - "hash": "" - }, - { - "input": "\t :foo.com \n", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com", - "search": "", - "hash": "" - }, - { - "input": " foo.com ", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/foo.com", - "search": "", - "hash": "" - }, - { - "input": "a:\t foo.com", - "base": "http://example.org/foo/bar", - "href": "a: foo.com", - "origin": "null", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": " foo.com", - "search": "", - "hash": "" - }, - { - "input": "http://f:21/ b ? d # e ", - "base": "http://example.org/foo/bar", - "href": "http://f:21/%20b%20?%20d%20#%20e", - "origin": "http://f:21", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:21", - "hostname": "f", - "port": "21", - "pathname": "/%20b%20", - "search": "?%20d%20", - "hash": "#%20e" - }, - { - "input": "lolscheme:x x#x x", - "base": "about:blank", - "href": "lolscheme:x x#x%20x", - "protocol": "lolscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "x x", - "search": "", - "hash": "#x%20x" - }, - { - "input": "http://f:/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:0/c", - "base": "http://example.org/foo/bar", - "href": "http://f:0/c", - "origin": "http://f:0", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:0", - "hostname": "f", - "port": "0", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:00000000000000/c", - "base": "http://example.org/foo/bar", - "href": "http://f:0/c", - "origin": "http://f:0", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:0", - "hostname": "f", - "port": "0", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:00000000000000000000080/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:b/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f: /c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f:\n/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:fifty-two/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f:999999/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "non-special://f:999999/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f: 21 / b ? d # e ", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": " \t", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": ":foo.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com/", - "search": "", - "hash": "" - }, - { - "input": ":foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com/", - "search": "", - "hash": "" - }, - { - "input": ":", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:", - "search": "", - "hash": "" - }, - { - "input": ":a", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:a", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:a", - "search": "", - "hash": "" - }, - { - "input": ":/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:/", - "search": "", - "hash": "" - }, - { - "input": ":\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:/", - "search": "", - "hash": "" - }, - { - "input": ":#", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:#", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:", - "search": "", - "hash": "" - }, - { - "input": "#", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "#/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#/" - }, - { - "input": "#\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#\\", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#\\" - }, - { - "input": "#;?", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#;?", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#;?" - }, - { - "input": "?", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar?", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": ":23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:23", - "search": "", - "hash": "" - }, - { - "input": "/:23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/:23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/:23", - "search": "", - "hash": "" - }, - { - "input": "::", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/::", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/::", - "search": "", - "hash": "" - }, - { - "input": "::23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/::23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/::23", - "search": "", - "hash": "" - }, - { - "input": "foo://", - "base": "http://example.org/foo/bar", - "href": "foo://", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "http://a:b@c:29/d", - "base": "http://example.org/foo/bar", - "href": "http://a:b@c:29/d", - "origin": "http://c:29", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "c:29", - "hostname": "c", - "port": "29", - "pathname": "/d", - "search": "", - "hash": "" - }, - { - "input": "http::@c:29", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:@c:29", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:@c:29", - "search": "", - "hash": "" - }, - { - "input": "http://&a:foo(b]c@d:2/", - "base": "http://example.org/foo/bar", - "href": "http://&a:foo(b%5Dc@d:2/", - "origin": "http://d:2", - "protocol": "http:", - "username": "&a", - "password": "foo(b%5Dc", - "host": "d:2", - "hostname": "d", - "port": "2", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://::@c@d:2", - "base": "http://example.org/foo/bar", - "href": "http://:%3A%40c@d:2/", - "origin": "http://d:2", - "protocol": "http:", - "username": "", - "password": "%3A%40c", - "host": "d:2", - "hostname": "d", - "port": "2", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo.com:b@d/", - "base": "http://example.org/foo/bar", - "href": "http://foo.com:b@d/", - "origin": "http://d", - "protocol": "http:", - "username": "foo.com", - "password": "b", - "host": "d", - "hostname": "d", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo.com/\\@", - "base": "http://example.org/foo/bar", - "href": "http://foo.com//@", - "origin": "http://foo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.com", - "hostname": "foo.com", - "port": "", - "pathname": "//@", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://foo.com/", - "origin": "http://foo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.com", - "hostname": "foo.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\a\\b:c\\d@foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://a/b:c/d@foo.com/", - "origin": "http://a", - "protocol": "http:", - "username": "", - "password": "", - "host": "a", - "hostname": "a", - "port": "", - "pathname": "/b:c/d@foo.com/", - "search": "", - "hash": "" - }, - { - "input": "foo:/", - "base": "http://example.org/foo/bar", - "href": "foo:/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "foo:/bar.com/", - "base": "http://example.org/foo/bar", - "href": "foo:/bar.com/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/bar.com/", - "search": "", - "hash": "" - }, - { - "input": "foo://///////", - "base": "http://example.org/foo/bar", - "href": "foo://///////", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///////", - "search": "", - "hash": "" - }, - { - "input": "foo://///////bar.com/", - "base": "http://example.org/foo/bar", - "href": "foo://///////bar.com/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///////bar.com/", - "search": "", - "hash": "" - }, - { - "input": "foo:////://///", - "base": "http://example.org/foo/bar", - "href": "foo:////://///", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//://///", - "search": "", - "hash": "" - }, - { - "input": "c:/foo", - "base": "http://example.org/foo/bar", - "href": "c:/foo", - "origin": "null", - "protocol": "c:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "//foo/bar", - "base": "http://example.org/foo/bar", - "href": "http://foo/bar", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/bar", - "search": "", - "hash": "" - }, - { - "input": "http://foo/path;a??e#f#g", - "base": "http://example.org/foo/bar", - "href": "http://foo/path;a??e#f#g", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/path;a", - "search": "??e", - "hash": "#f#g" - }, - { - "input": "http://foo/abcd?efgh?ijkl", - "base": "http://example.org/foo/bar", - "href": "http://foo/abcd?efgh?ijkl", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/abcd", - "search": "?efgh?ijkl", - "hash": "" - }, - { - "input": "http://foo/abcd#foo?bar", - "base": "http://example.org/foo/bar", - "href": "http://foo/abcd#foo?bar", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/abcd", - "search": "", - "hash": "#foo?bar" - }, - { - "input": "[61:24:74]:98", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/[61:24:74]:98", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/[61:24:74]:98", - "search": "", - "hash": "" - }, - { - "input": "http:[61:27]/:foo", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/[61:27]/:foo", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/[61:27]/:foo", - "search": "", - "hash": "" - }, - { - "input": "http://[1::2]:3:4", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1]", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1]:80", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://[2001::1]", - "base": "http://example.org/foo/bar", - "href": "http://[2001::1]/", - "origin": "http://[2001::1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[2001::1]", - "hostname": "[2001::1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[::127.0.0.1]", - "base": "http://example.org/foo/bar", - "href": "http://[::7f00:1]/", - "origin": "http://[::7f00:1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[::7f00:1]", - "hostname": "[::7f00:1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[0:0:0:0:0:0:13.1.68.3]", - "base": "http://example.org/foo/bar", - "href": "http://[::d01:4403]/", - "origin": "http://[::d01:4403]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[::d01:4403]", - "hostname": "[::d01:4403]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[2001::1]:80", - "base": "http://example.org/foo/bar", - "href": "http://[2001::1]/", - "origin": "http://[2001::1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[2001::1]", - "hostname": "[2001::1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/example.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/example.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftp:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:/example.com/", - "base": "http://example.org/foo/bar", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:/example.com/", - "base": "http://example.org/foo/bar", - "href": "madeupscheme:/example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file:/example.com/", - "base": "http://example.org/foo/bar", - "href": "file:///example.com/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file://example:1/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://example:test/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://example%/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://[example]/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftps:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ftps:/example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:/example.com/", - "base": "http://example.org/foo/bar", - "href": "gopher:/example.com/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ws:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:/example.com/", - "base": "http://example.org/foo/bar", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/example.com/", - "base": "http://example.org/foo/bar", - "href": "data:/example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/example.com/", - "base": "http://example.org/foo/bar", - "href": "javascript:/example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/example.com/", - "base": "http://example.org/foo/bar", - "href": "mailto:/example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "http:example.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/example.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftp:example.com/", - "base": "http://example.org/foo/bar", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:example.com/", - "base": "http://example.org/foo/bar", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:example.com/", - "base": "http://example.org/foo/bar", - "href": "madeupscheme:example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:example.com/", - "base": "http://example.org/foo/bar", - "href": "ftps:example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:example.com/", - "base": "http://example.org/foo/bar", - "href": "gopher:example.com/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ws:example.com/", - "base": "http://example.org/foo/bar", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:example.com/", - "base": "http://example.org/foo/bar", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:example.com/", - "base": "http://example.org/foo/bar", - "href": "data:example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:example.com/", - "base": "http://example.org/foo/bar", - "href": "javascript:example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:example.com/", - "base": "http://example.org/foo/bar", - "href": "mailto:example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "/a/b/c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/b/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/b/c", - "search": "", - "hash": "" - }, - { - "input": "/a/ /c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/%20/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/%20/c", - "search": "", - "hash": "" - }, - { - "input": "/a%2fc", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a%2fc", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a%2fc", - "search": "", - "hash": "" - }, - { - "input": "/a/%2f/c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/%2f/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/%2f/c", - "search": "", - "hash": "" - }, - { - "input": "#β", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#%CE%B2", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#%CE%B2" - }, - { - "input": "data:text/html,test#test", - "base": "http://example.org/foo/bar", - "href": "data:text/html,test#test", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "text/html,test", - "search": "", - "hash": "#test" - }, - { - "input": "tel:1234567890", - "base": "http://example.org/foo/bar", - "href": "tel:1234567890", - "origin": "null", - "protocol": "tel:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "1234567890", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", - { - "input": "file:c:\\foo\\bar.html", - "base": "file:///tmp/mock/path", - "href": "file:///c:/foo/bar.html", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar.html", - "search": "", - "hash": "" - }, - { - "input": " File:c|////foo\\bar.html", - "base": "file:///tmp/mock/path", - "href": "file:///c:////foo/bar.html", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:////foo/bar.html", - "search": "", - "hash": "" - }, - { - "input": "C|/foo/bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/C|\\foo\\bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "//C|/foo/bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "//server/file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "\\\\server\\file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "/\\server/file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "file:///foo/bar.txt", - "base": "file:///tmp/mock/path", - "href": "file:///foo/bar.txt", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/foo/bar.txt", - "search": "", - "hash": "" - }, - { - "input": "file:///home/me", - "base": "file:///tmp/mock/path", - "href": "file:///home/me", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/home/me", - "search": "", - "hash": "" - }, - { - "input": "//", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "///", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "///test", - "base": "file:///tmp/mock/path", - "href": "file:///test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "file://test", - "base": "file:///tmp/mock/path", - "href": "file://test/", - "protocol": "file:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost/", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost/test", - "base": "file:///tmp/mock/path", - "href": "file:///test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "test", - "base": "file:///tmp/mock/path", - "href": "file:///tmp/mock/test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/tmp/mock/test", - "search": "", - "hash": "" - }, - { - "input": "file:test", - "base": "file:///tmp/mock/path", - "href": "file:///tmp/mock/test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/tmp/mock/test", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", - { - "input": "http://example.com/././foo", - "base": "about:blank", - "href": "http://example.com/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/./.foo", - "base": "about:blank", - "href": "http://example.com/.foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/.foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/.", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/./", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/..", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/..bar", - "base": "about:blank", - "href": "http://example.com/foo/..bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/..bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../ton", - "base": "about:blank", - "href": "http://example.com/foo/ton", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/ton", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../ton/../../a", - "base": "about:blank", - "href": "http://example.com/a", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/a", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/../../..", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/../../../ton", - "base": "about:blank", - "href": "http://example.com/ton", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/ton", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e%2", - "base": "about:blank", - "href": "http://example.com/foo/%2e%2", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/%2e%2", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", - "base": "about:blank", - "href": "http://example.com/%2e.bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%2e.bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com////../..", - "base": "about:blank", - "href": "http://example.com//", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar//../..", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar//..", - "base": "about:blank", - "href": "http://example.com/foo/bar/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/bar/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo", - "base": "about:blank", - "href": "http://example.com/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%20foo", - "base": "about:blank", - "href": "http://example.com/%20foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%20foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%", - "base": "about:blank", - "href": "http://example.com/foo%", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2", - "base": "about:blank", - "href": "http://example.com/foo%2", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2zbar", - "base": "about:blank", - "href": "http://example.com/foo%2zbar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2zbar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2©zbar", - "base": "about:blank", - "href": "http://example.com/foo%2%C3%82%C2%A9zbar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2%C3%82%C2%A9zbar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%41%7a", - "base": "about:blank", - "href": "http://example.com/foo%41%7a", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%41%7a", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo\t\u0091%91", - "base": "about:blank", - "href": "http://example.com/foo%C2%91%91", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%C2%91%91", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%00%51", - "base": "about:blank", - "href": "http://example.com/foo%00%51", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%00%51", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/(%28:%3A%29)", - "base": "about:blank", - "href": "http://example.com/(%28:%3A%29)", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/(%28:%3A%29)", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%3A%3a%3C%3c", - "base": "about:blank", - "href": "http://example.com/%3A%3a%3C%3c", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%3A%3a%3C%3c", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo\tbar", - "base": "about:blank", - "href": "http://example.com/foobar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foobar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com\\\\foo\\\\bar", - "base": "about:blank", - "href": "http://example.com//foo//bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "//foo//bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", - "base": "about:blank", - "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%7Ffp3%3Eju%3Dduvgw%3Dd", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/@asdf%40", - "base": "about:blank", - "href": "http://example.com/@asdf%40", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/@asdf%40", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/你好你好", - "base": "about:blank", - "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/‥/foo", - "base": "about:blank", - "href": "http://example.com/%E2%80%A5/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E2%80%A5/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com//foo", - "base": "about:blank", - "href": "http://example.com/%EF%BB%BF/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%EF%BB%BF/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/‮/foo/‭/bar", - "base": "about:blank", - "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E2%80%AE/foo/%E2%80%AD/bar", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", - { - "input": "http://www.google.com/foo?bar=baz#", - "base": "about:blank", - "href": "http://www.google.com/foo?bar=baz#", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "?bar=baz", - "hash": "" - }, - { - "input": "http://www.google.com/foo?bar=baz# »", - "base": "about:blank", - "href": "http://www.google.com/foo?bar=baz#%20%C2%BB", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "?bar=baz", - "hash": "#%20%C2%BB" - }, - { - "input": "data:test# »", - "base": "about:blank", - "href": "data:test#%20%C2%BB", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "", - "hash": "#%20%C2%BB" - }, - { - "input": "http://www.google.com", - "base": "about:blank", - "href": "http://www.google.com/", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.0x00A80001", - "base": "about:blank", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://www/foo%2Ehtml", - "base": "about:blank", - "href": "http://www/foo%2Ehtml", - "origin": "http://www", - "protocol": "http:", - "username": "", - "password": "", - "host": "www", - "hostname": "www", - "port": "", - "pathname": "/foo%2Ehtml", - "search": "", - "hash": "" - }, - { - "input": "http://www/foo/%2E/html", - "base": "about:blank", - "href": "http://www/foo/html", - "origin": "http://www", - "protocol": "http:", - "username": "", - "password": "", - "host": "www", - "hostname": "www", - "port": "", - "pathname": "/foo/html", - "search": "", - "hash": "" - }, - { - "input": "http://user:pass@/", - "base": "about:blank", - "failure": true - }, - { - "input": "http://%25DOMAIN:foobar@foodomain.com/", - "base": "about:blank", - "href": "http://%25DOMAIN:foobar@foodomain.com/", - "origin": "http://foodomain.com", - "protocol": "http:", - "username": "%25DOMAIN", - "password": "foobar", - "host": "foodomain.com", - "hostname": "foodomain.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\www.google.com\\foo", - "base": "about:blank", - "href": "http://www.google.com/foo", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://foo:80/", - "base": "about:blank", - "href": "http://foo/", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo:81/", - "base": "about:blank", - "href": "http://foo:81/", - "origin": "http://foo:81", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "httpa://foo:80/", - "base": "about:blank", - "href": "httpa://foo:80/", - "origin": "null", - "protocol": "httpa:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo:-80/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://foo:443/", - "base": "about:blank", - "href": "https://foo/", - "origin": "https://foo", - "protocol": "https:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://foo:80/", - "base": "about:blank", - "href": "https://foo:80/", - "origin": "https://foo:80", - "protocol": "https:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp://foo:21/", - "base": "about:blank", - "href": "ftp://foo/", - "origin": "ftp://foo", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp://foo:80/", - "base": "about:blank", - "href": "ftp://foo:80/", - "origin": "ftp://foo:80", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "gopher://foo:70/", - "base": "about:blank", - "href": "gopher://foo:70/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "foo:70", - "hostname": "foo", - "port": "70", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "gopher://foo:443/", - "base": "about:blank", - "href": "gopher://foo:443/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "foo:443", - "hostname": "foo", - "port": "443", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:80/", - "base": "about:blank", - "href": "ws://foo/", - "origin": "ws://foo", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:81/", - "base": "about:blank", - "href": "ws://foo:81/", - "origin": "ws://foo:81", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:443/", - "base": "about:blank", - "href": "ws://foo:443/", - "origin": "ws://foo:443", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:443", - "hostname": "foo", - "port": "443", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:815/", - "base": "about:blank", - "href": "ws://foo:815/", - "origin": "ws://foo:815", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:815", - "hostname": "foo", - "port": "815", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:80/", - "base": "about:blank", - "href": "wss://foo:80/", - "origin": "wss://foo:80", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:81/", - "base": "about:blank", - "href": "wss://foo:81/", - "origin": "wss://foo:81", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:443/", - "base": "about:blank", - "href": "wss://foo/", - "origin": "wss://foo", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:815/", - "base": "about:blank", - "href": "wss://foo:815/", - "origin": "wss://foo:815", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:815", - "hostname": "foo", - "port": "815", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/example.com/", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp:/example.com/", - "base": "about:blank", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:/example.com/", - "base": "about:blank", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:/example.com/", - "base": "about:blank", - "href": "madeupscheme:/example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file:/example.com/", - "base": "about:blank", - "href": "file:///example.com/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:/example.com/", - "base": "about:blank", - "href": "ftps:/example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:/example.com/", - "base": "about:blank", - "href": "gopher:/example.com/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ws:/example.com/", - "base": "about:blank", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:/example.com/", - "base": "about:blank", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/example.com/", - "base": "about:blank", - "href": "data:/example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/example.com/", - "base": "about:blank", - "href": "javascript:/example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/example.com/", - "base": "about:blank", - "href": "mailto:/example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "http:example.com/", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp:example.com/", - "base": "about:blank", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:example.com/", - "base": "about:blank", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:example.com/", - "base": "about:blank", - "href": "madeupscheme:example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:example.com/", - "base": "about:blank", - "href": "ftps:example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:example.com/", - "base": "about:blank", - "href": "gopher:example.com/", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ws:example.com/", - "base": "about:blank", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:example.com/", - "base": "about:blank", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:example.com/", - "base": "about:blank", - "href": "data:example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:example.com/", - "base": "about:blank", - "href": "javascript:example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:example.com/", - "base": "about:blank", - "href": "mailto:example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", - { - "input": "http:@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://@pple.com", - "base": "about:blank", - "href": "http://pple.com/", - "origin": "http://pple.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "pple.com", - "hostname": "pple.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http::b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/:b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://:b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://user@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "https:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http::@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://www.@pple.com", - "base": "about:blank", - "href": "http://www.@pple.com/", - "origin": "http://pple.com", - "protocol": "http:", - "username": "www.", - "password": "", - "host": "pple.com", - "hostname": "pple.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://:@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# Others", - { - "input": "/", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": ".", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "./test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../aaa/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/aaa/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/aaa/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../../test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "中/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/%E4%B8%AD/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/%E4%B8%AD/test.txt", - "search": "", - "hash": "" - }, - { - "input": "http://www.example2.com", - "base": "http://www.example.com/test", - "href": "http://www.example2.com/", - "origin": "http://www.example2.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example2.com", - "hostname": "www.example2.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "//www.example2.com", - "base": "http://www.example.com/test", - "href": "http://www.example2.com/", - "origin": "http://www.example2.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example2.com", - "hostname": "www.example2.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:...", - "base": "http://www.example.com/test", - "href": "file:///...", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/...", - "search": "", - "hash": "" - }, - { - "input": "file:..", - "base": "http://www.example.com/test", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:a", - "base": "http://www.example.com/test", - "href": "file:///a", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/a", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html", - "Basic canonicalization, uppercase should be converted to lowercase", - { - "input": "http://ExAmPlE.CoM", - "base": "http://other.com/", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://example example.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://Goo%20 goo%7C|.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[:]", - "base": "http://other.com/", - "failure": true - }, - "U+3000 is mapped to U+0020 (space) which is disallowed", - { - "input": "http://GOO\u00a0\u3000goo.com", - "base": "http://other.com/", - "failure": true - }, - "Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored", - { - "input": "http://GOO\u200b\u2060\ufeffgoo.com", - "base": "http://other.com/", - "href": "http://googoo.com/", - "origin": "http://googoo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "googoo.com", - "hostname": "googoo.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Leading and trailing C0 control or space", - { - "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", - { - "input": "http://www.foo。bar.com", - "base": "http://other.com/", - "href": "http://www.foo.bar.com/", - "origin": "http://www.foo.bar.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.foo.bar.com", - "hostname": "www.foo.bar.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0", - { - "input": "http://\ufdd0zyx.com", - "base": "http://other.com/", - "failure": true - }, - "This is the same as previous but escaped", - { - "input": "http://%ef%b7%90zyx.com", - "base": "http://other.com/", - "failure": true - }, - "U+FFFD", - { - "input": "https://\ufffd", - "base": "about:blank", - "failure": true - }, - { - "input": "https://%EF%BF%BD", - "base": "about:blank", - "failure": true - }, - { - "input": "https://x/\ufffd?\ufffd#\ufffd", - "base": "about:blank", - "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", - "origin": "https://x", - "protocol": "https:", - "username": "", - "password": "", - "host": "x", - "hostname": "x", - "port": "", - "pathname": "/%EF%BF%BD", - "search": "?%EF%BF%BD", - "hash": "#%EF%BF%BD" - }, - "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", - { - "input": "http://Go.com", - "base": "http://other.com/", - "href": "http://go.com/", - "origin": "http://go.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "go.com", - "hostname": "go.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257", - { - "input": "http://%41.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://%ef%bc%85%ef%bc%94%ef%bc%91.com", - "base": "http://other.com/", - "failure": true - }, - "...%00 in fullwidth should fail (also as escaped UTF-8 input)", - { - "input": "http://%00.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://%ef%bc%85%ef%bc%90%ef%bc%90.com", - "base": "http://other.com/", - "failure": true - }, - "Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN", - { - "input": "http://你好你好", - "base": "http://other.com/", - "href": "http://xn--6qqa088eba/", - "origin": "http://xn--6qqa088eba", - "protocol": "http:", - "username": "", - "password": "", - "host": "xn--6qqa088eba", - "hostname": "xn--6qqa088eba", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://faß.ExAmPlE/", - "base": "about:blank", - "href": "https://xn--fa-hia.example/", - "origin": "https://xn--fa-hia.example", - "protocol": "https:", - "username": "", - "password": "", - "host": "xn--fa-hia.example", - "hostname": "xn--fa-hia.example", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://faß.ExAmPlE/", - "base": "about:blank", - "href": "sc://fa%C3%9F.ExAmPlE/", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "fa%C3%9F.ExAmPlE", - "hostname": "fa%C3%9F.ExAmPlE", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", - { - "input": "http://%zz%66%a.com", - "base": "http://other.com/", - "failure": true - }, - "If we get an invalid character that has been escaped.", - { - "input": "http://%25", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://hello%00", - "base": "http://other.com/", - "failure": true - }, - "Escaped numbers should be treated like IP addresses if they are.", - { - "input": "http://%30%78%63%30%2e%30%32%35%30.01", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://%30%78%63%30%2e%30%32%35%30.01%2e", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.168.0.257", - "base": "http://other.com/", - "failure": true - }, - "Invalid escaping in hosts causes failure", - { - "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01", - "base": "http://other.com/", - "failure": true - }, - "A space in a host causes failure", - { - "input": "http://192.168.0.1 hello", - "base": "http://other.com/", - "failure": true - }, - { - "input": "https://x x:12", - "base": "about:blank", - "failure": true - }, - "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", - { - "input": "http://0Xc0.0250.01", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Domains with empty labels", - { - "input": "http://./", - "base": "about:blank", - "href": "http://./", - "origin": "http://.", - "protocol": "http:", - "username": "", - "password": "", - "host": ".", - "hostname": ".", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://../", - "base": "about:blank", - "href": "http://../", - "origin": "http://..", - "protocol": "http:", - "username": "", - "password": "", - "host": "..", - "hostname": "..", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Broken IPv6", - { - "input": "http://[www.google.com]/", - "base": "about:blank", - "failure": true - }, - { - "input": "http://[google.com]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.3.4x]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.3.]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.]", - "base": "http://other.com/", - "failure": true - }, - "Misc Unicode", - { - "input": "http://foo:💩@example.com/bar", - "base": "http://other.com/", - "href": "http://foo:%F0%9F%92%A9@example.com/bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "foo", - "password": "%F0%9F%92%A9", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/bar", - "search": "", - "hash": "" - }, - "# resolving a fragment against any scheme succeeds", - { - "input": "#", - "base": "test:test", - "href": "test:test#", - "origin": "null", - "protocol": "test:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "", - "hash": "" - }, - { - "input": "#x", - "base": "mailto:x@x.com", - "href": "mailto:x@x.com#x", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "x@x.com", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "data:,", - "href": "data:,#x", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": ",", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "about:blank", - "href": "about:blank#x", - "origin": "null", - "protocol": "about:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "blank", - "search": "", - "hash": "#x" - }, - { - "input": "#", - "base": "test:test?test", - "href": "test:test?test#", - "origin": "null", - "protocol": "test:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "?test", - "hash": "" - }, - "# multiple @ in authority state", - { - "input": "https://@test@test@example:800/", - "base": "http://doesnotmatter/", - "href": "https://%40test%40test@example:800/", - "origin": "https://example:800", - "protocol": "https:", - "username": "%40test%40test", - "password": "", - "host": "example:800", - "hostname": "example", - "port": "800", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://@@@example", - "base": "http://doesnotmatter/", - "href": "https://%40%40@example/", - "origin": "https://example", - "protocol": "https:", - "username": "%40%40", - "password": "", - "host": "example", - "hostname": "example", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "non-az-09 characters", - { - "input": "http://`{}:`{}@h/`{}?`{}", - "base": "http://doesnotmatter/", - "href": "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}", - "origin": "http://h", - "protocol": "http:", - "username": "%60%7B%7D", - "password": "%60%7B%7D", - "host": "h", - "hostname": "h", - "port": "", - "pathname": "/%60%7B%7D", - "search": "?`{}", - "hash": "" - }, - "# Credentials in base", - { - "input": "/some/path", - "base": "http://user@example.org/smth", - "href": "http://user@example.org/some/path", - "origin": "http://example.org", - "protocol": "http:", - "username": "user", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/some/path", - "search": "", - "hash": "" - }, - { - "input": "", - "base": "http://user:pass@example.org:21/smth", - "href": "http://user:pass@example.org:21/smth", - "origin": "http://example.org:21", - "protocol": "http:", - "username": "user", - "password": "pass", - "host": "example.org:21", - "hostname": "example.org", - "port": "21", - "pathname": "/smth", - "search": "", - "hash": "" - }, - { - "input": "/some/path", - "base": "http://user:pass@example.org:21/smth", - "href": "http://user:pass@example.org:21/some/path", - "origin": "http://example.org:21", - "protocol": "http:", - "username": "user", - "password": "pass", - "host": "example.org:21", - "hostname": "example.org", - "port": "21", - "pathname": "/some/path", - "search": "", - "hash": "" - }, - "# a set of tests designed by zcorpan for relative URLs with unknown schemes", - { - "input": "i", - "base": "sc:sd", - "failure": true - }, - { - "input": "i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "i", - "base": "sc:/pa/pa", - "href": "sc:/pa/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/i", - "search": "", - "hash": "" - }, - { - "input": "i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "i", - "base": "sc:///pa/pa", - "href": "sc:///pa/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc:sd", - "failure": true - }, - { - "input": "../i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "../i", - "base": "sc:/pa/pa", - "href": "sc:/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc:///pa/pa", - "href": "sc:///i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc:sd", - "failure": true - }, - { - "input": "/i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "/i", - "base": "sc:/pa/pa", - "href": "sc:/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc:///pa/pa", - "href": "sc:///i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "?i", - "base": "sc:sd", - "failure": true - }, - { - "input": "?i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "?i", - "base": "sc:/pa/pa", - "href": "sc:/pa/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "?i", - "hash": "" - }, - { - "input": "?i", - "base": "sc://ho/pa", - "href": "sc://ho/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/pa", - "search": "?i", - "hash": "" - }, - { - "input": "?i", - "base": "sc:///pa/pa", - "href": "sc:///pa/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "?i", - "hash": "" - }, - { - "input": "#i", - "base": "sc:sd", - "href": "sc:sd#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "sd", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:sd/sd", - "href": "sc:sd/sd#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "sd/sd", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:/pa/pa", - "href": "sc:/pa/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc://ho/pa", - "href": "sc://ho/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/pa", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:///pa/pa", - "href": "sc:///pa/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "", - "hash": "#i" - }, - "# make sure that relative URL logic works on known typically non-relative schemes too", - { - "input": "about:/../", - "base": "about:blank", - "href": "about:/", - "origin": "null", - "protocol": "about:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/../", - "base": "about:blank", - "href": "data:/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/../", - "base": "about:blank", - "href": "javascript:/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/../", - "base": "about:blank", - "href": "mailto:/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# unknown schemes and their hosts", - { - "input": "sc://ñ.test/", - "base": "about:blank", - "href": "sc://%C3%B1.test/", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1.test", - "hostname": "%C3%B1.test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://\u0000/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc:// /", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://%/", - "base": "about:blank", - "href": "sc://%/", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%", - "hostname": "%", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://@/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://te@s:t@/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://:/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://:12/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://[/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://\\/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://]/", - "base": "about:blank", - "failure": true - }, - { - "input": "x", - "base": "sc://ñ", - "href": "sc://%C3%B1/x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - "# unknown schemes and backslashes", - { - "input": "sc:\\../", - "base": "about:blank", - "href": "sc:\\../", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "\\../", - "search": "", - "hash": "" - }, - "# unknown scheme with path looking like a password", - { - "input": "sc::a@example.net", - "base": "about:blank", - "href": "sc::a@example.net", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": ":a@example.net", - "search": "", - "hash": "" - }, - "# unknown scheme with bogus percent-encoding", - { - "input": "wow:%NBD", - "base": "about:blank", - "href": "wow:%NBD", - "origin": "null", - "protocol": "wow:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "%NBD", - "search": "", - "hash": "" - }, - { - "input": "wow:%1G", - "base": "about:blank", - "href": "wow:%1G", - "origin": "null", - "protocol": "wow:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "%1G", - "search": "", - "hash": "" - }, - "# Hosts and percent-encoding", - { - "input": "ftp://example.com%80/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftp://example.com%A0/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://example.com%80/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://example.com%A0/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftp://%e2%98%83", - "base": "about:blank", - "href": "ftp://xn--n3h/", - "origin": "ftp://xn--n3h", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "xn--n3h", - "hostname": "xn--n3h", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://%e2%98%83", - "base": "about:blank", - "href": "https://xn--n3h/", - "origin": "https://xn--n3h", - "protocol": "https:", - "username": "", - "password": "", - "host": "xn--n3h", - "hostname": "xn--n3h", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# tests from jsdom/whatwg-url designed for code coverage", - { - "input": "http://127.0.0.1:10100/relative_import.html", - "base": "about:blank", - "href": "http://127.0.0.1:10100/relative_import.html", - "origin": "http://127.0.0.1:10100", - "protocol": "http:", - "username": "", - "password": "", - "host": "127.0.0.1:10100", - "hostname": "127.0.0.1", - "port": "10100", - "pathname": "/relative_import.html", - "search": "", - "hash": "" - }, - { - "input": "http://facebook.com/?foo=%7B%22abc%22", - "base": "about:blank", - "href": "http://facebook.com/?foo=%7B%22abc%22", - "origin": "http://facebook.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "facebook.com", - "hostname": "facebook.com", - "port": "", - "pathname": "/", - "search": "?foo=%7B%22abc%22", - "hash": "" - }, - { - "input": "https://localhost:3000/jqueryui@1.2.3", - "base": "about:blank", - "href": "https://localhost:3000/jqueryui@1.2.3", - "origin": "https://localhost:3000", - "protocol": "https:", - "username": "", - "password": "", - "host": "localhost:3000", - "hostname": "localhost", - "port": "3000", - "pathname": "/jqueryui@1.2.3", - "search": "", - "hash": "" - }, - "# tab/LF/CR", - { - "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", - "base": "about:blank", - "href": "http://host:9000/path?query#frag", - "origin": "http://host:9000", - "protocol": "http:", - "username": "", - "password": "", - "host": "host:9000", - "hostname": "host", - "port": "9000", - "pathname": "/path", - "search": "?query", - "hash": "#frag" - }, - "# Stringification of URL.searchParams", - { - "input": "?a=b&c=d", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar?a=b&c=d", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "?a=b&c=d", - "searchParams": "a=b&c=d", - "hash": "" - }, - { - "input": "??a=b&c=d", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar??a=b&c=d", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "??a=b&c=d", - "searchParams": "%3Fa=b&c=d", - "hash": "" - }, - "# Scheme only", - { - "input": "http:", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "searchParams": "", - "hash": "" - }, - { - "input": "http:", - "base": "https://example.org/foo/bar", - "failure": true - }, - { - "input": "sc:", - "base": "https://example.org/foo/bar", - "href": "sc:", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "searchParams": "", - "hash": "" - }, - "# Percent encoding of fragments", - { - "input": "http://foo.bar/baz?qux#foo\bbar", - "base": "about:blank", - "href": "http://foo.bar/baz?qux#foo%08bar", - "origin": "http://foo.bar", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.bar", - "hostname": "foo.bar", - "port": "", - "pathname": "/baz", - "search": "?qux", - "searchParams": "qux=", - "hash": "#foo%08bar" - }, - "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)", - { - "input": "http://192.168.257", - "base": "http://other.com/", - "href": "http://192.168.1.1/", - "origin": "http://192.168.1.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.1.1", - "hostname": "192.168.1.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.168.257.com", - "base": "http://other.com/", - "href": "http://192.168.257.com/", - "origin": "http://192.168.257.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.257.com", - "hostname": "192.168.257.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://256", - "base": "http://other.com/", - "href": "http://0.0.1.0/", - "origin": "http://0.0.1.0", - "protocol": "http:", - "username": "", - "password": "", - "host": "0.0.1.0", - "hostname": "0.0.1.0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://256.com", - "base": "http://other.com/", - "href": "http://256.com/", - "origin": "http://256.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "256.com", - "hostname": "256.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://999999999", - "base": "http://other.com/", - "href": "http://59.154.201.255/", - "origin": "http://59.154.201.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "59.154.201.255", - "hostname": "59.154.201.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://999999999.com", - "base": "http://other.com/", - "href": "http://999999999.com/", - "origin": "http://999999999.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "999999999.com", - "hostname": "999999999.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://10000000000", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://10000000000.com", - "base": "http://other.com/", - "href": "http://10000000000.com/", - "origin": "http://10000000000.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "10000000000.com", - "hostname": "10000000000.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://4294967295", - "base": "http://other.com/", - "href": "http://255.255.255.255/", - "origin": "http://255.255.255.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "255.255.255.255", - "hostname": "255.255.255.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://4294967296", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://0xffffffff", - "base": "http://other.com/", - "href": "http://255.255.255.255/", - "origin": "http://255.255.255.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "255.255.255.255", - "hostname": "255.255.255.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0xffffffff1", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://256.256.256.256", - "base": "http://other.com/", - "failure": true - }, - { - "input": "https://0x.0x.0", - "base": "about:blank", - "href": "https://0.0.0.0/", - "origin": "https://0.0.0.0", - "protocol": "https:", - "username": "", - "password": "", - "host": "0.0.0.0", - "hostname": "0.0.0.0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", - { - "input": "https://0x100000000/test", - "base": "about:blank", - "failure": true - }, - { - "input": "https://256.0.0.1/test", - "base": "about:blank", - "failure": true - }, - "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", - { - "input": "file:///C%3A/", - "base": "about:blank", - "href": "file:///C%3A/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C%3A/", - "search": "", - "hash": "" - }, - { - "input": "file:///C%7C/", - "base": "about:blank", - "href": "file:///C%7C/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C%7C/", - "search": "", - "hash": "" - }, - "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)", - { - "input": "pix/submit.gif", - "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html", - "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///C:/", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# More file URL tests by zcorpan and annevk", - { - "input": "/", - "base": "file:///C:/a/b", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "//d:", - "base": "file:///C:/a/b", - "href": "file:///d:", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/d:", - "search": "", - "hash": "" - }, - { - "input": "//d:/..", - "base": "file:///C:/a/b", - "href": "file:///d:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/d:/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///ab:/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///1:/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "", - "base": "file:///test?test#test", - "href": "file:///test?test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "" - }, - { - "input": "file:", - "base": "file:///test?test#test", - "href": "file:///test?test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "" - }, - { - "input": "?x", - "base": "file:///test?test#test", - "href": "file:///test?x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?x", - "hash": "" - }, - { - "input": "file:?x", - "base": "file:///test?test#test", - "href": "file:///test?x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?x", - "hash": "" - }, - { - "input": "#x", - "base": "file:///test?test#test", - "href": "file:///test?test#x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "#x" - }, - { - "input": "file:#x", - "base": "file:///test?test#test", - "href": "file:///test?test#x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "#x" - }, - "# File URLs and many (back)slashes", - { - "input": "file:\\\\//", - "base": "about:blank", - "href": "file:////", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\\\\\", - "base": "about:blank", - "href": "file:////", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\\\\\?fox", - "base": "about:blank", - "href": "file:////?fox", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "?fox", - "hash": "" - }, - { - "input": "file:\\\\\\\\#guppy", - "base": "about:blank", - "href": "file:////#guppy", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "#guppy" - }, - { - "input": "file://spider///", - "base": "about:blank", - "href": "file://spider///", - "protocol": "file:", - "username": "", - "password": "", - "host": "spider", - "hostname": "spider", - "port": "", - "pathname": "///", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\localhost//", - "base": "about:blank", - "href": "file:////", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "file:///localhost//cat", - "base": "about:blank", - "href": "file:///localhost//cat", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/localhost//cat", - "search": "", - "hash": "" - }, - { - "input": "file://\\/localhost//cat", - "base": "about:blank", - "href": "file:////localhost//cat", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//localhost//cat", - "search": "", - "hash": "" - }, - { - "input": "file://localhost//a//../..//", - "base": "about:blank", - "href": "file://///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///", - "search": "", - "hash": "" - }, - { - "input": "/////mouse", - "base": "file:///elephant", - "href": "file://///mouse", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///mouse", - "search": "", - "hash": "" - }, - { - "input": "\\//pig", - "base": "file://lion/", - "href": "file:///pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pig", - "search": "", - "hash": "" - }, - { - "input": "\\/localhost//pig", - "base": "file://lion/", - "href": "file:////pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//pig", - "search": "", - "hash": "" - }, - { - "input": "//localhost//pig", - "base": "file://lion/", - "href": "file:////pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//pig", - "search": "", - "hash": "" - }, - { - "input": "/..//localhost//pig", - "base": "file://lion/", - "href": "file://lion//localhost//pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "lion", - "hostname": "lion", - "port": "", - "pathname": "//localhost//pig", - "search": "", - "hash": "" - }, - { - "input": "file://", - "base": "file://ape/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# File URLs with non-empty hosts", - { - "input": "/rooibos", - "base": "file://tea/", - "href": "file://tea/rooibos", - "protocol": "file:", - "username": "", - "password": "", - "host": "tea", - "hostname": "tea", - "port": "", - "pathname": "/rooibos", - "search": "", - "hash": "" - }, - { - "input": "/?chai", - "base": "file://tea/", - "href": "file://tea/?chai", - "protocol": "file:", - "username": "", - "password": "", - "host": "tea", - "hostname": "tea", - "port": "", - "pathname": "/", - "search": "?chai", - "hash": "" - }, - "# Windows drive letter handling with the 'file:' base URL", - { - "input": "C|", - "base": "file://host/dir/file", - "href": "file://host/C:", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|#", - "base": "file://host/dir/file", - "href": "file://host/C:#", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|?", - "base": "file://host/dir/file", - "href": "file://host/C:?", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|/", - "base": "file://host/dir/file", - "href": "file://host/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C|\n/", - "base": "file://host/dir/file", - "href": "file://host/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C|\\", - "base": "file://host/dir/file", - "href": "file://host/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C", - "base": "file://host/dir/file", - "href": "file://host/dir/C", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/dir/C", - "search": "", - "hash": "" - }, - { - "input": "C|a", - "base": "file://host/dir/file", - "href": "file://host/dir/C|a", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/dir/C|a", - "search": "", - "hash": "" - }, - "# Windows drive letter quirk with not empty host", - { - "input": "file://example.net/C:/", - "base": "about:blank", - "href": "file://example.net/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "example.net", - "hostname": "example.net", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://1.2.3.4/C:/", - "base": "about:blank", - "href": "file://1.2.3.4/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "1.2.3.4", - "hostname": "1.2.3.4", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://[1::8]/C:/", - "base": "about:blank", - "href": "file://[1::8]/C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "[1::8]", - "hostname": "[1::8]", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - "# Windows drive letter quirk (no host)", - { - "input": "file:/C|/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://C|/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - "# file URLs without base URL by Rimas Misevičius", - { - "input": "file:", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:?q=v", - "base": "about:blank", - "href": "file:///?q=v", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "?q=v", - "hash": "" - }, - { - "input": "file:#frag", - "base": "about:blank", - "href": "file:///#frag", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "#frag" - }, - "# IPv6 tests", - { - "input": "http://[1:0::]", - "base": "http://example.net/", - "href": "http://[1::]/", - "origin": "http://[1::]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[1::]", - "hostname": "[1::]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[0:1:2:3:4:5:6:7:8]", - "base": "http://example.net/", - "failure": true - }, - { - "input": "https://[0::0::0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:0:]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.00.0.0.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.290.0.0.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.23.23]", - "base": "about:blank", - "failure": true - }, - "# Empty host", - { - "input": "http://?", - "base": "about:blank", - "failure": true - }, - { - "input": "http://#", - "base": "about:blank", - "failure": true - }, - "# Non-special-URL path tests", - { - "input": "sc://ñ", - "base": "about:blank", - "href": "sc://%C3%B1", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "sc://ñ?x", - "base": "about:blank", - "href": "sc://%C3%B1?x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "?x", - "hash": "" - }, - { - "input": "sc://ñ#x", - "base": "about:blank", - "href": "sc://%C3%B1#x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "sc://ñ", - "href": "sc://%C3%B1#x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "#x" - }, - { - "input": "?x", - "base": "sc://ñ", - "href": "sc://%C3%B1?x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "?x", - "hash": "" - }, - { - "input": "sc://?", - "base": "about:blank", - "href": "sc://?", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "sc://#", - "base": "about:blank", - "href": "sc://#", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "///", - "base": "sc://x/", - "href": "sc:///", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "////", - "base": "sc://x/", - "href": "sc:////", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "////x/", - "base": "sc://x/", - "href": "sc:////x/", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//x/", - "search": "", - "hash": "" - }, - { - "input": "tftp://foobar.com/someconfig;mode=netascii", - "base": "about:blank", - "href": "tftp://foobar.com/someconfig;mode=netascii", - "origin": "null", - "protocol": "tftp:", - "username": "", - "password": "", - "host": "foobar.com", - "hostname": "foobar.com", - "port": "", - "pathname": "/someconfig;mode=netascii", - "search": "", - "hash": "" - }, - { - "input": "telnet://user:pass@foobar.com:23/", - "base": "about:blank", - "href": "telnet://user:pass@foobar.com:23/", - "origin": "null", - "protocol": "telnet:", - "username": "user", - "password": "pass", - "host": "foobar.com:23", - "hostname": "foobar.com", - "port": "23", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ut2004://10.10.10.10:7777/Index.ut2", - "base": "about:blank", - "href": "ut2004://10.10.10.10:7777/Index.ut2", - "origin": "null", - "protocol": "ut2004:", - "username": "", - "password": "", - "host": "10.10.10.10:7777", - "hostname": "10.10.10.10", - "port": "7777", - "pathname": "/Index.ut2", - "search": "", - "hash": "" - }, - { - "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", - "base": "about:blank", - "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", - "origin": "null", - "protocol": "redis:", - "username": "foo", - "password": "bar", - "host": "somehost:6379", - "hostname": "somehost", - "port": "6379", - "pathname": "/0", - "search": "?baz=bam&qux=baz", - "hash": "" - }, - { - "input": "rsync://foo@host:911/sup", - "base": "about:blank", - "href": "rsync://foo@host:911/sup", - "origin": "null", - "protocol": "rsync:", - "username": "foo", - "password": "", - "host": "host:911", - "hostname": "host", - "port": "911", - "pathname": "/sup", - "search": "", - "hash": "" - }, - { - "input": "git://github.com/foo/bar.git", - "base": "about:blank", - "href": "git://github.com/foo/bar.git", - "origin": "null", - "protocol": "git:", - "username": "", - "password": "", - "host": "github.com", - "hostname": "github.com", - "port": "", - "pathname": "/foo/bar.git", - "search": "", - "hash": "" - }, - { - "input": "irc://myserver.com:6999/channel?passwd", - "base": "about:blank", - "href": "irc://myserver.com:6999/channel?passwd", - "origin": "null", - "protocol": "irc:", - "username": "", - "password": "", - "host": "myserver.com:6999", - "hostname": "myserver.com", - "port": "6999", - "pathname": "/channel", - "search": "?passwd", - "hash": "" - }, - { - "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", - "base": "about:blank", - "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", - "origin": "null", - "protocol": "dns:", - "username": "", - "password": "", - "host": "fw.example.org:9999", - "hostname": "fw.example.org", - "port": "9999", - "pathname": "/foo.bar.org", - "search": "?type=TXT", - "hash": "" - }, - { - "input": "ldap://localhost:389/ou=People,o=JNDITutorial", - "base": "about:blank", - "href": "ldap://localhost:389/ou=People,o=JNDITutorial", - "origin": "null", - "protocol": "ldap:", - "username": "", - "password": "", - "host": "localhost:389", - "hostname": "localhost", - "port": "389", - "pathname": "/ou=People,o=JNDITutorial", - "search": "", - "hash": "" - }, - { - "input": "git+https://github.com/foo/bar", - "base": "about:blank", - "href": "git+https://github.com/foo/bar", - "origin": "null", - "protocol": "git+https:", - "username": "", - "password": "", - "host": "github.com", - "hostname": "github.com", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "urn:ietf:rfc:2648", - "base": "about:blank", - "href": "urn:ietf:rfc:2648", - "origin": "null", - "protocol": "urn:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "ietf:rfc:2648", - "search": "", - "hash": "" - }, - { - "input": "tag:joe@example.org,2001:foo/bar", - "base": "about:blank", - "href": "tag:joe@example.org,2001:foo/bar", - "origin": "null", - "protocol": "tag:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "joe@example.org,2001:foo/bar", - "search": "", - "hash": "" - }, - "# percent encoded hosts in non-special-URLs", - { - "input": "non-special://%E2%80%A0/", - "base": "about:blank", - "href": "non-special://%E2%80%A0/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "%E2%80%A0", - "hostname": "%E2%80%A0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://H%4fSt/path", - "base": "about:blank", - "href": "non-special://H%4fSt/path", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "H%4fSt", - "hostname": "H%4fSt", - "port": "", - "pathname": "/path", - "search": "", - "hash": "" - }, - "# IPv6 in non-special-URLs", - { - "input": "non-special://[1:2:0:0:5:0:0:0]/", - "base": "about:blank", - "href": "non-special://[1:2:0:0:5::]/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2:0:0:5::]", - "hostname": "[1:2:0:0:5::]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[1:2:0:0:0:0:0:3]/", - "base": "about:blank", - "href": "non-special://[1:2::3]/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2::3]", - "hostname": "[1:2::3]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[1:2::3]:80/", - "base": "about:blank", - "href": "non-special://[1:2::3]:80/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2::3]:80", - "hostname": "[1:2::3]", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[:80/", - "base": "about:blank", - "failure": true - }, - { - "input": "blob:https://example.com:443/", - "base": "about:blank", - "href": "blob:https://example.com:443/", - "origin": "https://example.com", - "protocol": "blob:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "https://example.com:443/", - "search": "", - "hash": "" - }, - { - "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", - "base": "about:blank", - "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", - "protocol": "blob:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf", - "search": "", - "hash": "" - }, - "Invalid IPv4 radix digits", - { - "input": "http://0x7f.0.0.0x7g", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "origin": "http://0x7f.0.0.0x7g", - "protocol": "http:", - "username": "", - "password": "", - "host": "0x7f.0.0.0x7g", - "hostname": "0x7f.0.0.0x7g", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0X7F.0.0.0X7G", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "origin": "http://0x7f.0.0.0x7g", - "protocol": "http:", - "username": "", - "password": "", - "host": "0x7f.0.0.0x7g", - "hostname": "0x7f.0.0.0x7g", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid IPv4 portion of IPv6 address", - { - "input": "http://[::127.0.0.0.1]", - "base": "about:blank", - "failure": true - }, - "Uncompressed IPv6 addresses with 0", - { - "input": "http://[0:1:0:1:0:1:0:1]", - "base": "about:blank", - "href": "http://[0:1:0:1:0:1:0:1]/", - "origin": "http://[0:1:0:1:0:1:0:1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[0:1:0:1:0:1:0:1]", - "hostname": "[0:1:0:1:0:1:0:1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[1:0:1:0:1:0:1:0]", - "base": "about:blank", - "href": "http://[1:0:1:0:1:0:1:0]/", - "origin": "http://[1:0:1:0:1:0:1:0]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[1:0:1:0:1:0:1:0]", - "hostname": "[1:0:1:0:1:0:1:0]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Percent-encoded query and fragment", - { - "input": "http://example.org/test?\u0022", - "base": "about:blank", - "href": "http://example.org/test?%22", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%22", - "hash": "" - }, - { - "input": "http://example.org/test?\u0023", - "base": "about:blank", - "href": "http://example.org/test?#", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "http://example.org/test?\u003C", - "base": "about:blank", - "href": "http://example.org/test?%3C", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%3C", - "hash": "" - }, - { - "input": "http://example.org/test?\u003E", - "base": "about:blank", - "href": "http://example.org/test?%3E", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%3E", - "hash": "" - }, - { - "input": "http://example.org/test?\u2323", - "base": "about:blank", - "href": "http://example.org/test?%E2%8C%A3", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%E2%8C%A3", - "hash": "" - }, - { - "input": "http://example.org/test?%23%23", - "base": "about:blank", - "href": "http://example.org/test?%23%23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%23%23", - "hash": "" - }, - { - "input": "http://example.org/test?%GH", - "base": "about:blank", - "href": "http://example.org/test?%GH", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%GH", - "hash": "" - }, - { - "input": "http://example.org/test?a#%EF", - "base": "about:blank", - "href": "http://example.org/test?a#%EF", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#%EF" - }, - { - "input": "http://example.org/test?a#%GH", - "base": "about:blank", - "href": "http://example.org/test?a#%GH", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#%GH" - }, - "Bad bases", - { - "input": "test-a.html", - "base": "a", - "failure": true - }, - { - "input": "test-a-slash.html", - "base": "a/", - "failure": true - }, - { - "input": "test-a-slash-slash.html", - "base": "a//", - "failure": true - }, - { - "input": "test-a-colon.html", - "base": "a:", - "failure": true - }, - { - "input": "test-a-colon-slash.html", - "base": "a:/", - "href": "a:/test-a-colon-slash.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-slash-slash.html", - "base": "a://", - "href": "a:///test-a-colon-slash-slash.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash-slash.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-b.html", - "base": "a:b", - "failure": true - }, - { - "input": "test-a-colon-slash-b.html", - "base": "a:/b", - "href": "a:/test-a-colon-slash-b.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash-b.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-slash-slash-b.html", - "base": "a://b", - "href": "a://b/test-a-colon-slash-slash-b.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "b", - "hostname": "b", - "port": "", - "pathname": "/test-a-colon-slash-slash-b.html", - "search": "", - "hash": "" - }, - "Null code point in fragment", - { - "input": "http://example.org/test?a#b\u0000c", - "base": "about:blank", - "href": "http://example.org/test?a#b%00c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#b%00c" - } - ]; - - cases.forEach((test) => { - if (typeof test === 'string') return; - if (test.failure) { - throws(() => { - new URL(test.input, test.base || 'about:blank'); - }); - return; - } - const url = new URL(test.input, test.base || 'about:blank'); - strictEqual(url.href, test.href); - strictEqual(url.protocol, test.protocol); - strictEqual(url.username, test.username); - strictEqual(url.password, test.password); - strictEqual(url.host, test.host); - strictEqual(url.hostname, test.hostname); - strictEqual(url.port, test.port); - strictEqual(url.pathname, test.pathname); - strictEqual(url.search, test.search); - if ('searchParams' in test) { - strictEqual(url.searchParams.toString(), test.searchParams); - } - strictEqual(url.hash, test.hash); - if (test.origin == null) { - strictEqual(url.origin, "null"); - } else { - strictEqual(url.origin, test.origin); - } - }); - } -}; - -export const urlSetterTests = { - test() { - - const cases = { - "protocol": [ - { - "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.", - "href": "a://example.net", - "new_value": "", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "href": "a://example.net", - "new_value": "b", - "expected": { - "href": "b://example.net", - "protocol": "b:" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "defuse", - "expected": { - "href": "defuse:alert(1)", - "protocol": "defuse:" - } - }, - { - "comment": "Upper-case ASCII is lower-cased", - "href": "a://example.net", - "new_value": "B", - "expected": { - "href": "b://example.net", - "protocol": "b:" - } - }, - { - "comment": "Non-ASCII is rejected", - "href": "a://example.net", - "new_value": "é", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "No leading digit", - "href": "a://example.net", - "new_value": "0b", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "No leading punctuation", - "href": "a://example.net", - "new_value": "+b", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "href": "a://example.net", - "new_value": "bC0+-.", - "expected": { - "href": "bc0+-.://example.net", - "protocol": "bc0+-.:" - } - }, - { - "comment": "Only some punctuation is acceptable", - "href": "a://example.net", - "new_value": "b,c", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "Non-ASCII is rejected", - "href": "a://example.net", - "new_value": "bé", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "Can’t switch from URL containing username/password/port to file", - "href": "http://test@example.net", - "new_value": "file", - "expected": { - "href": "http://test@example.net/", - "protocol": "http:" - } - }, - { - "href": "gopher://example.net:1234", - "new_value": "file", - "expected": { - "href": "gopher://example.net:1234", - "protocol": "gopher:" - } - }, - { - "href": "wss://x:x@example.net:1234", - "new_value": "file", - "expected": { - "href": "wss://x:x@example.net:1234/", - "protocol": "wss:" - } - }, - { - "comment": "Can’t switch from file URL with no host", - "href": "file://localhost/", - "new_value": "http", - "expected": { - "href": "file:///", - "protocol": "file:" - } - }, - { - "href": "file:///test", - "new_value": "gopher", - "expected": { - "href": "file:///test", - "protocol": "file:" - } - }, - { - "href": "file:", - "new_value": "wss", - "expected": { - "href": "file:///", - "protocol": "file:" - } - }, - { - "comment": "Can’t switch from special scheme to non-special", - "href": "http://example.net", - "new_value": "b", - "expected": { - "href": "http://example.net/", - "protocol": "http:" - } - }, - { - "href": "file://hi/path", - "new_value": "s", - "expected": { - "href": "file://hi/path", - "protocol": "file:" - } - }, - { - "href": "https://example.net", - "new_value": "s", - "expected": { - "href": "https://example.net/", - "protocol": "https:" - } - }, - { - "href": "ftp://example.net", - "new_value": "test", - "expected": { - "href": "ftp://example.net/", - "protocol": "ftp:" - } - }, - { - "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", - "href": "mailto:me@example.net", - "new_value": "http", - "expected": { - "href": "mailto:me@example.net", - "protocol": "mailto:" - } - }, - { - "comment": "Can’t switch from non-special scheme to special", - "href": "ssh://me@example.net", - "new_value": "http", - "expected": { - "href": "ssh://me@example.net", - "protocol": "ssh:" - } - }, - { - "href": "ssh://me@example.net", - "new_value": "gopher", - "expected": { - "href": "gopher://me@example.net", - "protocol": "gopher:" - } - }, - { - "href": "ssh://me@example.net", - "new_value": "file", - "expected": { - "href": "ssh://me@example.net", - "protocol": "ssh:" - } - }, - { - "href": "ssh://example.net", - "new_value": "file", - "expected": { - "href": "ssh://example.net", - "protocol": "ssh:" - } - }, - { - "href": "nonsense:///test", - "new_value": "https", - "expected": { - "href": "nonsense:///test", - "protocol": "nonsense:" - } - }, - { - "comment": "Stuff after the first ':' is ignored", - "href": "http://example.net", - "new_value": "https:foo : bar", - "expected": { - "href": "https://example.net/", - "protocol": "https:" - } - }, - { - "comment": "Stuff after the first ':' is ignored", - "href": "data:text/html,

Test", - "new_value": "view-source+data:foo : bar", - "expected": { - "href": "view-source+data:text/html,

Test", - "protocol": "view-source+data:" - } - }, - { - "comment": "Port is set to null if it is the default for new scheme.", - "href": "http://foo.com:443/", - "new_value": "https", - "expected": { - "href": "https://foo.com/", - "protocol": "https:", - "port": "" - } - } - ], - "username": [ - { - "comment": "No host means no username", - "href": "file:///home/you/index.html", - "new_value": "me", - "expected": { - "href": "file:///home/you/index.html", - "username": "" - } - }, - { - "comment": "No host means no username", - "href": "unix:/run/foo.socket", - "new_value": "me", - "expected": { - "href": "unix:/run/foo.socket", - "username": "" - } - }, - { - "comment": "Cannot-be-a-base means no username", - "href": "mailto:you@example.net", - "new_value": "me", - "expected": { - "href": "mailto:you@example.net", - "username": "" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "wario", - "expected": { - "href": "javascript:alert(1)", - "username": "" - } - }, - { - "href": "http://example.net", - "new_value": "me", - "expected": { - "href": "http://me@example.net/", - "username": "me" - } - }, - { - "href": "http://:secret@example.net", - "new_value": "me", - "expected": { - "href": "http://me:secret@example.net/", - "username": "me" - } - }, - { - "href": "http://me@example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "username": "" - } - }, - { - "href": "http://me:secret@example.net", - "new_value": "", - "expected": { - "href": "http://:secret@example.net/", - "username": "" - } - }, - { - "comment": "UTF-8 percent encoding with the userinfo encode set.", - "href": "http://example.net", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", - "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is.", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://%c3%89t%C3%A9@example.net/", - "username": "%c3%89t%C3%A9" - } - }, - { - "href": "sc:///", - "new_value": "x", - "expected": { - "href": "sc:///", - "username": "" - } - }, - { - "href": "javascript://x/", - "new_value": "wario", - "expected": { - "href": "javascript://wario@x/", - "username": "wario" - } - }, - { - "href": "file://test/", - "new_value": "test", - "expected": { - "href": "file://test/", - "username": "" - } - } - ], - "password": [ - { - "comment": "No host means no password", - "href": "file:///home/me/index.html", - "new_value": "secret", - "expected": { - "href": "file:///home/me/index.html", - "password": "" - } - }, - { - "comment": "No host means no password", - "href": "unix:/run/foo.socket", - "new_value": "secret", - "expected": { - "href": "unix:/run/foo.socket", - "password": "" - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "mailto:me@example.net", - "new_value": "secret", - "expected": { - "href": "mailto:me@example.net", - "password": "" - } - }, - { - "href": "http://example.net", - "new_value": "secret", - "expected": { - "href": "http://:secret@example.net/", - "password": "secret" - } - }, - { - "href": "http://me@example.net", - "new_value": "secret", - "expected": { - "href": "http://me:secret@example.net/", - "password": "secret" - } - }, - { - "href": "http://:secret@example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "password": "" - } - }, - { - "href": "http://me:secret@example.net", - "new_value": "", - "expected": { - "href": "http://me@example.net/", - "password": "" - } - }, - { - "comment": "UTF-8 percent encoding with the userinfo encode set.", - "href": "http://example.net", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", - "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is.", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://:%c3%89t%C3%A9@example.net/", - "password": "%c3%89t%C3%A9" - } - }, - { - "href": "sc:///", - "new_value": "x", - "expected": { - "href": "sc:///", - "password": "" - } - }, - { - "href": "javascript://x/", - "new_value": "bowser", - "expected": { - "href": "javascript://:bowser@x/", - "password": "bowser" - } - }, - { - "href": "file://test/", - "new_value": "test", - "expected": { - "href": "file://test/", - "password": "" - } - } - ], - "host": [ - { - "comment": "Non-special scheme", - "href": "sc://x/", - "new_value": "\u0000", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "\u0009", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000A", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000D", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": " ", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "#", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "/", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "?", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "@", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "ß", - "expected": { - "href": "sc://%C3%9F/", - "host": "%C3%9F", - "hostname": "%C3%9F" - } - }, - { - "comment": "IDNA Nontransitional_Processing", - "href": "https://x/", - "new_value": "ß", - "expected": { - "href": "https://xn--zca/", - "host": "xn--zca", - "hostname": "xn--zca" - } - }, - { - "comment": "Cannot-be-a-base means no host", - "href": "mailto:me@example.net", - "new_value": "example.com", - "expected": { - "href": "mailto:me@example.net", - "host": "" - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "data:text/plain,Stuff", - "new_value": "example.net", - "expected": { - "href": "data:text/plain,Stuff", - "host": "" - } - }, - { - "href": "http://example.net", - "new_value": "example.com:8080", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port number is unchanged if not specified in the new value", - "href": "http://example.net:8080", - "new_value": "example.com", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port number is unchanged if not specified", - "href": "http://example.net:8080", - "new_value": "example.com:", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "The empty host is not valid for special schemes", - "href": "http://example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net" - } - }, - { - "comment": "The empty host is OK for non-special schemes", - "href": "view-source+http://example.net/foo", - "new_value": "", - "expected": { - "href": "view-source+http:///foo", - "host": "" - } - }, - { - "comment": "Path-only URLs can gain a host", - "href": "a:/foo", - "new_value": "example.net", - "expected": { - "href": "a://example.net/foo", - "host": "example.net" - } - }, - { - "comment": "IPv4 address syntax is normalized", - "href": "http://example.net", - "new_value": "0x7F000001:8080", - "expected": { - "href": "http://127.0.0.1:8080/", - "host": "127.0.0.1:8080", - "hostname": "127.0.0.1", - "port": "8080" - } - }, - { - "comment": "IPv6 address syntax is normalized", - "href": "http://example.net", - "new_value": "[::0:01]:2", - "expected": { - "href": "http://[::1]:2/", - "host": "[::1]:2", - "hostname": "[::1]", - "port": "2" - } - }, - { - "comment": "Default port number is removed", - "href": "http://example.net", - "new_value": "example.com:80", - "expected": { - "href": "http://example.com/", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "https://example.net", - "new_value": "example.com:443", - "expected": { - "href": "https://example.com/", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Default port number is only removed for the relevant scheme", - "href": "https://example.net", - "new_value": "example.com:80", - "expected": { - "href": "https://example.com:80/", - "host": "example.com:80", - "hostname": "example.com", - "port": "80" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com/stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080/stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com?stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080?stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com#stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080#stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com:8080\\stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", - "href": "view-source+http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "view-source+http://example.net/path", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "view-source+http://example.net/path", - "new_value": "example.com:8080stuff2", - "expected": { - "href": "view-source+http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "example.com:8080stuff2", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "example.com:8080+2", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers", - "href": "http://example.net/path", - "new_value": "example.com:65535", - "expected": { - "href": "http://example.com:65535/path", - "host": "example.com:65535", - "hostname": "example.com", - "port": "65535" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", - "href": "http://example.net/path", - "new_value": "example.com:65536", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Broken IPv6", - "href": "http://example.net/", - "new_value": "[google.com]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.4x]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "file://y/", - "new_value": "x:123", - "expected": { - "href": "file://y/", - "host": "y", - "hostname": "y", - "port": "" - } - }, - { - "href": "file://y/", - "new_value": "loc%41lhost", - "expected": { - "href": "file:///", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "file://hi/x", - "new_value": "", - "expected": { - "href": "file:///x", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "sc://test@test/", - "new_value": "", - "expected": { - "href": "sc://test@test/", - "host": "test", - "hostname": "test", - "username": "test" - } - }, - { - "href": "sc://test:12/", - "new_value": "", - "expected": { - "href": "sc://test:12/", - "host": "test:12", - "hostname": "test", - "port": "12" - } - } - ], - - "hostname": [ - { - "comment": "Non-special scheme", - "href": "sc://x/", - "new_value": "\u0000", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "\u0009", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000A", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000D", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": " ", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "#", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "/", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "?", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "@", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "comment": "Cannot-be-a-base means no host", - "href": "mailto:me@example.net", - "new_value": "example.com", - "expected": { - "href": "mailto:me@example.net", - "host": "", - "hostname": "", - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "data:text/plain,Stuff", - "new_value": "example.net", - "expected": { - "href": "data:text/plain,Stuff", - "host": "", - "hostname": "" - } - }, - { - "href": "http://example.net:8080", - "new_value": "example.com", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "The empty host is not valid for special schemes", - "href": "http://example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "comment": "The empty host is OK for non-special schemes", - "href": "view-source+http://example.net/foo", - "new_value": "", - "expected": { - "href": "view-source+http:///foo", - "host": "", - "hostname": "", - } - }, - { - "comment": "Path-only URLs can gain a host", - "href": "a:/foo", - "new_value": "example.net", - "expected": { - "href": "a://example.net/foo", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "comment": "IPv4 address syntax is normalized", - "href": "http://example.net:8080", - "new_value": "0x7F000001", - "expected": { - "href": "http://127.0.0.1:8080/", - "host": "127.0.0.1:8080", - "hostname": "127.0.0.1", - "port": "8080" - } - }, - { - "comment": "IPv6 address syntax is normalized", - "href": "http://example.net", - "new_value": "[::0:01]", - "expected": { - "href": "http://[::1]/", - "host": "[::1]", - "hostname": "[::1]", - "port": "" - } - }, - { - "comment": ": delimiter invalidates entire value", - "href": "http://example.net/path", - "new_value": "example.com:8080", - "expected": { - "href": "http://example.net/path", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": ": delimiter invalidates entire value", - "href": "http://example.net:8080/path", - "new_value": "example.com:", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com/stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com?stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com#stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", - "href": "view-source+http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "view-source+http://example.net/path", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Broken IPv6", - "href": "http://example.net/", - "new_value": "[google.com]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.4x]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "file://y/", - "new_value": "x:123", - "expected": { - "href": "file://y/", - "host": "y", - "hostname": "y", - "port": "" - } - }, - { - "href": "file://y/", - "new_value": "loc%41lhost", - "expected": { - "href": "file:///", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "file://hi/x", - "new_value": "", - "expected": { - "href": "file:///x", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "sc://test@test/", - "new_value": "", - "expected": { - "href": "sc://test@test/", - "host": "test", - "hostname": "test", - "username": "test" - } - }, - { - "href": "sc://test:12/", - "new_value": "", - "expected": { - "href": "sc://test:12/", - "host": "test:12", - "hostname": "test", - "port": "12" - } - } - ], - "port": [ - { - "href": "http://example.net", - "new_value": "8080", - "expected": { - "href": "http://example.net:8080/", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port number is removed if empty is the new value", - "href": "http://example.net:8080", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "http://example.net:8080", - "new_value": "80", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "https://example.net:4433", - "new_value": "443", - "expected": { - "href": "https://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is only removed for the relevant scheme", - "href": "https://example.net", - "new_value": "80", - "expected": { - "href": "https://example.net:80/", - "host": "example.net:80", - "hostname": "example.net", - "port": "80" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080/stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080?stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080#stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "8080\\stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "view-source+http://example.net/path", - "new_value": "8080stuff2", - "expected": { - "href": "view-source+http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "8080stuff2", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "8080+2", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers", - "href": "http://example.net/path", - "new_value": "65535", - "expected": { - "href": "http://example.net:65535/path", - "host": "example.net:65535", - "hostname": "example.net", - "port": "65535" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error", - "href": "http://example.net:8080/path", - "new_value": "65536", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error", - "href": "non-special://example.net:8080/path", - "new_value": "65536", - "expected": { - "href": "non-special://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "href": "file://test/", - "new_value": "12", - "expected": { - "href": "file://test/", - "port": "" - } - }, - { - "href": "file://localhost/", - "new_value": "12", - "expected": { - "href": "file:///", - "port": "" - } - }, - { - "href": "non-base:value", - "new_value": "12", - "expected": { - "href": "non-base:value", - "port": "" - } - }, - { - "href": "sc:///", - "new_value": "12", - "expected": { - "href": "sc:///", - "port": "" - } - }, - { - "href": "sc://x/", - "new_value": "12", - "expected": { - "href": "sc://x:12/", - "port": "12" - } - }, - { - "href": "javascript://x/", - "new_value": "12", - "expected": { - "href": "javascript://x:12/", - "port": "12" - } - } - ], - "pathname": [ - { - "comment": "Cannot-be-a-base don’t have a path", - "href": "mailto:me@example.net", - "new_value": "/foo", - "expected": { - "href": "mailto:me@example.net", - "pathname": "me@example.net" - } - }, - { - "href": "unix:/run/foo.socket?timeout=10", - "new_value": "/var/log/../run/bar.socket", - "expected": { - "href": "unix:/var/run/bar.socket?timeout=10", - "pathname": "/var/run/bar.socket" - } - }, - { - "href": "https://example.net#nav", - "new_value": "home", - "expected": { - "href": "https://example.net/home#nav", - "pathname": "/home" - } - }, - { - "href": "https://example.net#nav", - "new_value": "../home", - "expected": { - "href": "https://example.net/home#nav", - "pathname": "/home" - } - }, - { - "comment": "\\ is a segment delimiter for 'special' URLs", - "href": "http://example.net/home?lang=fr#nav", - "new_value": "\\a\\%2E\\b\\%2e.\\c", - "expected": { - "href": "http://example.net/a/c?lang=fr#nav", - "pathname": "/a/c" - } - }, - { - "comment": "\\ is *not* a segment delimiter for non-'special' URLs", - "href": "view-source+http://example.net/home?lang=fr#nav", - "new_value": "\\a\\%2E\\b\\%2e.\\c", - "expected": { - "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav", - "pathname": "/\\a\\%2E\\b\\%2e.\\c" - } - }, - { - "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", - "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.", - "href": "http://example.net", - "new_value": "%2e%2E%c3%89té", - "expected": { - "href": "http://example.net/%2e%2E%c3%89t%C3%A9", - "pathname": "/%2e%2E%c3%89t%C3%A9" - } - }, - { - "comment": "? needs to be encoded", - "href": "http://example.net", - "new_value": "?", - "expected": { - "href": "http://example.net/%3F", - "pathname": "/%3F" - } - }, - { - "comment": "# needs to be encoded", - "href": "http://example.net", - "new_value": "#", - "expected": { - "href": "http://example.net/%23", - "pathname": "/%23" - } - }, - { - "comment": "? needs to be encoded, non-special scheme", - "href": "sc://example.net", - "new_value": "?", - "expected": { - "href": "sc://example.net/%3F", - "pathname": "/%3F" - } - }, - { - "comment": "# needs to be encoded, non-special scheme", - "href": "sc://example.net", - "new_value": "#", - "expected": { - "href": "sc://example.net/%23", - "pathname": "/%23" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file://monkey/", - "new_value": "\\\\", - "expected": { - "href": "file://monkey//", - "pathname": "//" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file:///unicorn", - "new_value": "//\\/", - "expected": { - "href": "file://////", - "pathname": "////" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file:///unicorn", - "new_value": "//monkey/..//", - "expected": { - "href": "file://///", - "pathname": "///" - } - } - ], - "search": [ - { - "href": "https://example.net#nav", - "new_value": "lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "?lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "??lang=fr", - "expected": { - "href": "https://example.net/??lang=fr#nav", - "search": "??lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "?", - "expected": { - "href": "https://example.net/?#nav", - "search": "" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "", - "expected": { - "href": "https://example.net/#nav", - "search": "" - } - }, - { - "href": "https://example.net?lang=en-US", - "new_value": "", - "expected": { - "href": "https://example.net/", - "search": "" - } - }, - { - "href": "https://example.net", - "new_value": "", - "expected": { - "href": "https://example.net/", - "search": "" - } - }, - { - "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", - "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://example.net/?%c3%89t%C3%A9", - "search": "?%c3%89t%C3%A9" - } - } + href: 'https://example.net?lang=en-US#nav', + new_value: '', + expected: { + href: 'https://example.net/?lang=en-US', + hash: '', + }, + }, + { + comment: + 'Simple percent-encoding; nuls, tabs, and newlines are removed', + href: 'a:/', + new_value: + '\u0000\u0001\t\n\r\u001f !"#$%&\'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé', + expected: { + href: "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + hash: "#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + }, + }, + { + comment: 'Bytes already percent-encoded are left as-is', + href: 'http://example.net', + new_value: '%c3%89té', + expected: { + href: 'http://example.net/#%c3%89t%C3%A9', + hash: '#%c3%89t%C3%A9', + }, + }, + { + href: 'javascript:alert(1)', + new_value: 'castle', + expected: { + href: 'javascript:alert(1)#castle', + hash: '#castle', + }, + }, ], - "hash": [ - { - "href": "https://example.net", - "new_value": "main", - "expected": { - "href": "https://example.net/#main", - "hash": "#main" - } - }, - { - "href": "https://example.net#nav", - "new_value": "main", - "expected": { - "href": "https://example.net/#main", - "hash": "#main" - } - }, - { - "href": "https://example.net?lang=en-US", - "new_value": "##nav", - "expected": { - "href": "https://example.net/?lang=en-US##nav", - "hash": "##nav" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "#main", - "expected": { - "href": "https://example.net/?lang=en-US#main", - "hash": "#main" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "#", - "expected": { - "href": "https://example.net/?lang=en-US#", - "hash": "" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "", - "expected": { - "href": "https://example.net/?lang=en-US", - "hash": "" - } - }, - { - "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", - "hash": "#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://example.net/#%c3%89t%C3%A9", - "hash": "#%c3%89t%C3%A9" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "castle", - "expected": { - "href": "javascript:alert(1)#castle", - "hash": "#castle" - } - } - ] }; for (const attribute in cases) { @@ -8686,7 +8729,7 @@ export const urlSetterTests = { strictEqual(url[attribute], test.expected[attribute]); }); } - } + }, }; export const wptTestURLSearchParamsConstructor = { @@ -8701,13 +8744,16 @@ export const wptTestURLSearchParamsConstructor = { strictEqual(params + '', 'a=b'); { - const params = new URLSearchParams() - strictEqual(params.toString(), "") + const params = new URLSearchParams(); + strictEqual(params.toString(), ''); } { const params = new URLSearchParams(DOMException); - strictEqual(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25") + strictEqual( + params.toString(), + 'INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25' + ); } { @@ -8717,7 +8763,7 @@ export const wptTestURLSearchParamsConstructor = { { const params = new URLSearchParams({}); - strictEqual(params + '', ""); + strictEqual(params + '', ''); } { @@ -8734,11 +8780,11 @@ export const wptTestURLSearchParamsConstructor = { ok(!params.has('c')); ok(params.has(' c')); ok(params.has('møø')); - }; + } { const seed = new URLSearchParams('a=b&c=d'); - const params = new URLSearchParams(seed); + const params = new URLSearchParams(seed); strictEqual(params.get('a'), 'b'); strictEqual(params.get('c'), 'd'); ok(!params.has('d')); @@ -8751,7 +8797,7 @@ export const wptTestURLSearchParamsConstructor = { } { - let params = new URLSearchParams('a=b+c'); + let params = new URLSearchParams('a=b+c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a+b=c'); strictEqual(params.get('a b'), 'c'); @@ -8769,68 +8815,71 @@ export const wptTestURLSearchParamsConstructor = { } { - let params = new URLSearchParams('a=b c'); + let params = new URLSearchParams('a=b c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a b=c'); strictEqual(params.get('a b'), 'c'); } { - let params = new URLSearchParams('a=b%20c'); + let params = new URLSearchParams('a=b%20c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a%20b=c'); strictEqual(params.get('a b'), 'c'); - }; + } { - let params = new URLSearchParams('a=b\0c'); + let params = new URLSearchParams('a=b\0c'); strictEqual(params.get('a'), 'b\0c'); params = new URLSearchParams('a\0b=c'); strictEqual(params.get('a\0b'), 'c'); } { - let params = new URLSearchParams('a=b%00c'); + let params = new URLSearchParams('a=b%00c'); strictEqual(params.get('a'), 'b\0c'); params = new URLSearchParams('a%00b=c'); strictEqual(params.get('a\0b'), 'c'); } { - let params = new URLSearchParams('a=b\u2384'); + let params = new URLSearchParams('a=b\u2384'); strictEqual(params.get('a'), 'b\u2384'); params = new URLSearchParams('a\u2384b=c'); strictEqual(params.get('a\u2384b'), 'c'); } { - let params = new URLSearchParams('a=b%e2%8e%84'); + let params = new URLSearchParams('a=b%e2%8e%84'); strictEqual(params.get('a'), 'b\u2384'); params = new URLSearchParams('a%e2%8e%84b=c'); strictEqual(params.get('a\u2384b'), 'c'); } { - let params = new URLSearchParams('a=b\uD83D\uDCA9c'); + let params = new URLSearchParams('a=b\uD83D\uDCA9c'); strictEqual(params.get('a'), 'b\uD83D\uDCA9c'); params = new URLSearchParams('a\uD83D\uDCA9b=c'); strictEqual(params.get('a\uD83D\uDCA9b'), 'c'); } { - let params = new URLSearchParams('a=b%f0%9f%92%a9c'); + let params = new URLSearchParams('a=b%f0%9f%92%a9c'); strictEqual(params.get('a'), 'b\uD83D\uDCA9c'); params = new URLSearchParams('a%f0%9f%92%a9b=c'); strictEqual(params.get('a\uD83D\uDCA9b'), 'c'); } { - let params = new URLSearchParams([]); - params = new URLSearchParams([['a', 'b'], ['c', 'd']]); - strictEqual(params.get("a"), "b"); - strictEqual(params.get("c"), "d"); + let params = new URLSearchParams([]); + params = new URLSearchParams([ + ['a', 'b'], + ['c', 'd'], + ]); + strictEqual(params.get('a'), 'b'); + strictEqual(params.get('c'), 'd'); throws(() => new URLSearchParams([[1]])); - throws(() => new URLSearchParams([[1,2,3]])); + throws(() => new URLSearchParams([[1, 2, 3]])); } { @@ -8843,27 +8892,44 @@ export const wptTestURLSearchParamsConstructor = { } [ - { "input": {"+": "%C2"}, "output": [["+", "%C2"]], "name": "object with +" }, - { "input": {c: "x", a: "?"}, "output": [["c", "x"], ["a", "?"]], "name": "object with two keys" }, - { "input": [["c", "x"], ["a", "?"]], "output": [["c", "x"], ["a", "?"]], "name": "array with two keys" }, + { input: { '+': '%C2' }, output: [['+', '%C2']], name: 'object with +' }, + { + input: { c: 'x', a: '?' }, + output: [ + ['c', 'x'], + ['a', '?'], + ], + name: 'object with two keys', + }, + { + input: [ + ['c', 'x'], + ['a', '?'], + ], + output: [ + ['c', 'x'], + ['a', '?'], + ], + name: 'array with two keys', + }, ].forEach((val) => { let params = new URLSearchParams(val.input); let i = 0; for (let param of params) { - deepStrictEqual(param, val.output[i]) - i++ + deepStrictEqual(param, val.output[i]); + i++; } - }) + }); { - const params = new URLSearchParams() - params[Symbol.iterator] = function *() { - yield ["a", "b"] - } - let params2 = new URLSearchParams(params) - strictEqual(params2.get("a"), "b") + const params = new URLSearchParams(); + params[Symbol.iterator] = function* () { + yield ['a', 'b']; + }; + let params2 = new URLSearchParams(params); + strictEqual(params2.get('a'), 'b'); } - } + }, }; export const w3cTestURLSearchParamsAppend = { @@ -8907,7 +8973,7 @@ export const w3cTestURLSearchParamsAppend = { params.append('first', 10); strictEqual(params.get('first'), '1'); } - } + }, }; export const w3cTestURLSearchParamsDelete = { @@ -8957,7 +9023,7 @@ export const w3cTestURLSearchParamsDelete = { strictEqual(url.href, 'http://example.com/'); strictEqual(url.search, ''); } - } + }, }; export const w3cTestURLSearchParamsGet = { @@ -8983,7 +9049,7 @@ export const w3cTestURLSearchParamsGet = { strictEqual(params.get('third'), ''); strictEqual(params.get('fourth'), null); } - } + }, }; export const w3cTestURLSearchParamsGetAll = { @@ -9005,7 +9071,10 @@ export const w3cTestURLSearchParamsGetAll = { let params = new URLSearchParams('a=1&a=2&a=3&a'); ok(params.has('a')); var matches = params.getAll('a'); - ok(matches && matches.length == 4, 'Search params object has values for name "a"'); + ok( + matches && matches.length == 4, + 'Search params object has values for name "a"' + ); deepStrictEqual(matches, ['1', '2', '3', '']); params.set('a', 'one'); strictEqual(params.get('a'), 'one'); @@ -9013,7 +9082,7 @@ export const w3cTestURLSearchParamsGetAll = { ok(matches && matches.length == 1); deepStrictEqual(matches, ['one']); } - } + }, }; export const w3cTestURLSearchParamsHas = { @@ -9042,20 +9111,20 @@ export const w3cTestURLSearchParamsHas = { params.delete('first'); ok(!params.has('first')); } - } + }, }; export const w3cTestURLSearchParamsSet = { test() { - { + { let params = new URLSearchParams('a=b&c=d'); params.set('a', 'B'); strictEqual(params + '', 'a=B&c=d'); params = new URLSearchParams('a=b&c=d&a=e'); params.set('a', 'B'); - strictEqual(params + '', 'a=B&c=d') + strictEqual(params + '', 'a=B&c=d'); params.set('e', 'f'); - strictEqual(params + '', 'a=B&c=d&e=f') + strictEqual(params + '', 'a=B&c=d&e=f'); } { @@ -9069,63 +9138,94 @@ export const w3cTestURLSearchParamsSet = { ok(params.has('a')); strictEqual(params.get('a'), '4'); } - } + }, }; export const w3cTestURLSearchParamsSort = { test() { [ { - "input": "z=b&a=b&z=a&a=a", - "output": [["a", "b"], ["a", "a"], ["z", "b"], ["z", "a"]] - }, - { - "input": "\uFFFD=x&\uFFFC&\uFFFD=a", - "output": [["\uFFFC", ""], ["\uFFFD", "x"], ["\uFFFD", "a"]] - }, - { - "input": "ffi&🌈", // 🌈 > code point, but < code unit because two code units - "output": [["ffi", ""], ["🌈", ""]] - }, - { - "input": "é&e\uFFFD&e\u0301", - "output": [["e\u0301", ""], ["e\uFFFD", ""], ["é", ""]] + input: 'z=b&a=b&z=a&a=a', + output: [ + ['a', 'b'], + ['a', 'a'], + ['z', 'b'], + ['z', 'a'], + ], + }, + { + input: '\uFFFD=x&\uFFFC&\uFFFD=a', + output: [ + ['\uFFFC', ''], + ['\uFFFD', 'x'], + ['\uFFFD', 'a'], + ], + }, + { + input: 'ffi&🌈', // 🌈 > code point, but < code unit because two code units + output: [ + ['ffi', ''], + ['🌈', ''], + ], + }, + { + input: 'é&e\uFFFD&e\u0301', + output: [ + ['e\u0301', ''], + ['e\uFFFD', ''], + ['é', ''], + ], + }, + { + input: 'z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g', + output: [ + ['a', 'a'], + ['a', 'b'], + ['a', 'c'], + ['a', 'd'], + ['a', 'e'], + ['a', 'f'], + ['a', 'g'], + ['z', 'z'], + ['z', 'y'], + ['z', 'x'], + ['z', 'w'], + ['z', 'v'], + ['z', 'u'], + ['z', 't'], + ], }, - { - "input": "z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g", - "output": [["a", "a"], ["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"], ["a", "g"], ["z", "z"], ["z", "y"], ["z", "x"], ["z", "w"], ["z", "v"], ["z", "u"], ["z", "t"]] - } ].forEach((val) => { { const params = new URLSearchParams(val.input); let i = 0; - params.sort() - for(let param of params) { - deepStrictEqual(param, val.output[i]) - i++ + params.sort(); + for (let param of params) { + deepStrictEqual(param, val.output[i]); + i++; } } { - const url = new URL("?" + val.input, "https://example/") - url.searchParams.sort() + const url = new URL('?' + val.input, 'https://example/'); + url.searchParams.sort(); const params = new URLSearchParams(url.search); let i = 0; - for(let param of params) { + for (let param of params) { deepStrictEqual(param, val.output[i]); i++; } } - }) + }); { - const url = new URL("http://example.com/?") - url.searchParams.sort() - strictEqual(url.href, "http://example.com/") - strictEqual(url.search, "") + const url = new URL('http://example.com/?'); + url.searchParams.sort(); + strictEqual(url.href, 'http://example.com/'); + strictEqual(url.search, ''); } - } -} + }, +}; export const w3cTestURLSearchParamsStringifier = { test() { @@ -9251,22 +9351,19 @@ export const w3cTestURLSearchParamsStringifier = { strictEqual(url.toString(), 'http://www.example.com/?a=b%2Cc&x=y'); strictEqual(params.toString(), 'a=b%2Cc&x=y'); } - } + }, }; export const urlSetSearch = { test() { - const url = new URL("http://example.com?foo=bar&baz=qux"); - url.search = "?quux=corge&grault=garply"; + const url = new URL('http://example.com?foo=bar&baz=qux'); + url.search = '?quux=corge&grault=garply'; const result = []; for (let param of url.searchParams) { - result.push(param.join(":")); + result.push(param.join(':')); } - deepStrictEqual(result, [ - 'quux:corge', - 'grault:garply' - ]); - } + deepStrictEqual(result, ['quux:corge', 'grault:garply']); + }, }; export const urlSegfaultRegression = { @@ -9276,9 +9373,9 @@ export const urlSegfaultRegression = { // nondeterministic crash during URL/URLSearchParams destruction. It triggered an assertion // under debug mode when the `searchParams` property was accessed, which this test is designed // to express. - url.protocol = "http:"; - strictEqual(url.searchParams.toString(), "foo=bar&baz=qux"); - } + url.protocol = 'http:'; + strictEqual(url.searchParams.toString(), 'foo=bar&baz=qux'); + }, }; // ====================================================================================== @@ -9288,14 +9385,14 @@ export const urlPatternBasics = { const urlPattern = new URLPattern(); // The standard attributes exist as they should and are readonly - strictEqual(urlPattern.protocol, "*"); - strictEqual(urlPattern.username, "*"); - strictEqual(urlPattern.password, "*"); - strictEqual(urlPattern.hostname, "*"); - strictEqual(urlPattern.port, "*"); - strictEqual(urlPattern.pathname, "*"); - strictEqual(urlPattern.search, "*"); - strictEqual(urlPattern.hash, "*"); + strictEqual(urlPattern.protocol, '*'); + strictEqual(urlPattern.username, '*'); + strictEqual(urlPattern.password, '*'); + strictEqual(urlPattern.hostname, '*'); + strictEqual(urlPattern.port, '*'); + strictEqual(urlPattern.pathname, '*'); + strictEqual(urlPattern.search, '*'); + strictEqual(urlPattern.hash, '*'); strictEqual(typeof urlPattern.exec, 'function'); strictEqual(typeof urlPattern.test, 'function'); @@ -9336,24 +9433,28 @@ export const urlPatternBasics = { count++; return super.hash; } - test() { return true; } - exec() { return true; } + test() { + return true; + } + exec() { + return true; + } } const myPattern = new MyURLPattern(); - strictEqual(myPattern.protocol, "*"); - strictEqual(myPattern.username, "*"); - strictEqual(myPattern.password, "*"); - strictEqual(myPattern.hostname, "*"); - strictEqual(myPattern.port, "*"); - strictEqual(myPattern.pathname, "*"); - strictEqual(myPattern.search, "*"); - strictEqual(myPattern.hash, "*"); + strictEqual(myPattern.protocol, '*'); + strictEqual(myPattern.username, '*'); + strictEqual(myPattern.password, '*'); + strictEqual(myPattern.hostname, '*'); + strictEqual(myPattern.port, '*'); + strictEqual(myPattern.pathname, '*'); + strictEqual(myPattern.search, '*'); + strictEqual(myPattern.hash, '*'); strictEqual(myPattern.exec(), true); strictEqual(myPattern.test(), true); strictEqual(count, 8); } - } + }, }; export const urlPatternMdn1 = { @@ -9364,28 +9465,31 @@ export const urlPatternMdn1 = { const res = pattern.exec('https://example.com/books'); strictEqual(res.inputs[0], 'https://example.com/books'); strictEqual(res.protocol.input, 'https'); - strictEqual(res.protocol.groups["0"], "https"); - strictEqual(res.username.input, ""); - strictEqual(res.username.groups["0"], ""); - strictEqual(res.password.input, ""); - strictEqual(res.password.groups["0"], ""); - strictEqual(res.hostname.input, "example.com"); - strictEqual(res.hostname.groups["0"], "example.com"); - strictEqual(res.pathname.input, "/books"); + strictEqual(res.protocol.groups['0'], 'https'); + strictEqual(res.username.input, ''); + strictEqual(res.username.groups['0'], ''); + strictEqual(res.password.input, ''); + strictEqual(res.password.groups['0'], ''); + strictEqual(res.hostname.input, 'example.com'); + strictEqual(res.hostname.groups['0'], 'example.com'); + strictEqual(res.pathname.input, '/books'); deepStrictEqual(Object.keys(res.pathname.groups), []); - strictEqual(res.search.input, ""); - strictEqual(res.search.groups["0"], ""); - strictEqual(res.hash.input, ""); - strictEqual(res.hash.groups["0"], ""); - } + strictEqual(res.search.input, ''); + strictEqual(res.search.groups['0'], ''); + strictEqual(res.hash.input, ''); + strictEqual(res.hash.groups['0'], ''); + }, }; export const urlPatternMdn2 = { test() { const pattern = new URLPattern({ pathname: '/books/:id' }); ok(pattern.test('https://example.com/books/123')); - strictEqual(pattern.exec('https://example.com/books/123').pathname.groups.id, "123"); - } + strictEqual( + pattern.exec('https://example.com/books/123').pathname.groups.id, + '123' + ); + }, }; export const urlPatternMdn3 = { @@ -9394,7 +9498,7 @@ export const urlPatternMdn3 = { ok(pattern.test('https://example.com/books/123')); ok(!pattern.test('https://example.com/books/abc')); ok(!pattern.test('https://example.com/books/')); - } + }, }; export const urlPatternMdn4 = { @@ -9402,21 +9506,27 @@ export const urlPatternMdn4 = { const pattern = new URLPattern({ pathname: '/:type(foo|bar)' }); const result = pattern.exec({ pathname: '/foo' }); strictEqual(result.pathname.groups.type, 'foo'); - } + }, }; export const urlPatternMdn5 = { test() { const pattern = new URLPattern('/books/:id(\\d+)', 'https://example.com'); - strictEqual(pattern.exec('https://example.com/books/123').pathname.groups.id, "123"); - } + strictEqual( + pattern.exec('https://example.com/books/123').pathname.groups.id, + '123' + ); + }, }; export const urlPatternMdn6 = { test() { const pattern = new URLPattern('/books/(\\d+)', 'https://example.com'); - strictEqual(pattern.exec('https://example.com/books/123').pathname.groups["0"], "123"); - } + strictEqual( + pattern.exec('https://example.com/books/123').pathname.groups['0'], + '123' + ); + }, }; export const urlPatternMdn7 = { @@ -9427,7 +9537,7 @@ export const urlPatternMdn7 = { ok(!pattern.test('https://example.com/books/')); ok(!pattern.test('https://example.com/books/123/456')); ok(!pattern.test('https://example.com/books/123/456/789')); - } + }, }; export const urlPatternMdn8 = { @@ -9439,7 +9549,7 @@ export const urlPatternMdn8 = { ok(!pattern.test('https://example.com/books/')); ok(pattern.test('https://example.com/books/123/456')); ok(pattern.test('https://example.com/books/123/456/789')); - } + }, }; export const urlPatternMdn9 = { @@ -9450,7 +9560,7 @@ export const urlPatternMdn9 = { ok(!pattern.test('https://example.com/books/')); ok(pattern.test('https://example.com/books/123/456')); ok(pattern.test('https://example.com/books/123/456/789')); - } + }, }; export const urlPatternMdn10 = { @@ -9458,8 +9568,11 @@ export const urlPatternMdn10 = { const pattern = new URLPattern('/book{s}?', 'https://example.com'); ok(pattern.test('https://example.com/books')); ok(pattern.test('https://example.com/book')); - deepStrictEqual(Object.keys(pattern.exec('https://example.com/books').pathname.groups), []); - } + deepStrictEqual( + Object.keys(pattern.exec('https://example.com/books').pathname.groups), + [] + ); + }, }; export const urlPatternMdn11 = { @@ -9469,7 +9582,7 @@ export const urlPatternMdn11 = { strictEqual(pattern.pathname, '/books'); ok(pattern.test('https://example.com/books')); ok(!pattern.test('https://example.com/book')); - } + }, }; export const urlPatternMdn12 = { @@ -9479,7 +9592,7 @@ export const urlPatternMdn12 = { ok(pattern.test('https://example.com/blog/123-my-blog')); ok(pattern.test('https://example.com/blog/123')); ok(!pattern.test('https://example.com/blog/my-blog')); - } + }, }; export const urlPatternMdn13 = { @@ -9488,7 +9601,7 @@ export const urlPatternMdn13 = { ok(pattern.test('https://example.com/books/123')); ok(pattern.test('https://example.com/books')); ok(!pattern.test('https://example.com/books/')); - } + }, }; export const urlPatternMdn14 = { @@ -9498,7 +9611,7 @@ export const urlPatternMdn14 = { ok(pattern.test('https://example.com/books/123/456')); ok(!pattern.test('https://example.com/books/123/')); ok(!pattern.test('https://example.com/books/123/456/')); - } + }, }; export const urlPatternMdn15 = { @@ -9507,7 +9620,7 @@ export const urlPatternMdn15 = { ok(pattern.test('https://example.com#/books/123')); ok(!pattern.test('https://example.com#/books')); ok(pattern.test('https://example.com#/books/')); - } + }, }; export const urlPatternMdn16 = { @@ -9516,7 +9629,7 @@ export const urlPatternMdn16 = { ok(pattern.test('https://example.com/books/123')); ok(!pattern.test('https://example.com/books')); ok(pattern.test('https://example.com/books/')); - } + }, }; export const urlPatternMdn17 = { @@ -9526,7 +9639,7 @@ export const urlPatternMdn17 = { ok(!pattern.test('https://example.com/books')); ok(pattern.test('https://example.com/books/')); ok(pattern.test('https://example.com/books/123/456')); - } + }, }; export const urlPatternMdn18 = { @@ -9536,7 +9649,7 @@ export const urlPatternMdn18 = { ok(!pattern.test('https://example.com/image.png/123')); ok(pattern.test('https://example.com/folder/image.png')); ok(pattern.test('https://example.com/.png')); - } + }, }; export const urlPatternMdn19 = { @@ -9546,18 +9659,18 @@ export const urlPatternMdn19 = { const pattern = new URLPattern({ hostname: '{*.}?example.com', }); - strictEqual(pattern.hostname, "{*.}?example.com"); - strictEqual(pattern.protocol, "*"); - strictEqual(pattern.username, "*"); - strictEqual(pattern.password, "*"); - strictEqual(pattern.pathname, "*"); - strictEqual(pattern.search, "*"); - strictEqual(pattern.hash, "*"); + strictEqual(pattern.hostname, '{*.}?example.com'); + strictEqual(pattern.protocol, '*'); + strictEqual(pattern.username, '*'); + strictEqual(pattern.password, '*'); + strictEqual(pattern.pathname, '*'); + strictEqual(pattern.search, '*'); + strictEqual(pattern.hash, '*'); ok(pattern.test('https://example.com/foo/bar')); ok(pattern.test({ hostname: 'cdn.example.com' })); ok(pattern.test('custom-protocol://example.com/other/path?q=1')); ok(!pattern.test('https://cdn-example.com/foo/bar')); - } + }, }; export const urlPatternMdn20 = { @@ -9571,26 +9684,33 @@ export const urlPatternMdn20 = { strictEqual(pattern.pathname, '/*.jpg'); strictEqual(pattern.username, ''); strictEqual(pattern.password, ''); - strictEqual(pattern.search, ""); - strictEqual(pattern.hash, ""); - ok(pattern.test("https://cdn-1234.example.com/product/assets/hero.jpg")); - ok(!pattern.test("https://cdn-1234.example.com/product/assets/hero.jpg?q=1")); - } + strictEqual(pattern.search, ''); + strictEqual(pattern.hash, ''); + ok(pattern.test('https://cdn-1234.example.com/product/assets/hero.jpg')); + ok( + !pattern.test('https://cdn-1234.example.com/product/assets/hero.jpg?q=1') + ); + }, }; export const urlPatternMdn21 = { test() { throws(() => new URLPattern('data:foo*')); - } + }, }; export const urlPatternMdn22 = { test() { - const pattern = new URLPattern({ hostname: 'example.com', pathname: '/foo/*' }); - ok(pattern.test({ - pathname: '/foo/bar', - baseURL: 'https://example.com/baz', - })); + const pattern = new URLPattern({ + hostname: 'example.com', + pathname: '/foo/*', + }); + ok( + pattern.test({ + pathname: '/foo/bar', + baseURL: 'https://example.com/baz', + }) + ); ok(pattern.test('/foo/bar', 'https://example.com/baz')); // Throws because the second argument cannot be passed with a dictionary input. throws(() => { @@ -9601,13 +9721,15 @@ export const urlPatternMdn22 = { strictEqual(result.pathname.input, '/foo/bar'); strictEqual(result.pathname.groups[0], 'bar'); strictEqual(result.hostname.input, 'example.com'); - } + }, }; export const urlPatternMdn23 = { test() { - const pattern1 = new URLPattern({ pathname: '/foo/*', - baseURL: 'https://example.com' }); + const pattern1 = new URLPattern({ + pathname: '/foo/*', + baseURL: 'https://example.com', + }); strictEqual(pattern1.protocol, 'https'); strictEqual(pattern1.hostname, 'example.com'); strictEqual(pattern1.pathname, '/foo/*'); @@ -9618,7 +9740,7 @@ export const urlPatternMdn23 = { strictEqual(pattern1.hash, ''); new URLPattern('/foo/*', 'https://example.com'); throws(() => new URLPattern('/foo/*')); - } + }, }; export const urlPatternMdn24 = { @@ -9628,7 +9750,7 @@ export const urlPatternMdn24 = { strictEqual(result.hostname.groups[0], 'cdn'); strictEqual(result.hostname.input, 'cdn.example.com'); strictEqual(result.inputs?.[0].hostname, 'cdn.example.com'); - } + }, }; export const urlPatternMdn25 = { @@ -9643,7 +9765,7 @@ export const urlPatternMdn25 = { strictEqual(result.pathname.groups.action, 'view'); strictEqual(result.pathname.input, '/store/wanderview/view'); strictEqual(result.inputs?.[0].pathname, '/store/wanderview/view'); - } + }, }; export const urlPattern26 = { @@ -9652,7 +9774,7 @@ export const urlPattern26 = { const result = pattern.exec({ pathname: '/product/do/some/thing/cool' }); strictEqual(result.pathname.groups.action, 'do/some/thing/cool'); ok(!pattern.test({ pathname: '/product' })); - } + }, }; export const urlPattern27 = { @@ -9661,7 +9783,7 @@ export const urlPattern27 = { const result = pattern.exec({ pathname: '/product/do/some/thing/cool' }); strictEqual(result.pathname.groups.action, 'do/some/thing/cool'); ok(pattern.test({ pathname: '/product' })); - } + }, }; export const urlPattern28 = { @@ -9672,7 +9794,7 @@ export const urlPattern28 = { ok(!pattern.test({ hostname: '.example.com' })); const result = pattern.exec({ hostname: 'foo.bar.example.com' }); strictEqual(result.hostname.groups.subdomain, 'foo.bar'); - } + }, }; export const urlPattern29 = { @@ -9682,7 +9804,7 @@ export const urlPattern29 = { ok(pattern.test({ pathname: '/product/' })); const result = pattern.exec({ pathname: '/product/' }); deepStrictEqual(Object.keys(result.pathname.groups), []); - } + }, }; export const urlPattern32 = { @@ -9696,14 +9818,14 @@ export const urlPattern32 = { }); const result = pattern.exec( - 'http://foo:bar@sub.example.com/product/view?q=12345', + 'http://foo:bar@sub.example.com/product/view?q=12345' ); strictEqual(result.username.groups.user, 'foo'); strictEqual(result.password.groups.pass, 'bar'); strictEqual(result.hostname.groups.subdomain, 'sub'); strictEqual(result.pathname.groups.action, 'view'); - } + }, }; export const urlPattern33 = { @@ -9719,7 +9841,7 @@ export const urlPattern33 = { strictEqual(pattern.search, ''); strictEqual(pattern.hash, ''); ok(pattern.test('data:foobar')); - } + }, }; export const urlPattern34 = { @@ -9730,7 +9852,7 @@ export const urlPattern34 = { ok(!pattern.test({ pathname: '/baz' })); const result = pattern.exec({ pathname: '/foo' }); strictEqual(result.pathname.groups[0], 'foo'); - } + }, }; export const urlPatternMdn35 = { @@ -9748,33 +9870,33 @@ export const urlPatternMdn35 = { ok(pattern3.test({ pathname: '/product/wanderview/view' })); ok(pattern3.test({ pathname: '/product' })); ok(pattern3.test({ pathname: '/product/' })); - } + }, }; export const urlPatternFun = { test() { // The pattern is not useful but it should parse and produce the // same results we see in the browser. - const pattern = new URLPattern(":café://:\u1234/:_✔️"); - strictEqual(pattern.protocol, ":café") - strictEqual(pattern.hostname, ":ሴ"); - strictEqual(pattern.pathname, "/:_%E2%9C%94%EF%B8%8F"); + const pattern = new URLPattern(':café://:\u1234/:_✔️'); + strictEqual(pattern.protocol, ':café'); + strictEqual(pattern.hostname, ':ሴ'); + strictEqual(pattern.pathname, '/:_%E2%9C%94%EF%B8%8F'); { // There was a bug that would cause a crash. Instead the following should throw // as invalid URLPattern syntax. - throws(() => new URLPattern({ hash: "=((" })); + throws(() => new URLPattern({ hash: '=((' })); } - } + }, }; export const urlPatternPortRegression = { test() { - const pattern = new URLPattern({pathname: "/graphql"}); - const url = new URL("http://localhost:53000/"); + const pattern = new URLPattern({ pathname: '/graphql' }); + const url = new URL('http://localhost:53000/'); // Shouldn't match, but also shouldn't throw ok(!pattern.test(url)); - } + }, }; export const urlParseStatic = { @@ -9791,7 +9913,7 @@ export const urlParseStatic = { // Unlike `new URL(...)` the `URL.parse(...)` function does not throw on invalid URLs // (which is the key point) strictEqual(URL.parse('not valid'), null); - } + }, }; export const urlSearchParamsPipe = { @@ -9799,5 +9921,5 @@ export const urlSearchParamsPipe = { const url = new URL('http://example.com/?a=b%7Cc'); strictEqual(url.search, '?a=b%7Cc'); strictEqual(url.searchParams.toString(), 'a=b%7Cc'); - } + }, }; diff --git a/src/workerd/api/tests/websocket-hibernation.js b/src/workerd/api/tests/websocket-hibernation.js index 4dca4094f91..3519fcca791 100644 --- a/src/workerd/api/tests/websocket-hibernation.js +++ b/src/workerd/api/tests/websocket-hibernation.js @@ -18,15 +18,15 @@ export class DurableObjectExample { let pair = new WebSocketPair(); let server = pair[0]; - if (request.url.endsWith("/hibernation")) { + if (request.url.endsWith('/hibernation')) { this.state.acceptWebSocket(server); } else { server.accept(); - server.addEventListener("message", () => { - server.send("regular message from DO"); - }) - server.addEventListener("close", () => { - server.close(1000, "regular close from DO"); + server.addEventListener('message', () => { + server.send('regular message from DO'); + }); + server.addEventListener('close', () => { + server.close(1000, 'regular close from DO'); }); } @@ -37,17 +37,17 @@ export class DurableObjectExample { } webSocketMessage(ws) { - ws.send(`Hibernatable message from DO.`) + ws.send(`Hibernatable message from DO.`); } webSocketClose(ws, code, reason, wasClean) { - ws.close(1000, "Hibernatable close from DO"); + ws.close(1000, 'Hibernatable close from DO'); } } export default { async test(ctrl, env, ctx) { - let id = env.ns.idFromName("foo"); + let id = env.ns.idFromName('foo'); let obj = env.ns.get(id); // Test to make sure that we can call ws.close() from the DO's close handler. @@ -60,27 +60,31 @@ export default { let ws = req.webSocket; if (!ws) { - return new Error("Failed to get ws"); + return new Error('Failed to get ws'); } ws.accept(); let prom = new Promise((resolve, reject) => { - ws.addEventListener("close", (close) => { - if (close.code != 1000 & close.reason != expected) { + ws.addEventListener('close', (close) => { + if ((close.code != 1000) & (close.reason != expected)) { reject(`got ${close.reason}`); } resolve(); }); }); - ws.send("Hi from Worker!") - ws.close(1000, "bye from Worker!") + ws.send('Hi from Worker!'); + ws.close(1000, 'bye from Worker!'); await prom; - } + }; // Normal websocket - await webSocketTest(obj, "http://example.com/", "regular close from DO"); + await webSocketTest(obj, 'http://example.com/', 'regular close from DO'); // Hibernatable Websocket. - await webSocketTest(obj, "http://example.com/hibernation", "Hibernatable close from DO"); - } -} + await webSocketTest( + obj, + 'http://example.com/hibernation', + 'Hibernatable close from DO' + ); + }, +}; diff --git a/src/workerd/api/tsconfig.json b/src/workerd/api/tsconfig.json index cb5c6eef1c5..f39472cd559 100644 --- a/src/workerd/api/tsconfig.json +++ b/src/workerd/api/tsconfig.json @@ -18,5 +18,5 @@ "skipLibCheck": true }, "include": ["**/*.ts"], - "exclude": [], + "exclude": [] } diff --git a/src/workerd/jsg/resource-test-bootstrap.js b/src/workerd/jsg/resource-test-bootstrap.js index 3cafe6f5ae0..b28e1c153c6 100644 --- a/src/workerd/jsg/resource-test-bootstrap.js +++ b/src/workerd/jsg/resource-test-bootstrap.js @@ -1,9 +1,9 @@ export function bootstrapFunction() { - return "THIS_IS_BOOTSTRAP_FUNCTION"; + return 'THIS_IS_BOOTSTRAP_FUNCTION'; } export class BootstrapClass { run() { - return "THIS_IS_BOOTSTRAP_CLASS"; + return 'THIS_IS_BOOTSTRAP_CLASS'; } } diff --git a/src/workerd/jsg/resource-test-builtin.js b/src/workerd/jsg/resource-test-builtin.js index 195603a53a6..4f997e75a60 100644 --- a/src/workerd/jsg/resource-test-builtin.js +++ b/src/workerd/jsg/resource-test-builtin.js @@ -1,3 +1,3 @@ export function builtinFunction() { - return "THIS_IS_BUILTIN_FUNCTION"; + return 'THIS_IS_BUILTIN_FUNCTION'; } diff --git a/src/workerd/server/tests/extensions/binding.js b/src/workerd/server/tests/extensions/binding.js index 7b3f99c28ee..f4bffe8e764 100644 --- a/src/workerd/server/tests/extensions/binding.js +++ b/src/workerd/server/tests/extensions/binding.js @@ -4,15 +4,14 @@ export function wrap(env) { if (!env.secret) { - throw new Error("secret internal binding is not specified"); + throw new Error('secret internal binding is not specified'); } return { tryOpen(key) { return key === env.secret; - } - } + }, + }; } - export default wrap; diff --git a/src/workerd/server/tests/extensions/extensions-test.js b/src/workerd/server/tests/extensions/extensions-test.js index 582ef934d72..b5051dc1b24 100644 --- a/src/workerd/server/tests/extensions/extensions-test.js +++ b/src/workerd/server/tests/extensions/extensions-test.js @@ -2,47 +2,46 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from "node:assert"; -import { openDoor } from "test:module"; - +import * as assert from 'node:assert'; +import { openDoor } from 'test:module'; export const test_module_api = { test() { - assert.throws(() => openDoor("test key")); - assert.equal(openDoor("0p3n s3sam3"), true); - } + assert.throws(() => openDoor('test key')); + assert.equal(openDoor('0p3n s3sam3'), true); + }, }; export const test_builtin_dynamic_import = { async test() { - await assert.doesNotReject(import("test:module")); - } -} + await assert.doesNotReject(import('test:module')); + }, +}; // internal modules can't be imported export const test_builtin_internal_dynamic_import = { async test() { - await assert.rejects(import("test-internal:internal-module")); - } -} + await assert.rejects(import('test-internal:internal-module')); + }, +}; export const test_wrapped_binding = { async test(ctr, env) { - assert.ok(env.door, "binding is not present"); - assert.equal(typeof(env.door), "object"); + assert.ok(env.door, 'binding is not present'); + assert.equal(typeof env.door, 'object'); assert.ok(env.door.tryOpen); - assert.equal(typeof(env.door.tryOpen), "function"); + assert.equal(typeof env.door.tryOpen, 'function'); // binding uses a different secret specified in the config - assert.ok(env.door.tryOpen("open sesame")); - assert.ok(!env.door.tryOpen("bad secret")); + assert.ok(env.door.tryOpen('open sesame')); + assert.ok(!env.door.tryOpen('bad secret')); // check there are no other properties available - assert.deepEqual(Object.keys(env.door), ["tryOpen"]); - assert.deepEqual(Object.getOwnPropertyNames(env.door), ["tryOpen"]); - - assert.ok(env.customDoor, "custom binding is not present"); - assert.ok(!env.customDoor.tryOpen("open sesame")); - assert.ok(env.customDoor.tryOpen("custom open sesame")); - } -} + assert.deepEqual(Object.keys(env.door), ['tryOpen']); + assert.deepEqual(Object.getOwnPropertyNames(env.door), ['tryOpen']); + + assert.ok(env.customDoor, 'custom binding is not present'); + assert.ok(!env.customDoor.tryOpen('open sesame')); + assert.ok(env.customDoor.tryOpen('custom open sesame')); + }, +}; diff --git a/src/workerd/server/tests/extensions/internal-module.js b/src/workerd/server/tests/extensions/internal-module.js index 8eee6e6da53..c3baafe3fd0 100644 --- a/src/workerd/server/tests/extensions/internal-module.js +++ b/src/workerd/server/tests/extensions/internal-module.js @@ -3,5 +3,5 @@ // https://opensource.org/licenses/Apache-2.0 export default { - caveKey: "0p3n s3sam3", -} + caveKey: '0p3n s3sam3', +}; diff --git a/src/workerd/server/tests/extensions/module.js b/src/workerd/server/tests/extensions/module.js index 70c88f014ac..9cf61f8a0a4 100644 --- a/src/workerd/server/tests/extensions/module.js +++ b/src/workerd/server/tests/extensions/module.js @@ -2,9 +2,9 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import secret from "test-internal:internal-module"; +import secret from 'test-internal:internal-module'; export function openDoor(key) { - if (key != secret.caveKey) throw new Error("Wrong key: " + key); + if (key != secret.caveKey) throw new Error('Wrong key: ' + key); return true; } diff --git a/src/workerd/server/tests/inspector/driver.mjs b/src/workerd/server/tests/inspector/driver.mjs index 21d44ac7db4..00b34aa908c 100644 --- a/src/workerd/server/tests/inspector/driver.mjs +++ b/src/workerd/server/tests/inspector/driver.mjs @@ -1,14 +1,20 @@ -import { env } from "node:process"; -import { beforeEach, afterEach, test } from "node:test"; -import assert from "node:assert"; -import CDP from "chrome-remote-interface"; -import { WorkerdServerHarness } from "@workerd/test/server-harness.mjs"; +import { env } from 'node:process'; +import { beforeEach, afterEach, test } from 'node:test'; +import assert from 'node:assert'; +import CDP from 'chrome-remote-interface'; +import { WorkerdServerHarness } from '@workerd/test/server-harness.mjs'; // Global that is reset for each test. let workerd; -assert(env.WORKERD_BINARY !== undefined, "You must set the WORKERD_BINARY environment variable."); -assert(env.WORKERD_CONFIG !== undefined, "You must set the WORKERD_CONFIG environment variable."); +assert( + env.WORKERD_BINARY !== undefined, + 'You must set the WORKERD_BINARY environment variable.' +); +assert( + env.WORKERD_CONFIG !== undefined, + 'You must set the WORKERD_CONFIG environment variable.' +); // Start workerd. beforeEach(async () => { @@ -17,7 +23,7 @@ beforeEach(async () => { workerdConfig: env.WORKERD_CONFIG, // Hard-coded to match a socket name expected in the `workerdConfig` file. - listenPortNames: [ "http" ], + listenPortNames: ['http'], }); await workerd.start(); @@ -26,7 +32,7 @@ beforeEach(async () => { // Stop workerd. afterEach(async () => { const [code, signal] = await workerd.stop(); - assert(code === 0 || signal === "SIGTERM"); + assert(code === 0 || signal === 'SIGTERM'); workerd = null; }); @@ -35,7 +41,7 @@ async function connectInspector(port) { port, // Hard-coded to match a service name expected in the `workerdConfig` file. - target: "/main", + target: '/main', // Required to avoid trying to load the Protocol (schema, I guess?) from workerd, which doesn't // implement the inspector protocol message in question. @@ -45,12 +51,14 @@ async function connectInspector(port) { // TODO(soon): This test reproduces a null pointer dereference in workerd (possibly the same issue // as https://github.com/cloudflare/workerd/issues/2564), but the test doesn't fail. :( -test("Can repeatedly connect and disconnect to the inspector port", async () => { +test('Can repeatedly connect and disconnect to the inspector port', async () => { for (let i = 0; i < 5; ++i) { - let inspectorClient = await connectInspector(await workerd.getListenInspectorPort()); + let inspectorClient = await connectInspector( + await workerd.getListenInspectorPort() + ); // Drive the worker with a test request. - let httpPort = await workerd.getListenPort("http"); + let httpPort = await workerd.getListenPort('http'); const response = await fetch(`http://localhost:${httpPort}`); let body = await response.arrayBuffer(); console.log(body); diff --git a/src/workerd/server/tests/inspector/index.mjs b/src/workerd/server/tests/inspector/index.mjs index 7a8d837bc5e..29af26ddfcd 100644 --- a/src/workerd/server/tests/inspector/index.mjs +++ b/src/workerd/server/tests/inspector/index.mjs @@ -1,23 +1,28 @@ // index.mjs -import { Buffer } from "node:buffer"; +import { Buffer } from 'node:buffer'; const encoder = new TextEncoder(); async function pbkdf2Derive(password) { const passwordArray = encoder.encode(password); const passwordKey = await crypto.subtle.importKey( - "raw", passwordArray, "PBKDF2", false, ["deriveBits"] + 'raw', + passwordArray, + 'PBKDF2', + false, + ['deriveBits'] ); const saltArray = crypto.getRandomValues(new Uint8Array(16)); const keyBuffer = await crypto.subtle.deriveBits( - { name: "PBKDF2", hash: "SHA-256", salt: saltArray, iterations: 1_000_000 }, - passwordKey, 256 + { name: 'PBKDF2', hash: 'SHA-256', salt: saltArray, iterations: 1_000_000 }, + passwordKey, + 256 ); - return Buffer.from(keyBuffer).toString("base64"); + return Buffer.from(keyBuffer).toString('base64'); } export default { async fetch(request, env, ctx) { - return new Response(await pbkdf2Derive("hello!")); - } -} + return new Response(await pbkdf2Derive('hello!')); + }, +}; diff --git a/src/workerd/server/tests/server-harness.mjs b/src/workerd/server/tests/server-harness.mjs index 925ad78848e..4a71591041f 100644 --- a/src/workerd/server/tests/server-harness.mjs +++ b/src/workerd/server/tests/server-harness.mjs @@ -1,5 +1,5 @@ -import { spawn } from "node:child_process"; -import assert from "node:assert"; +import { spawn } from 'node:child_process'; +import assert from 'node:assert'; // A convenience class to: // - start workerd @@ -17,11 +17,7 @@ export class WorkerdServerHarness { #listenInspectorPort = null; #closed = null; - constructor({ - workerdBinary, - workerdConfig, - listenPortNames, - }) { + constructor({ workerdBinary, workerdConfig, listenPortNames }) { this.#workerdBinary = workerdBinary; this.#workerdConfig = workerdConfig; this.#listenPortNames = listenPortNames; @@ -35,20 +31,20 @@ export class WorkerdServerHarness { const CONTROL_FD = 3; const args = [ - "serve", + 'serve', this.#workerdConfig, - "--verbose", - "--inspector-addr=127.0.0.1:0", + '--verbose', + '--inspector-addr=127.0.0.1:0', `--control-fd=${CONTROL_FD}`, ]; const options = { stdio: [ - "inherit", - "inherit", - "inherit", + 'inherit', + 'inherit', + 'inherit', // One more for our control FD. - "pipe", + 'pipe', ], }; @@ -63,38 +59,41 @@ export class WorkerdServerHarness { // spend forever on this code. this.#listenPorts = new Map(); for (const listenPort of this.#listenPortNames) { - this.#listenPorts.set(listenPort, new Promise((resolve, reject) => { - this.#child.stdio[CONTROL_FD].on("data", data => { - const parsed = JSON.parse(data); - if (parsed.event === "listen" && parsed.socket === listenPort) { - resolve(parsed.port); - } - }); - this.#child.once("error", reject); - })); + this.#listenPorts.set( + listenPort, + new Promise((resolve, reject) => { + this.#child.stdio[CONTROL_FD].on('data', (data) => { + const parsed = JSON.parse(data); + if (parsed.event === 'listen' && parsed.socket === listenPort) { + resolve(parsed.port); + } + }); + this.#child.once('error', reject); + }) + ); } // Do the same as the above for the inspector port. this.#listenInspectorPort = new Promise((resolve, reject) => { - this.#child.stdio[CONTROL_FD].on("data", data => { + this.#child.stdio[CONTROL_FD].on('data', (data) => { const parsed = JSON.parse(data); - if (parsed.event === "listen-inspector") { + if (parsed.event === 'listen-inspector') { resolve(parsed.port); } }); - this.#child.once("error", reject); + this.#child.once('error', reject); }); // Set up a closed promise, too. this.#closed = new Promise((resolve, reject) => { - this.#child.once("close", (code, signal) => resolve([code, signal])) - .once("error", reject); + this.#child + .once('close', (code, signal) => resolve([code, signal])) + .once('error', reject); }); // Wait for the subprocess to complete spawning before we return. await new Promise((resolve, reject) => { - this.#child.once("spawn", resolve) - .once("error", reject); + this.#child.once('spawn', resolve).once('error', reject); }); } diff --git a/src/workerd/server/tests/unsafe-eval/module.js b/src/workerd/server/tests/unsafe-eval/module.js index b779c3fb0c5..71e3bda47c5 100644 --- a/src/workerd/server/tests/unsafe-eval/module.js +++ b/src/workerd/server/tests/unsafe-eval/module.js @@ -2,8 +2,8 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { default as UnsafeEval } from "internal:unsafe-eval"; +import { default as UnsafeEval } from 'internal:unsafe-eval'; export function doEval() { - return UnsafeEval.eval("1 + 1"); + return UnsafeEval.eval('1 + 1'); } diff --git a/src/workerd/server/tests/unsafe-eval/unsafe-eval-test.js b/src/workerd/server/tests/unsafe-eval/unsafe-eval-test.js index 850930b0ef7..50da54e149c 100644 --- a/src/workerd/server/tests/unsafe-eval/unsafe-eval-test.js +++ b/src/workerd/server/tests/unsafe-eval/unsafe-eval-test.js @@ -2,8 +2,8 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import * as assert from "node:assert"; -import { doEval } from "test:module"; +import * as assert from 'node:assert'; +import { doEval } from 'test:module'; export const test_can_use_eval_via_proxy = { async test() { @@ -14,6 +14,6 @@ export const test_can_use_eval_via_proxy = { // internal modules can't be imported export const test_cannot_import_unsafe_eval = { async test() { - await assert.rejects(import("internal:unsafe-eval")); + await assert.rejects(import('internal:unsafe-eval')); }, }; diff --git a/src/workerd/server/tests/unsafe-module/unsafe-module-test.js b/src/workerd/server/tests/unsafe-module/unsafe-module-test.js index b4833ebf59a..6b7f4f95bf3 100644 --- a/src/workerd/server/tests/unsafe-module/unsafe-module-test.js +++ b/src/workerd/server/tests/unsafe-module/unsafe-module-test.js @@ -1,5 +1,5 @@ -import assert from "node:assert"; -import unsafe from "workerd:unsafe"; +import assert from 'node:assert'; +import unsafe from 'workerd:unsafe'; function createTestObject(type) { return class { @@ -7,12 +7,16 @@ function createTestObject(type) { fetch() { return new Response(`${type}:${this.id}`); } - } + }; } -export const TestDurableObject = createTestObject("durable"); -export const TestDurableObjectPreventEviction = createTestObject("durable-prevent-eviction"); -export const TestEphemeralObject = createTestObject("ephemeral"); -export const TestEphemeralObjectPreventEviction = createTestObject("ephemeral-prevent-eviction"); +export const TestDurableObject = createTestObject('durable'); +export const TestDurableObjectPreventEviction = createTestObject( + 'durable-prevent-eviction' +); +export const TestEphemeralObject = createTestObject('ephemeral'); +export const TestEphemeralObjectPreventEviction = createTestObject( + 'ephemeral-prevent-eviction' +); export const test_abort_all_durable_objects = { async test(ctrl, env, ctx) { @@ -20,21 +24,32 @@ export const test_abort_all_durable_objects = { const durablePreventEvictionId = env.DURABLE_PREVENT_EVICTION.newUniqueId(); const durableStub = env.DURABLE.get(durableId); - const durablePreventEvictionStub = env.DURABLE_PREVENT_EVICTION.get(durablePreventEvictionId); - const ephemeralStub = env.EPHEMERAL.get("thing"); - const ephemeralPreventEvictionStub = env.EPHEMERAL_PREVENT_EVICTION.get("thing"); + const durablePreventEvictionStub = env.DURABLE_PREVENT_EVICTION.get( + durablePreventEvictionId + ); + const ephemeralStub = env.EPHEMERAL.get('thing'); + const ephemeralPreventEvictionStub = + env.EPHEMERAL_PREVENT_EVICTION.get('thing'); - const durableRes1 = await (await durableStub.fetch("http://x")).text(); - const durablePreventEvictionRes1 = await (await durablePreventEvictionStub.fetch("http://x")).text(); - const ephemeralRes1 = await (await ephemeralStub.fetch("http://x")).text(); - const ephemeralPreventEvictionRes1 = await (await ephemeralPreventEvictionStub.fetch("http://x")).text(); + const durableRes1 = await (await durableStub.fetch('http://x')).text(); + const durablePreventEvictionRes1 = await ( + await durablePreventEvictionStub.fetch('http://x') + ).text(); + const ephemeralRes1 = await (await ephemeralStub.fetch('http://x')).text(); + const ephemeralPreventEvictionRes1 = await ( + await ephemeralPreventEvictionStub.fetch('http://x') + ).text(); await unsafe.abortAllDurableObjects(); - const durableRes2 = await (await durableStub.fetch("http://x")).text(); - const durablePreventEvictionRes2 = await (await durablePreventEvictionStub.fetch("http://x")).text(); - const ephemeralRes2 = await (await ephemeralStub.fetch("http://x")).text(); - const ephemeralPreventEvictionRes2 = await (await ephemeralPreventEvictionStub.fetch("http://x")).text(); + const durableRes2 = await (await durableStub.fetch('http://x')).text(); + const durablePreventEvictionRes2 = await ( + await durablePreventEvictionStub.fetch('http://x') + ).text(); + const ephemeralRes2 = await (await ephemeralStub.fetch('http://x')).text(); + const ephemeralPreventEvictionRes2 = await ( + await ephemeralPreventEvictionStub.fetch('http://x') + ).text(); // Irrespective of abort status, verify responses start with expected prefix assert.match(durableRes1, /^durable:/); @@ -50,6 +65,9 @@ export const test_abort_all_durable_objects = { // Response from objects in namespaces that have prevent eviction set shouldn't change assert.strictEqual(durablePreventEvictionRes1, durablePreventEvictionRes2); - assert.strictEqual(ephemeralPreventEvictionRes1, ephemeralPreventEvictionRes2); - } -} + assert.strictEqual( + ephemeralPreventEvictionRes1, + ephemeralPreventEvictionRes2 + ); + }, +}; diff --git a/src/workerd/tests/performance-test.js b/src/workerd/tests/performance-test.js index 8845b244a63..38bd1409116 100644 --- a/src/workerd/tests/performance-test.js +++ b/src/workerd/tests/performance-test.js @@ -25,6 +25,5 @@ export const test = { if (start == performance.now()) { throw new Error('performance.now() is not increasing'); } - } + }, }; - From d150b43b8f39199cf855536b182041b58e0ef3fd Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Fri, 16 Aug 2024 08:39:32 -0700 Subject: [PATCH 4/6] Add to git-blame-ignore-revs --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..d99b84fff59 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Apply prettier to the project +0523bf8b36a937348f1bb79eceda2463a5c220b5 From d5b2e516de1b9e7a2ccb84d16699affc8ac865d5 Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Tue, 20 Aug 2024 10:48:24 -0700 Subject: [PATCH 5/6] Add githooks --- githooks/pre-push | 45 +++++++++ tools/unix/apply-big-move.sh | 181 +++++++++++++++++++++++++++++++++++ tools/unix/find-python3.sh | 21 ++++ 3 files changed, 247 insertions(+) create mode 100644 githooks/pre-push create mode 100644 tools/unix/apply-big-move.sh create mode 100644 tools/unix/find-python3.sh diff --git a/githooks/pre-push b/githooks/pre-push new file mode 100644 index 00000000000..179a9b86343 --- /dev/null +++ b/githooks/pre-push @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +set -euo pipefail + + +source "$(dirname -- $BASH_SOURCE)/../tools/unix/find-python3.sh" +PYTHON_PATH=$(get_python3) +if [[ -z "$PYTHON_PATH" ]]; then + echo + echo "python3 is required for formatting and was not found" + echo + echo "ERROR: you must either install python3 and try pushing again or run `git push` with `--no-verify`" + exit 1 +fi + +while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA +do + git fetch origin master &>/dev/null + # Check all local changes, not present in origin/master, for lint. + set +e + $PYTHON_PATH "$(dirname -- $BASH_SOURCE)/../tools/cross/format.py" --check git --source $LOCAL_SHA --target origin/master + EXIT_CODE=$? + set -e + case $EXIT_CODE in + 0) + # No lint. + ;; + 1) + echo + echo "ERROR: changes in $LOCAL_REF have lint which may fail CI." + echo + echo "To fix lint:" + echo " python3 ./tools/cross/format.py" + echo + exit 1 + ;; + 2) + echo + echo "ERROR: failed to run format.py, Pass '--no-verify' or '-n' to skip." + echo + exit 1 + ;; + esac +done + diff --git a/tools/unix/apply-big-move.sh b/tools/unix/apply-big-move.sh new file mode 100644 index 00000000000..810572f34a2 --- /dev/null +++ b/tools/unix/apply-big-move.sh @@ -0,0 +1,181 @@ +#! /bin/bash +# +# This script applies the most recent "big change". +# +# This script is designed so that it can help you rebase an in-flight PR across this change. Once +# the big move has been merged, you may simply run this script inside your branch, and it will +# take care of updating your change in order to avoid any merge conflicts. +# +# How it does this: +# 1. Rebases your change to the commit just before the Big Move. +# 2. Applies the same logical changes that the Big Move did, but now applies this to the changes +# on your branch too. +# 3. Rewrites git history so that your commits are now based on the commit immediately after the +# Big Move. +# +# To use the script, just run it in your branch. It'll take care of everything, and you'll end up +# with the changes in your branch all based on the commit after The Big Move. + +set -euo pipefail + +AFTER_MOVE_TAG=after-big-move-1 +BEFORE_MOVE_TAG=before-big-move-1 +NEXT_BIG_MOVE=before-big-move-2 +ORIG_BRANCH=$(git branch --show-current) + +fail() { + echo -e '\e[0;1;31mFAILED:\e[0m '"$@" >&2 + exit 1 +} + +check_big_move_dependencies() { + source "$(dirname -- $BASH_SOURCE)/find-python3.sh" + PYTHON_PATH=$(get_python3) + if [[ -z "$PYTHON_PATH" ]]; then + fail "Cannot find python3. Run install python3 first." + fi +} + +apply_big_move() { + echo "Applying format..." + + source "$(dirname -- $BASH_SOURCE)/find-python3.sh" + PYTHON_PATH=$(get_python3) + $PYTHON_PATH "$(dirname -- $BASH_SOURCE)/../cross/format.py" + + echo "Changes applied successfully." +} + +rebase_and_rerun() { + # Rebase on top of tag $1 and then run the script again. + + BASE=$1 + + echo -e '\e[0;1;34mRebasing onto tag '"$BASE"'...\e[0m' + git rebase $BASE || \ + fail "Rebase had conflicts. Please resolve them and run the script again." + git submodule update + + # Make sure we're using the correct version of the script by starting it over. + exec ./apply-big-move.sh +} + +check_for_next_move() { + # Check if there's a new "Big Move" in the future and, if so, prompt the user to apply it too. + + if git describe $NEXT_BIG_MOVE >/dev/null 2>&1; then + while true; do + echo -en '\e[0;1;33mIt looks like there is another big move after this one. Should we apply it now? [y/n]\e[0m ' + read -n1 CHOICE + echo + case "$CHOICE" in + y | Y ) + rebase_and_rerun $NEXT_BIG_MOVE + ;; + n | N ) + echo "OK. When you are ready, please run the script again to apply the next move." + exit 0 + ;; + esac + echo "??? Please press either y or n." + done + fi +} + +main() { + if [ "x$(git status --untracked-files=no --porcelain)" != "x" ]; then + fail "You have uncommitted changes. Please commit or discard them first." + fi + + check_big_move_dependencies + + # Use --apply to just apply the Big Move changes to the current tree without committing or + # rewriting any history. This is intended to be used to create the Big Move commit in the first + # place. + if [ "${1:-}" = "--apply" ]; then + apply_big_move + exit 0 + fi + + # Make sure our tags are up-to-date so we can find the relevant Big Move tags. + echo "Fetching tags..." + git fetch origin --tags --force + + # Check that the Big Move is actually ready. (This script will be committed to the repo before + # the Big Move itself is, so this checks if someone is running the script too early.) + if ! git describe $BEFORE_MOVE_TAG >/dev/null 2>&1; then + fail "The Big Move hasn't happened yet (tags not found)." + fi + + # Check if we already applied The Big Move in this branch, as indicated by $AFTER_MOVE_TAG being + # in our history. + if git merge-base --is-ancestor $AFTER_MOVE_TAG HEAD; then + # This branch already includes The Big Move, but maybe there is a future Big Move and the + # user was actually intending to apply that? + if git describe $NEXT_BIG_MOVE >/dev/null 2>&1; then + # Indeed there is, let's skip forward to that. + rebase_and_rerun $NEXT_BIG_MOVE + fi + + echo "The Big Move has already been applied to this branch." + exit 0 + fi + + # Check if $BEFORE_MOVE_TAG is in this branch's history. If not, we need to rebase first. + if ! git merge-base --is-ancestor $BEFORE_MOVE_TAG HEAD; then + # Branch is not yet based on $BEFORE_MOVE_TAG, so rebase onto it. + rebase_and_rerun $BEFORE_MOVE_TAG + fail "(can't get here -- rebase_and_rerun should not return)" + fi + + # Get the list of commits that we need to rebase over The Big Move. + COMMITS=($(git log --reverse --format='%H' $BEFORE_MOVE_TAG..HEAD)) + + # Checkout $AFTER_MOVE_TAG in order to start building on it. + git checkout -q $AFTER_MOVE_TAG + git submodule update + + # Apply each commit. + for COMMIT in ${COMMITS[@]}; do + git log -1 --format='%CblueRewriting commit %h:%Creset %s' $COMMIT + + # Update the working tree to match the code from the source commit. + git checkout $COMMIT . + git submodule update + + # Apply the Big Move on top of that. + apply_big_move + + # Commit to edgeworker (including updating the workerd submodule), reusing the old commit + # message. It's possible that the diff is now empty, in which case we skip this commit, much + # like `git rebase` does by default. + if git commit -a --dry-run > /dev/null 2>&1; then + git commit -aC $COMMIT + fi + done + + # Record the final commit. + FINAL_COMMIT=$(git log -1 --format=%H) + + # Check out the original branch, and reset it to the final commit. + git checkout -q "$ORIG_BRANCH" + git reset --hard "$FINAL_COMMIT" + + # Success! + echo -e '\e[0;1;32mSUCCESS:\e[0m Applied Big Move.' + + # Check if there's another move upcoming that we should apply next. + check_for_next_move + + exit 0 +} + +# Ensure that if the file changes while bash is reading it, bash won't go off the rails. Normally, +# bash reads one line from the file at a time and then executes it before reading the next. +# Wrapping the whole script body in a function ensures that bash buffers it in memory. Placing +# `exit 0` on the same line ensures that bash won't attempt to read anything more after the +# function returns. +# +# This ensures that if further changes are made to this file before the Big Move actually happens, +# then the rebase command that rebases to the commit before the Big Move won't confuse bash. +main "$@"; exit 0 diff --git a/tools/unix/find-python3.sh b/tools/unix/find-python3.sh new file mode 100644 index 00000000000..6966fcb81b3 --- /dev/null +++ b/tools/unix/find-python3.sh @@ -0,0 +1,21 @@ + +get_python3() { + # Search for python3 + python=$(which python3 2>/dev/null) + + # If not found, search for python + if [ -z "$python" ]; then + python=$(which python 2>/dev/null) + if [ -n "$python" ]; then + local python_version=$($python -V 2>&1 | head -n 1 | cut -d ' ' -f 2- | cut -d '.' -f1) + if [ "$python_version" != "3" ]; then + unset python + fi + fi + fi + + if [ -z "$python" ]; then + return + fi + echo "$python" +} From 1463f7721b3f146260ee6915c3ab212b5f2c4156 Mon Sep 17 00:00:00 2001 From: Nicholas Paun Date: Tue, 20 Aug 2024 11:26:31 -0700 Subject: [PATCH 6/6] Correct placement of ts-ignore / eslint-ignore --- src/node/internal/internal_diffs.ts | 2 +- src/node/internal/internal_zlib.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/internal/internal_diffs.ts b/src/node/internal/internal_diffs.ts index 1df6ae8d4ff..80318a6cea2 100644 --- a/src/node/internal/internal_diffs.ts +++ b/src/node/internal/internal_diffs.ts @@ -277,9 +277,9 @@ export function diffstr(A: string, B: string) { // Join boundary splits that we do not consider to be boundaries and merge empty strings surrounded by word chars for (let i = 0; i < tokens.length - 1; i++) { if ( - // @ts-ignore !tokens[i + 1] && tokens[i + 2] && + // @ts-ignore words.test(tokens[i]) && // @ts-ignore words.test(tokens[i + 2]) diff --git a/src/node/internal/internal_zlib.ts b/src/node/internal/internal_zlib.ts index 8654da1e501..f9c88c8bfa5 100644 --- a/src/node/internal/internal_zlib.ts +++ b/src/node/internal/internal_zlib.ts @@ -17,10 +17,10 @@ function crc32(data: ArrayBufferView | string, value: number = 0): number { const constPrefix = 'CONST_'; const constants = {}; -// eslint-disable-next-line @typescript-eslint/no-unsafe-argument Object.defineProperties( constants, Object.fromEntries( + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument Object.entries(Object.getPrototypeOf(zlibUtil)) .filter(([k]) => k.startsWith(constPrefix)) .map(([k, v]) => [