diff options
Diffstat (limited to 'std/node')
141 files changed, 0 insertions, 23857 deletions
diff --git a/std/node/README.md b/std/node/README.md deleted file mode 100644 index 5f0d8511a..000000000 --- a/std/node/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# Deno Node compatibility - -This module is meant to have a compatibility layer for the -[NodeJS standard library](https://nodejs.org/docs/latest-v12.x/api/). - -**Warning**: Any function of this module should not be referred anywhere in the -deno standard library as it's a compatibility module. - -## Supported Builtins - -- [ ] assert -- [x] buffer -- [ ] child_process -- [ ] cluster -- [ ] console -- [ ] crypto -- [ ] dgram -- [ ] dns -- [x] events -- [x] fs _partly_ -- [ ] http -- [ ] http2 -- [ ] https -- [x] module -- [ ] net -- [x] os _partly_ -- [x] path -- [ ] perf_hooks -- [x] process _partly_ -- [x] querystring -- [ ] readline -- [ ] repl -- [ ] stream -- [ ] string_decoder -- [ ] sys -- [x] timers -- [ ] tls -- [ ] tty -- [ ] url -- [x] util _partly_ -- [ ] ~~v8~~ _can't implement_ -- [ ] vm -- [ ] worker_threads -- [ ] zlib - -* [x] node globals _partly_ - -### Deprecated - -These builtins are deprecated in NodeJS v13 and will probably not be polyfilled: - -- constants -- domain -- freelist -- punycode - -### Experimental - -These builtins are experimental in NodeJS v13 and will not be polyfilled until -they are stable: - -- async_hooks -- inspector -- policies -- report -- trace_events -- wasi - -## CommonJS Module Loading - -`createRequire(...)` is provided to create a `require` function for loading CJS -modules. It also sets supported globals. - -```ts -import { createRequire } from "https://deno.land/std@$STD_VERSION/node/module.ts"; - -const require = createRequire(import.meta.url); -// Loads native module polyfill. -const path = require("path"); -// Loads extensionless module. -const cjsModule = require("./my_mod"); -// Visits node_modules. -const leftPad = require("left-pad"); -``` - -## Contributing - -When converting from promise-based to callback-based APIs, the most obvious way -is like this: - -```ts -promise.then((value) => callback(null, value)).catch(callback); -``` - -This has a subtle bug - if the callback throws an error, the catch statement -will also catch _that_ error, and the callback will be called twice. The correct -way to do it is like this: - -```ts -promise.then((value) => callback(null, value), callback); -``` - -The second parameter of `then` can also be used to catch errors, but only errors -from the existing promise, not the new one created by the callback. - -If the Deno equivalent is actually synchronous, there's a similar problem with -try/catch statements: - -```ts -try { - const value = process(); - callback(null, value); -} catch (err) { - callback(err); -} -``` - -Since the callback is called within the `try` block, any errors from it will be -caught and call the callback again. - -The correct way to do it is like this: - -```ts -let err, value; -try { - value = process(); -} catch (e) { - err = e; -} -if (err) { - callback(err); // Make sure arguments.length === 1 -} else { - callback(null, value); -} -``` - -It's not as clean, but prevents the callback being called twice. diff --git a/std/node/_crypto/constants.ts b/std/node/_crypto/constants.ts deleted file mode 100644 index cfe3f4626..000000000 --- a/std/node/_crypto/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const MAX_ALLOC = Math.pow(2, 30) - 1; diff --git a/std/node/_crypto/pbkdf2.ts b/std/node/_crypto/pbkdf2.ts deleted file mode 100644 index 2a63802e6..000000000 --- a/std/node/_crypto/pbkdf2.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { createHash } from "../../hash/mod.ts"; -import { Buffer } from "../buffer.ts"; -import { MAX_ALLOC } from "./constants.ts"; -import { HASH_DATA } from "./types.ts"; - -export type NormalizedAlgorithms = - | "md5" - | "ripemd160" - | "sha1" - | "sha224" - | "sha256" - | "sha384" - | "sha512"; - -type Algorithms = - | "md5" - | "ripemd160" - | "rmd160" - | "sha1" - | "sha224" - | "sha256" - | "sha384" - | "sha512"; - -function createHasher(alg: Algorithms) { - let normalizedAlg: NormalizedAlgorithms; - if (alg === "rmd160") { - normalizedAlg = "ripemd160"; - } else { - normalizedAlg = alg; - } - return (value: Uint8Array) => - Buffer.from(createHash(normalizedAlg).update(value).digest()); -} - -function getZeroes(zeros: number) { - return Buffer.alloc(zeros); -} -const sizes = { - md5: 16, - sha1: 20, - sha224: 28, - sha256: 32, - sha384: 48, - sha512: 64, - rmd160: 20, - ripemd160: 20, -}; - -function toBuffer(bufferable: HASH_DATA) { - if (bufferable instanceof Uint8Array || typeof bufferable === "string") { - return Buffer.from(bufferable as Uint8Array); - } else { - return Buffer.from(bufferable.buffer); - } -} - -class Hmac { - hash: (value: Uint8Array) => Buffer; - ipad1: Buffer; - opad: Buffer; - alg: string; - blocksize: number; - size: number; - ipad2: Buffer; - - constructor(alg: Algorithms, key: Buffer, saltLen: number) { - this.hash = createHasher(alg); - - const blocksize = (alg === "sha512" || alg === "sha384") ? 128 : 64; - - if (key.length > blocksize) { - key = this.hash(key); - } else if (key.length < blocksize) { - key = Buffer.concat([key, getZeroes(blocksize - key.length)], blocksize); - } - - const ipad = Buffer.allocUnsafe(blocksize + sizes[alg]); - const opad = Buffer.allocUnsafe(blocksize + sizes[alg]); - for (let i = 0; i < blocksize; i++) { - ipad[i] = key[i] ^ 0x36; - opad[i] = key[i] ^ 0x5C; - } - - const ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4); - ipad.copy(ipad1, 0, 0, blocksize); - - this.ipad1 = ipad1; - this.ipad2 = ipad; - this.opad = opad; - this.alg = alg; - this.blocksize = blocksize; - this.size = sizes[alg]; - } - - run(data: Buffer, ipad: Buffer) { - data.copy(ipad, this.blocksize); - const h = this.hash(ipad); - h.copy(this.opad, this.blocksize); - return this.hash(this.opad); - } -} - -/** - * @param iterations Needs to be higher or equal than zero - * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30) - * @param digest Algorithm to be used for encryption - */ -export function pbkdf2Sync( - password: HASH_DATA, - salt: HASH_DATA, - iterations: number, - keylen: number, - digest: Algorithms = "sha1", -): Buffer { - if (typeof iterations !== "number" || iterations < 0) { - throw new TypeError("Bad iterations"); - } - if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) { - throw new TypeError("Bad key length"); - } - - const bufferedPassword = toBuffer(password); - const bufferedSalt = toBuffer(salt); - - const hmac = new Hmac(digest, bufferedPassword, bufferedSalt.length); - - const DK = Buffer.allocUnsafe(keylen); - const block1 = Buffer.allocUnsafe(bufferedSalt.length + 4); - bufferedSalt.copy(block1, 0, 0, bufferedSalt.length); - - let destPos = 0; - const hLen = sizes[digest]; - const l = Math.ceil(keylen / hLen); - - for (let i = 1; i <= l; i++) { - block1.writeUInt32BE(i, bufferedSalt.length); - - const T = hmac.run(block1, hmac.ipad1); - let U = T; - - for (let j = 1; j < iterations; j++) { - U = hmac.run(U, hmac.ipad2); - for (let k = 0; k < hLen; k++) T[k] ^= U[k]; - } - - T.copy(DK, destPos); - destPos += hLen; - } - - return DK; -} - -/** - * @param iterations Needs to be higher or equal than zero - * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30) - * @param digest Algorithm to be used for encryption - */ -export function pbkdf2( - password: HASH_DATA, - salt: HASH_DATA, - iterations: number, - keylen: number, - digest: Algorithms = "sha1", - callback: ((err: Error | null, derivedKey?: Buffer) => void), -): void { - setTimeout(() => { - let err = null, res; - try { - res = pbkdf2Sync( - password, - salt, - iterations, - keylen, - digest, - ); - } catch (e) { - err = e; - } - if (err) { - callback(err); - } else { - callback(null, res); - } - }, 0); -} diff --git a/std/node/_crypto/pbkdf2_test.ts b/std/node/_crypto/pbkdf2_test.ts deleted file mode 100644 index 29f149cbe..000000000 --- a/std/node/_crypto/pbkdf2_test.ts +++ /dev/null @@ -1,427 +0,0 @@ -import { - NormalizedAlgorithms as Algorithms, - pbkdf2, - pbkdf2Sync, -} from "./pbkdf2.ts"; -import { - assert, - assertEquals, - assertStringIncludes, -} from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; - -type Pbkdf2Fixture = { - key: string | Float64Array | Int32Array | Uint8Array; - salt: string | Float64Array | Int32Array | Uint8Array; - iterations: number; - dkLen: number; - results: { [key in Algorithms]: string }; -}; - -const fixtures: Pbkdf2Fixture[] = [ - { - "key": "password", - "salt": "salt", - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "f31afb6d931392daa5e3130f47f9a9b6e8e72029d8350b9fb27a9e0e00b9d991", - "sha1": - "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164", - "sha256": - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b", - "sha512": - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252", - "sha224": - "3c198cbdb9464b7857966bd05b7bc92bc1cc4e6e63155d4e490557fd85989497", - "sha384": - "c0e14f06e49e32d73f9f52ddf1d0c5c7191609233631dadd76a567db42b78676", - "ripemd160": - "b725258b125e0bacb0e2307e34feb16a4d0d6aed6cb4b0eee458fc1829020428", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 2, - "dkLen": 32, - "results": { - "md5": "042407b552be345ad6eee2cf2f7ed01dd9662d8f0c6950eaec7124aa0c82279e", - "sha1": - "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957cae93136266537a8d7bf4b76", - "sha256": - "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43", - "sha512": - "e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53c", - "sha224": - "93200ffa96c5776d38fa10abdf8f5bfc0054b9718513df472d2331d2d1e66a3f", - "sha384": - "54f775c6d790f21930459162fc535dbf04a939185127016a04176a0730c6f1f4", - "ripemd160": - "768dcc27b7bfdef794a1ff9d935090fcf598555e66913180b9ce363c615e9ed9", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 1, - "dkLen": 64, - "results": { - "md5": - "f31afb6d931392daa5e3130f47f9a9b6e8e72029d8350b9fb27a9e0e00b9d9915a5f18928639ca8bbc3d1c1cb66d4f27b9dfe39156774c6798b42adc57ed253f", - "sha1": - "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164ac2e7a8e3f9d2e83ace57e0d50e5e1071367c179bc86c767fc3f78ddb561363f", - "sha256": - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c", - "sha512": - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce", - "sha224": - "3c198cbdb9464b7857966bd05b7bc92bc1cc4e6e63155d4e490557fd859894978ab846d52a1083ac610c36c2c5ea8ce4a024dd691064d5453bd17b15ea1ac194", - "sha384": - "c0e14f06e49e32d73f9f52ddf1d0c5c7191609233631dadd76a567db42b78676b38fc800cc53ddb642f5c74442e62be44d727702213e3bb9223c53b767fbfb5d", - "ripemd160": - "b725258b125e0bacb0e2307e34feb16a4d0d6aed6cb4b0eee458fc18290204289e55d962783bf52237d264cbbab25f18d89d8c798f90f558ea7b45bdf3d08334", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 2, - "dkLen": 64, - "results": { - "md5": - "042407b552be345ad6eee2cf2f7ed01dd9662d8f0c6950eaec7124aa0c82279ed0b7e2a854d0f29ec82ddcabe9760368e5821af8745d74846ccbd17afbfe5ff0", - "sha1": - "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957cae93136266537a8d7bf4b76c51094cc1ae010b19923ddc4395cd064acb023ffd1edd5ef4be8ffe61426c28e", - "sha256": - "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43830651afcb5c862f0b249bd031f7a67520d136470f5ec271ece91c07773253d9", - "sha512": - "e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e", - "sha224": - "93200ffa96c5776d38fa10abdf8f5bfc0054b9718513df472d2331d2d1e66a3f97b510224f700ce72581ffb10a1c99ec99a8cc1b951851a71f30d9265fccf912", - "sha384": - "54f775c6d790f21930459162fc535dbf04a939185127016a04176a0730c6f1f4fb48832ad1261baadd2cedd50814b1c806ad1bbf43ebdc9d047904bf7ceafe1e", - "ripemd160": - "768dcc27b7bfdef794a1ff9d935090fcf598555e66913180b9ce363c615e9ed953b95fd07169be535e38afbea29c030e06d14f40745b1513b7ccdf0e76229e50", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 4096, - "dkLen": 32, - "results": { - "md5": "15001f89b9c29ee6998c520d1a0629e893cc3f996a08d27060e4c33305bf0fb2", - "sha1": - "4b007901b765489abead49d926f721d065a429c12e463f6c4cd79401085b03db", - "sha256": - "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a", - "sha512": - "d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5", - "sha224": - "218c453bf90635bd0a21a75d172703ff6108ef603f65bb821aedade1d6961683", - "sha384": - "559726be38db125bc85ed7895f6e3cf574c7a01c080c3447db1e8a76764deb3c", - "ripemd160": - "99a40d3fe4ee95869791d9faa24864562782762171480b620ca8bed3dafbbcac", - }, - }, - { - "key": "passwordPASSWORDpassword", - "salt": "saltSALTsaltSALTsaltSALTsaltSALTsalt", - "iterations": 4096, - "dkLen": 40, - "results": { - "md5": - "8d5d0aad94d14420429fbc7e5b087d7a5527e65dfd0d486a310e8a7b6ff5a21bed000b118b2c26a6", - "sha1": - "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038b6b89a48612c5a25284e6605e12329", - "sha256": - "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9", - "sha512": - "8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd953", - "sha224": - "056c4ba438ded91fc14e0594e6f52b87e1f3690c0dc0fbc05784ed9a754ca780e6c017e80c8de278", - "sha384": - "819143ad66df9a552559b9e131c52ae6c5c1b0eed18f4d283b8c5c9eaeb92b392c147cc2d2869d58", - "ripemd160": - "503b9a069633b261b2d3e4f21c5d0cafeb3f5008aec25ed21418d12630b6ce036ec82a0430ef1974", - }, - }, - { - "key": "pass\u00000word", - "salt": "sa\u00000lt", - "iterations": 4096, - "dkLen": 16, - "results": { - "md5": "2d6b566fd00069a30dd1ffdb4d598f54", - "sha1": "345cbad979dfccb90cac5257bea6ea46", - "sha256": "1df6274d3c0bd2fc7f54fb46f149dda4", - "sha512": "336d14366099e8aac2c46c94a8f178d2", - "sha224": "0aca9ca9634db6ef4927931f633c6453", - "sha384": "b6ab6f8f6532fd9c5c30a79e1f93dcc6", - "ripemd160": "914d58209e6483e491571a60e433124a", - }, - }, - { - "key": "63ffeeddccbbaa", - "salt": "salt", - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "23a33e38c9c57ea122df372a5b96347667e843ba21c79f150ce503d947449b75", - "sha1": - "1a12b21aa46bd3bed3a23b8ad072a1465585344b1516252618aabbc41276dada", - "sha256": - "a47c9371d4d4f663c2a0d3becbd475b7eb884722c7265391381d7696151470a6", - "sha512": - "09328469e02fcee4f6ab88a23037de33d54f17f786eee39e1f8826109ee54e16", - "sha224": - "59baceb002865e57061c65dd861c309c049a97207054416c943764efc38b94ed", - "sha384": - "01cc52b81eda47c8bc9861ab7f7de682e92a0d5e522f4d3a06a3b97be1856580", - "ripemd160": - "4f04f4782f2def250005e04ef0497403330b52a085ae856f4640700b19983b7c", - }, - }, - { - "key": - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "salt": - "6d6e656d6f6e6963e383a1e383bce38388e383abe382abe38299e3838fe38299e382a6e38299e382a1e381afe3829ae381afe38299e3818fe38299e3829de38299e381a1e381a1e38299e58d81e4babae58d81e889b2", - "iterations": 2048, - "dkLen": 64, - "results": { - "md5": - "029d0e4484f56d9cf7ab7ca972c8991aeb2be275cba9683db4143e9b72f67d49551ec4c70ca6d051538fc7a86b8568d08244fdea24ba826b7927babac4f62cf2", - "sha1": - "fb3fa7c05a98ff66da2eadd69fa2ba52401ee630e04322d3c5bb018d1dda03c7e47bdea0c9e4c77c87826632eed59bbe42ce05329a838664683b1a8dae3fffd8", - "sha256": - "3b19907cb907d1ee6e5a0ecb80bd66e2776d1f2c73f4789eafcad94fda832e970471ceb0d200ede70e63ae021044cf4b58b1011e34252ace8d94a48c287906ec", - "sha512": - "0be4563c5175fd02b042251228774f34c1ccb235054a9f0f968c6d828466eae8c32433a7aa09ce922722dc808c6a1629ba8f1b6ba46f0cf7a921e125d1cc9fcd", - "sha224": - "dd529ad11b298cafad9209a0a620af98cf1b782bd0ba1a61efcd74a4fe2662af6c36ffd015c68ed0cd630bdb023ea61e59317eb07b342e0c6ece1bd3034b768c", - "sha384": - "7265c090b602b0a432b4908f70b6a5a2a6657926d09ac72ebb78d8bcc81e0d4563316f1eb5570b2850ef06a14719746a8a8397d3d56aa51b2d50489741b7ff61", - "ripemd160": - "c984beaf664aea5ae7f671063ef2ad1f80098e48382a916809ff9212d1a8cb7ad6cb17354422717c668726dfce294e1442bb354b6a6693db84032172e77af6ae", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 1, - "dkLen": 10, - "results": { - "md5": "f31afb6d931392daa5e3", - "sha1": "0c60c80f961f0e71f3a9", - "sha256": "120fb6cffcf8b32c43e7", - "sha512": "867f70cf1ade02cff375", - "sha224": "3c198cbdb9464b785796", - "sha384": "c0e14f06e49e32d73f9f", - "ripemd160": "b725258b125e0bacb0e2", - }, - }, - { - "key": "password", - "salt": "salt", - "iterations": 1, - "dkLen": 100, - "results": { - "md5": - "f31afb6d931392daa5e3130f47f9a9b6e8e72029d8350b9fb27a9e0e00b9d9915a5f18928639ca8bbc3d1c1cb66d4f27b9dfe39156774c6798b42adc57ed253f44fc731edccf067904ce2e317b9ef45767add4dfe53f8c190dac43d90cda5e66e627d4f2", - "sha1": - "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164ac2e7a8e3f9d2e83ace57e0d50e5e1071367c179bc86c767fc3f78ddb561363fc692ba406d1301e42bcccc3c520d06751d78b80c3db926b16ffa3395bd697c647f280b51", - "sha256": - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c22cd7fe60fa40e91c65849e1f60c0d8b62a7b2dbd0d3dfd75fb8498a5c2131ab02b66de5", - "sha512": - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce7b532e206c2967d4c7d2ffa460539fc4d4e5eec70125d74c6c7cf86d25284f297907fcea", - "sha224": - "3c198cbdb9464b7857966bd05b7bc92bc1cc4e6e63155d4e490557fd859894978ab846d52a1083ac610c36c2c5ea8ce4a024dd691064d5453bd17b15ea1ac1944bbfd62e61b997e7b22660f588e297186572480015f33bc2bfd2b423827bcdcdb4845914", - "sha384": - "c0e14f06e49e32d73f9f52ddf1d0c5c7191609233631dadd76a567db42b78676b38fc800cc53ddb642f5c74442e62be44d727702213e3bb9223c53b767fbfb5db9d270d54c45d9cb6003d2967280b22671e2dbc6375f6ebf219c36f0d127be35e19d65a8", - "ripemd160": - "b725258b125e0bacb0e2307e34feb16a4d0d6aed6cb4b0eee458fc18290204289e55d962783bf52237d264cbbab25f18d89d8c798f90f558ea7b45bdf3d083340c18b9d23ba842183c5364d18bc0ffde5a8a408dd7ef02dde561a08d21c6d2325a69869b", - }, - }, - { - "key": new Uint8Array([112, 97, 115, 115, 119, 111, 114, 100]), - "salt": "salt", - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "f31afb6d931392daa5e3130f47f9a9b6e8e72029d8350b9fb27a9e0e00b9d991", - "sha1": - "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164", - "sha256": - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b", - "sha512": - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252", - "sha224": - "3c198cbdb9464b7857966bd05b7bc92bc1cc4e6e63155d4e490557fd85989497", - "sha384": - "c0e14f06e49e32d73f9f52ddf1d0c5c7191609233631dadd76a567db42b78676", - "ripemd160": - "b725258b125e0bacb0e2307e34feb16a4d0d6aed6cb4b0eee458fc1829020428", - }, - }, - { - "key": "password", - "salt": new Uint8Array([115, 97, 108, 116]), - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "f31afb6d931392daa5e3130f47f9a9b6e8e72029d8350b9fb27a9e0e00b9d991", - "sha1": - "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164", - "sha256": - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b", - "sha512": - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252", - "sha224": - "3c198cbdb9464b7857966bd05b7bc92bc1cc4e6e63155d4e490557fd85989497", - "sha384": - "c0e14f06e49e32d73f9f52ddf1d0c5c7191609233631dadd76a567db42b78676", - "ripemd160": - "b725258b125e0bacb0e2307e34feb16a4d0d6aed6cb4b0eee458fc1829020428", - }, - }, - { - "key": new Int32Array([112, 97, 115, 115, 119, 111, 114, 100]), - "salt": "salt", - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "81de8e85b07d7969d9fe530641b63cc4ecbbf2345037cdc0ba61ad329fc7029c", - "sha1": - "f260ccd0bbc8fe6773119b834feec48636b716caad4180a4d0af4f9aa67c646e", - "sha256": - "9b4608f5eeab348f0b9d85a918b140706b24f275acf6829382dfee491015f9eb", - "sha512": - "c44b8f26550fe6ca0a55bce54b4a75e9530398f32ec28b59d0fded996e95e3d5", - "sha224": - "03d0c2b530ec6339e6418cb0f906e50591619be40aa8817aa9c7305d1773231c", - "sha384": - "2e69d62ae8c21ebc2de45a885b488f65fb88dfa58aaa9c57dd1fcb9d1edce96a", - "ripemd160": - "fc69276ba3f145492065feb0259b9edf68179f2023c95094e71ac7d01748018a", - }, - }, - { - "key": "password", - "salt": new Int32Array([115, 97, 108, 116]), - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "36587a57770a8eef264391786b4ddfae0723f6a64dc2fc199fe7eb6ad9def701", - "sha1": - "b297f1ea23008f10ba9d645961e4661109e804b10af26bea22c44244492d6252", - "sha256": - "f678f0772894c079f21377d9ee1e76dd77b62dfc1f0575e6aa9eb030af7a356a", - "sha512": - "7f8133f6937ae1d7e4a43c19aabd2de8308d5b833341281716a501334cdb2470", - "sha224": - "ab66d29d3dacc731e44f091a7baa051926219cf493e8b9e3934cedfb215adc8b", - "sha384": - "cf139d648cf63e9b85a3b9b8f23f4445b84d22201bc2544bc273a17d5dcb7b28", - "ripemd160": - "26142e48fae1ad1c53be54823aadda2aa7d42f5524463fb1eff0efafa08edb9d", - }, - }, - { - "key": new Float64Array([112, 97, 115, 115, 119, 111, 114, 100]), - "salt": "salt", - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "48336072da7d11ff203c61705b384b1c60953e7d1677fed2cd3e65738d60e67e", - "sha1": - "c2b17a7e98cc48690a92cd9f753a2c700229045905167571aa281aafe8230bba", - "sha256": - "55d62579a083a6c14b886710f81b54f567d214d343af776e5e90c467ea81b821", - "sha512": - "ded01ce343e2683d962fc74b7b5ceef525228f49393ce9353254f44e3dc7e9aa", - "sha224": - "5f10a348d320c7555b972b8d7d45a363a91e1a82dea063c3ac495cfad74a8d89", - "sha384": - "4b7f97dbadfd652e0579499d0e23607ec476ed4bea9d6f1740d0b110e2d08792", - "ripemd160": - "f92080d972a649d98d91a53922863fc7b8076c54869e9885f9a804868ef752e0", - }, - }, - { - "key": "password", - "salt": new Float64Array([115, 97, 108, 116]), - "iterations": 1, - "dkLen": 32, - "results": { - "md5": "9f1716e6f9d77b0beb56758f9509edea50828d15909073c3c715f66173ac3716", - "sha1": - "f158b9edd28c16ad3b41e0e8197ec132a98c2ddea73b959f55ec9792e0b29d6f", - "sha256": - "a6154d17480547a10212f75883509842f88f2ca5d6c1a2419646e47342051852", - "sha512": - "b10c2ea742de7dd0525988761ee1733564c91380eeaa1b199f4fafcbf7144b0c", - "sha224": - "29b315ac30c7d5e1640ca0f9e27b68a794fb9f950b8dd117129824f103ffb9db", - "sha384": - "624b4ed6ad389b976fb7503e54a35109f249c29ac6eb8b56850152be21b3cb0e", - "ripemd160": - "8999b9280207bc9c76cf25327aa352da26a683fac7a2adff17a39dcc4f4c3b5b", - }, - }, -]; - -Deno.test("pbkdf2 hashes data correctly", () => { - fixtures.forEach(({ - dkLen, - iterations, - key, - results, - salt, - }) => { - for (const algorithm in results) { - pbkdf2( - key, - salt, - iterations, - dkLen, - algorithm as Algorithms, - (err, res) => { - assert(!err); - assertEquals( - res?.toString("hex"), - results[algorithm as Algorithms], - ); - }, - ); - } - }); -}); - -Deno.test("pbkdf2Sync hashes data correctly", () => { - fixtures.forEach(({ - dkLen, - iterations, - key, - results, - salt, - }) => { - for (const algorithm in results) { - assertEquals( - pbkdf2Sync(key, salt, iterations, dkLen, algorithm as Algorithms) - .toString("hex"), - results[algorithm as Algorithms], - ); - } - }); -}); - -Deno.test("[std/node/crypto] pbkdf2 callback isn't called twice if error is thrown", async () => { - const importUrl = new URL("./pbkdf2.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { pbkdf2 } from ${JSON.stringify(importUrl)}`, - invocation: 'pbkdf2("password", "salt", 1, 32, "sha1", ', - }); -}); diff --git a/std/node/_crypto/randomBytes.ts b/std/node/_crypto/randomBytes.ts deleted file mode 100644 index 335c92d68..000000000 --- a/std/node/_crypto/randomBytes.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Buffer } from "../buffer.ts"; - -export const MAX_RANDOM_VALUES = 65536; -export const MAX_SIZE = 4294967295; - -function generateRandomBytes(size: number) { - if (size > MAX_SIZE) { - throw new RangeError( - `The value of "size" is out of range. It must be >= 0 && <= ${MAX_SIZE}. Received ${size}`, - ); - } - - const bytes = Buffer.allocUnsafe(size); - - //Work around for getRandomValues max generation - if (size > MAX_RANDOM_VALUES) { - for (let generated = 0; generated < size; generated += MAX_RANDOM_VALUES) { - crypto.getRandomValues( - bytes.slice(generated, generated + MAX_RANDOM_VALUES), - ); - } - } else { - crypto.getRandomValues(bytes); - } - - return bytes; -} - -/** - * @param size Buffer length, must be equal or greater than zero - */ -export default function randomBytes(size: number): Buffer; -export default function randomBytes( - size: number, - cb?: (err: Error | null, buf?: Buffer) => void, -): void; -export default function randomBytes( - size: number, - cb?: (err: Error | null, buf?: Buffer) => void, -): Buffer | void { - if (typeof cb === "function") { - let err: Error | null = null, bytes: Buffer; - try { - bytes = generateRandomBytes(size); - } catch (e) { - //NodeJS nonsense - //If the size is out of range it will throw sync, otherwise throw async - if ( - e instanceof RangeError && - e.message.includes('The value of "size" is out of range') - ) { - throw e; - } else { - err = e; - } - } - setTimeout(() => { - if (err) { - cb(err); - } else { - cb(null, bytes); - } - }, 0); - } else { - return generateRandomBytes(size); - } -} diff --git a/std/node/_crypto/randomBytes_test.ts b/std/node/_crypto/randomBytes_test.ts deleted file mode 100644 index 6dd2091e1..000000000 --- a/std/node/_crypto/randomBytes_test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { - assert, - assertEquals, - assertStringIncludes, - assertThrows, - assertThrowsAsync, -} from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import randomBytes, { MAX_RANDOM_VALUES, MAX_SIZE } from "./randomBytes.ts"; - -Deno.test("randomBytes sync works correctly", function () { - assertEquals(randomBytes(0).length, 0, "len: " + 0); - assertEquals(randomBytes(3).length, 3, "len: " + 3); - assertEquals(randomBytes(30).length, 30, "len: " + 30); - assertEquals(randomBytes(300).length, 300, "len: " + 300); - assertEquals( - randomBytes(17 + MAX_RANDOM_VALUES).length, - 17 + MAX_RANDOM_VALUES, - "len: " + 17 + MAX_RANDOM_VALUES, - ); - assertEquals( - randomBytes(MAX_RANDOM_VALUES * 100).length, - MAX_RANDOM_VALUES * 100, - "len: " + MAX_RANDOM_VALUES * 100, - ); - assertThrows(() => randomBytes(MAX_SIZE + 1)); - assertThrows(() => randomBytes(-1)); -}); - -Deno.test("randomBytes async works correctly", function () { - randomBytes(0, function (err, resp) { - assert(!err); - assertEquals(resp?.length, 0, "len: " + 0); - }); - randomBytes(3, function (err, resp) { - assert(!err); - assertEquals(resp?.length, 3, "len: " + 3); - }); - randomBytes(30, function (err, resp) { - assert(!err); - assertEquals(resp?.length, 30, "len: " + 30); - }); - randomBytes(300, function (err, resp) { - assert(!err); - assertEquals(resp?.length, 300, "len: " + 300); - }); - randomBytes(17 + MAX_RANDOM_VALUES, function (err, resp) { - assert(!err); - assertEquals( - resp?.length, - 17 + MAX_RANDOM_VALUES, - "len: " + 17 + MAX_RANDOM_VALUES, - ); - }); - randomBytes(MAX_RANDOM_VALUES * 100, function (err, resp) { - assert(!err); - assertEquals( - resp?.length, - MAX_RANDOM_VALUES * 100, - "len: " + MAX_RANDOM_VALUES * 100, - ); - }); - assertThrows(() => - randomBytes(MAX_SIZE + 1, function (err) { - //Shouldn't throw async - assert(!err); - }) - ); - assertThrowsAsync(() => - new Promise((resolve, reject) => { - randomBytes(-1, function (err, res) { - //Shouldn't throw async - if (err) { - reject(err); - } else { - resolve(res); - } - }); - }) - ); -}); - -Deno.test("[std/node/crypto] randomBytes callback isn't called twice if error is thrown", async () => { - const importUrl = new URL("./randomBytes.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import randomBytes from ${JSON.stringify(importUrl)}`, - invocation: "randomBytes(0, ", - }); -}); diff --git a/std/node/_crypto/types.ts b/std/node/_crypto/types.ts deleted file mode 100644 index e56d8416c..000000000 --- a/std/node/_crypto/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Buffer } from "../buffer.ts"; - -export type HASH_DATA = string | ArrayBufferView | Buffer; diff --git a/std/node/_errors.ts b/std/node/_errors.ts deleted file mode 100644 index db37e3186..000000000 --- a/std/node/_errors.ts +++ /dev/null @@ -1,2270 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -/************ NOT IMPLEMENTED -* ERR_INVALID_ARG_VALUE -* ERR_INVALID_MODULE_SPECIFIER -* ERR_INVALID_PACKAGE_TARGET -* ERR_INVALID_URL_SCHEME -* ERR_MANIFEST_ASSERT_INTEGRITY -* ERR_MODULE_NOT_FOUND -* ERR_PACKAGE_PATH_NOT_EXPORTED -* ERR_QUICSESSION_VERSION_NEGOTIATION -* ERR_REQUIRE_ESM -* ERR_SOCKET_BAD_PORT -* ERR_TLS_CERT_ALTNAME_INVALID -* ERR_UNHANDLED_ERROR -* ERR_WORKER_INVALID_EXEC_ARGV -* ERR_WORKER_PATH -* ERR_QUIC_ERROR -* ERR_SOCKET_BUFFER_SIZE //System error, shouldn't ever happen inside Deno -* ERR_SYSTEM_ERROR //System error, shouldn't ever happen inside Deno -* ERR_TTY_INIT_FAILED //System error, shouldn't ever happen inside Deno -* ERR_INVALID_PACKAGE_CONFIG // package.json stuff, probably useless -*************/ - -import { unreachable } from "../testing/asserts.ts"; - -/** - * All error instances in Node have additional methods and properties - * This export class is meant to be extended by these instances abstracting native JS error instances - */ -export class NodeErrorAbstraction extends Error { - code: string; - - constructor(name: string, code: string, message: string) { - super(message); - this.code = code; - this.name = name; - //This number changes dependending on the name of this class - //20 characters as of now - this.stack = this.stack && `${name} [${this.code}]${this.stack.slice(20)}`; - } - - toString() { - return `${this.name} [${this.code}]: ${this.message}`; - } -} - -export class NodeError extends NodeErrorAbstraction { - constructor(code: string, message: string) { - super(Error.prototype.name, code, message); - } -} - -export class NodeSyntaxError extends NodeErrorAbstraction - implements SyntaxError { - constructor(code: string, message: string) { - super(SyntaxError.prototype.name, code, message); - Object.setPrototypeOf(this, SyntaxError.prototype); - } -} - -export class NodeRangeError extends NodeErrorAbstraction { - constructor(code: string, message: string) { - super(RangeError.prototype.name, code, message); - Object.setPrototypeOf(this, RangeError.prototype); - } -} - -export class NodeTypeError extends NodeErrorAbstraction implements TypeError { - constructor(code: string, message: string) { - super(TypeError.prototype.name, code, message); - Object.setPrototypeOf(this, TypeError.prototype); - } -} - -export class NodeURIError extends NodeErrorAbstraction implements URIError { - constructor(code: string, message: string) { - super(URIError.prototype.name, code, message); - Object.setPrototypeOf(this, URIError.prototype); - } -} - -export class ERR_INVALID_ARG_TYPE extends NodeTypeError { - constructor(a1: string, a2: string | string[], a3: unknown) { - super( - "ERR_INVALID_ARG_TYPE", - `The "${a1}" argument must be of type ${ - typeof a2 === "string" - ? a2.toLocaleLowerCase() - : a2.map((x) => x.toLocaleLowerCase()).join(", ") - }. Received ${typeof a3} (${a3})`, - ); - } -} - -export class ERR_OUT_OF_RANGE extends RangeError { - code = "ERR_OUT_OF_RANGE"; - - constructor(str: string, range: string, received: unknown) { - super( - `The value of "${str}" is out of range. It must be ${range}. Received ${received}`, - ); - - const { name } = this; - // Add the error code to the name to include it in the stack trace. - this.name = `${name} [${this.code}]`; - // Access the stack to generate the error message including the error code from the name. - this.stack; - // Reset the name to the actual name. - this.name = name; - } -} - -export class ERR_AMBIGUOUS_ARGUMENT extends NodeTypeError { - constructor(x: string, y: string) { - super("ERR_AMBIGUOUS_ARGUMENT", `The "${x}" argument is ambiguous. ${y}`); - } -} - -export class ERR_ARG_NOT_ITERABLE extends NodeTypeError { - constructor(x: string) { - super("ERR_ARG_NOT_ITERABLE", `${x} must be iterable`); - } -} - -export class ERR_ASSERTION extends NodeError { - constructor(x: string) { - super("ERR_ASSERTION", `${x}`); - } -} - -export class ERR_ASYNC_CALLBACK extends NodeTypeError { - constructor(x: string) { - super("ERR_ASYNC_CALLBACK", `${x} must be a function`); - } -} - -export class ERR_ASYNC_TYPE extends NodeTypeError { - constructor(x: string) { - super("ERR_ASYNC_TYPE", `Invalid name for async "type": ${x}`); - } -} - -export class ERR_BROTLI_INVALID_PARAM extends NodeRangeError { - constructor(x: string) { - super("ERR_BROTLI_INVALID_PARAM", `${x} is not a valid Brotli parameter`); - } -} - -export class ERR_BUFFER_OUT_OF_BOUNDS extends NodeRangeError { - constructor(name?: string) { - super( - "ERR_BUFFER_OUT_OF_BOUNDS", - name - ? `"${name}" is outside of buffer bounds` - : "Attempt to access memory outside buffer bounds", - ); - } -} - -export class ERR_BUFFER_TOO_LARGE extends NodeRangeError { - constructor(x: string) { - super( - "ERR_BUFFER_TOO_LARGE", - `Cannot create a Buffer larger than ${x} bytes`, - ); - } -} - -export class ERR_CANNOT_WATCH_SIGINT extends NodeError { - constructor() { - super( - "ERR_CANNOT_WATCH_SIGINT", - "Cannot watch for SIGINT signals", - ); - } -} - -export class ERR_CHILD_CLOSED_BEFORE_REPLY extends NodeError { - constructor() { - super( - "ERR_CHILD_CLOSED_BEFORE_REPLY", - "Child closed before reply received", - ); - } -} - -export class ERR_CHILD_PROCESS_IPC_REQUIRED extends NodeError { - constructor(x: string) { - super( - "ERR_CHILD_PROCESS_IPC_REQUIRED", - `Forked processes must have an IPC channel, missing value 'ipc' in ${x}`, - ); - } -} - -export class ERR_CHILD_PROCESS_STDIO_MAXBUFFER extends NodeRangeError { - constructor(x: string) { - super( - "ERR_CHILD_PROCESS_STDIO_MAXBUFFER", - `${x} maxBuffer length exceeded`, - ); - } -} - -export class ERR_CONSOLE_WRITABLE_STREAM extends NodeTypeError { - constructor(x: string) { - super( - "ERR_CONSOLE_WRITABLE_STREAM", - `Console expects a writable stream instance for ${x}`, - ); - } -} - -export class ERR_CONTEXT_NOT_INITIALIZED extends NodeError { - constructor() { - super( - "ERR_CONTEXT_NOT_INITIALIZED", - "context used is not initialized", - ); - } -} - -export class ERR_CPU_USAGE extends NodeError { - constructor(x: string) { - super( - "ERR_CPU_USAGE", - `Unable to obtain cpu usage ${x}`, - ); - } -} - -export class ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED extends NodeError { - constructor() { - super( - "ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED", - "Custom engines not supported by this OpenSSL", - ); - } -} - -export class ERR_CRYPTO_ECDH_INVALID_FORMAT extends NodeTypeError { - constructor(x: string) { - super( - "ERR_CRYPTO_ECDH_INVALID_FORMAT", - `Invalid ECDH format: ${x}`, - ); - } -} - -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", - ); - } -} - -export class ERR_CRYPTO_ENGINE_UNKNOWN extends NodeError { - constructor(x: string) { - super( - "ERR_CRYPTO_ENGINE_UNKNOWN", - `Engine "${x}" was not found`, - ); - } -} - -export class ERR_CRYPTO_FIPS_FORCED extends NodeError { - constructor() { - super( - "ERR_CRYPTO_FIPS_FORCED", - "Cannot set FIPS mode, it was forced with --force-fips at startup.", - ); - } -} - -export class ERR_CRYPTO_FIPS_UNAVAILABLE extends NodeError { - constructor() { - super( - "ERR_CRYPTO_FIPS_UNAVAILABLE", - "Cannot set FIPS mode in a non-FIPS build.", - ); - } -} - -export class ERR_CRYPTO_HASH_FINALIZED extends NodeError { - constructor() { - 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", - ); - } -} - -export class ERR_CRYPTO_INCOMPATIBLE_KEY extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_CRYPTO_INCOMPATIBLE_KEY", - `Incompatible ${x}: ${y}`, - ); - } -} - -export class ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS", - `The selected key encoding ${x} ${y}.`, - ); - } -} - -export class ERR_CRYPTO_INVALID_DIGEST extends NodeTypeError { - constructor(x: string) { - super( - "ERR_CRYPTO_INVALID_DIGEST", - `Invalid digest: ${x}`, - ); - } -} - -export class ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE", - `Invalid key object type ${x}, expected ${y}.`, - ); - } -} - -export class ERR_CRYPTO_INVALID_STATE extends NodeError { - constructor(x: string) { - super( - "ERR_CRYPTO_INVALID_STATE", - `Invalid state for operation ${x}`, - ); - } -} - -export class ERR_CRYPTO_PBKDF2_ERROR extends NodeError { - constructor() { - super( - "ERR_CRYPTO_PBKDF2_ERROR", - "PBKDF2 error", - ); - } -} - -export class ERR_CRYPTO_SCRYPT_INVALID_PARAMETER extends NodeError { - constructor() { - super( - "ERR_CRYPTO_SCRYPT_INVALID_PARAMETER", - "Invalid scrypt parameter", - ); - } -} - -export class ERR_CRYPTO_SCRYPT_NOT_SUPPORTED extends NodeError { - constructor() { - super( - "ERR_CRYPTO_SCRYPT_NOT_SUPPORTED", - "Scrypt algorithm not supported", - ); - } -} - -export class ERR_CRYPTO_SIGN_KEY_REQUIRED extends NodeError { - constructor() { - super( - "ERR_CRYPTO_SIGN_KEY_REQUIRED", - "No key provided to sign", - ); - } -} - -export class ERR_DIR_CLOSED extends NodeError { - constructor() { - super( - "ERR_DIR_CLOSED", - "Directory handle was closed", - ); - } -} - -export class ERR_DIR_CONCURRENT_OPERATION extends NodeError { - constructor() { - super( - "ERR_DIR_CONCURRENT_OPERATION", - "Cannot do synchronous work on directory handle with concurrent asynchronous operations", - ); - } -} - -export class ERR_DNS_SET_SERVERS_FAILED extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_DNS_SET_SERVERS_FAILED", - `c-ares failed to set servers: "${x}" [${y}]`, - ); - } -} - -export class ERR_DOMAIN_CALLBACK_NOT_AVAILABLE extends NodeError { - constructor() { - super( - "ERR_DOMAIN_CALLBACK_NOT_AVAILABLE", - "A callback was registered through " + - "process.setUncaughtExceptionCaptureCallback(), which is mutually " + - "exclusive with using the `domain` module", - ); - } -} - -export class ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE - extends NodeError { - constructor() { - super( - "ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE", - "The `domain` module is in use, which is mutually exclusive with calling " + - "process.setUncaughtExceptionCaptureCallback()", - ); - } -} - -export class ERR_ENCODING_INVALID_ENCODED_DATA extends NodeErrorAbstraction - implements TypeError { - errno: number; - constructor(encoding: string, ret: number) { - super( - TypeError.prototype.name, - "ERR_ENCODING_INVALID_ENCODED_DATA", - `The encoded data was not valid for encoding ${encoding}`, - ); - Object.setPrototypeOf(this, TypeError.prototype); - - this.errno = ret; - } -} - -// In Node these values are coming from libuv: -// Ref: https://github.com/libuv/libuv/blob/v1.x/include/uv/errno.h -// Ref: https://github.com/nodejs/node/blob/524123fbf064ff64bb6fcd83485cfc27db932f68/lib/internal/errors.js#L383 -// Since there is no easy way to port code from libuv and these maps are -// changing very rarely, we simply extract them from Node and store here. - -// Note -// Run the following to get the map: -// $ node -e "console.log(process.binding('uv').getErrorMap())" -// This setup automatically exports maps from both "win", "linux" & darwin: -// https://github.com/schwarzkopfb/node_errno_map - -type ErrMapData = Array<[number, [string, string]]>; - -const windows: ErrMapData = [ - [-4093, ["E2BIG", "argument list too long"]], - [-4092, ["EACCES", "permission denied"]], - [-4091, ["EADDRINUSE", "address already in use"]], - [-4090, ["EADDRNOTAVAIL", "address not available"]], - [-4089, ["EAFNOSUPPORT", "address family not supported"]], - [-4088, ["EAGAIN", "resource temporarily unavailable"]], - [-3000, ["EAI_ADDRFAMILY", "address family not supported"]], - [-3001, ["EAI_AGAIN", "temporary failure"]], - [-3002, ["EAI_BADFLAGS", "bad ai_flags value"]], - [-3013, ["EAI_BADHINTS", "invalid value for hints"]], - [-3003, ["EAI_CANCELED", "request canceled"]], - [-3004, ["EAI_FAIL", "permanent failure"]], - [-3005, ["EAI_FAMILY", "ai_family not supported"]], - [-3006, ["EAI_MEMORY", "out of memory"]], - [-3007, ["EAI_NODATA", "no address"]], - [-3008, ["EAI_NONAME", "unknown node or service"]], - [-3009, ["EAI_OVERFLOW", "argument buffer overflow"]], - [-3014, ["EAI_PROTOCOL", "resolved protocol is unknown"]], - [-3010, ["EAI_SERVICE", "service not available for socket type"]], - [-3011, ["EAI_SOCKTYPE", "socket type not supported"]], - [-4084, ["EALREADY", "connection already in progress"]], - [-4083, ["EBADF", "bad file descriptor"]], - [-4082, ["EBUSY", "resource busy or locked"]], - [-4081, ["ECANCELED", "operation canceled"]], - [-4080, ["ECHARSET", "invalid Unicode character"]], - [-4079, ["ECONNABORTED", "software caused connection abort"]], - [-4078, ["ECONNREFUSED", "connection refused"]], - [-4077, ["ECONNRESET", "connection reset by peer"]], - [-4076, ["EDESTADDRREQ", "destination address required"]], - [-4075, ["EEXIST", "file already exists"]], - [-4074, ["EFAULT", "bad address in system call argument"]], - [-4036, ["EFBIG", "file too large"]], - [-4073, ["EHOSTUNREACH", "host is unreachable"]], - [-4072, ["EINTR", "interrupted system call"]], - [-4071, ["EINVAL", "invalid argument"]], - [-4070, ["EIO", "i/o error"]], - [-4069, ["EISCONN", "socket is already connected"]], - [-4068, ["EISDIR", "illegal operation on a directory"]], - [-4067, ["ELOOP", "too many symbolic links encountered"]], - [-4066, ["EMFILE", "too many open files"]], - [-4065, ["EMSGSIZE", "message too long"]], - [-4064, ["ENAMETOOLONG", "name too long"]], - [-4063, ["ENETDOWN", "network is down"]], - [-4062, ["ENETUNREACH", "network is unreachable"]], - [-4061, ["ENFILE", "file table overflow"]], - [-4060, ["ENOBUFS", "no buffer space available"]], - [-4059, ["ENODEV", "no such device"]], - [-4058, ["ENOENT", "no such file or directory"]], - [-4057, ["ENOMEM", "not enough memory"]], - [-4056, ["ENONET", "machine is not on the network"]], - [-4035, ["ENOPROTOOPT", "protocol not available"]], - [-4055, ["ENOSPC", "no space left on device"]], - [-4054, ["ENOSYS", "function not implemented"]], - [-4053, ["ENOTCONN", "socket is not connected"]], - [-4052, ["ENOTDIR", "not a directory"]], - [-4051, ["ENOTEMPTY", "directory not empty"]], - [-4050, ["ENOTSOCK", "socket operation on non-socket"]], - [-4049, ["ENOTSUP", "operation not supported on socket"]], - [-4048, ["EPERM", "operation not permitted"]], - [-4047, ["EPIPE", "broken pipe"]], - [-4046, ["EPROTO", "protocol error"]], - [-4045, ["EPROTONOSUPPORT", "protocol not supported"]], - [-4044, ["EPROTOTYPE", "protocol wrong type for socket"]], - [-4034, ["ERANGE", "result too large"]], - [-4043, ["EROFS", "read-only file system"]], - [-4042, ["ESHUTDOWN", "cannot send after transport endpoint shutdown"]], - [-4041, ["ESPIPE", "invalid seek"]], - [-4040, ["ESRCH", "no such process"]], - [-4039, ["ETIMEDOUT", "connection timed out"]], - [-4038, ["ETXTBSY", "text file is busy"]], - [-4037, ["EXDEV", "cross-device link not permitted"]], - [-4094, ["UNKNOWN", "unknown error"]], - [-4095, ["EOF", "end of file"]], - [-4033, ["ENXIO", "no such device or address"]], - [-4032, ["EMLINK", "too many links"]], - [-4031, ["EHOSTDOWN", "host is down"]], - [-4030, ["EREMOTEIO", "remote I/O error"]], - [-4029, ["ENOTTY", "inappropriate ioctl for device"]], - [-4028, ["EFTYPE", "inappropriate file type or format"]], - [-4027, ["EILSEQ", "illegal byte sequence"]], -]; - -const darwin: ErrMapData = [ - [-7, ["E2BIG", "argument list too long"]], - [-13, ["EACCES", "permission denied"]], - [-48, ["EADDRINUSE", "address already in use"]], - [-49, ["EADDRNOTAVAIL", "address not available"]], - [-47, ["EAFNOSUPPORT", "address family not supported"]], - [-35, ["EAGAIN", "resource temporarily unavailable"]], - [-3000, ["EAI_ADDRFAMILY", "address family not supported"]], - [-3001, ["EAI_AGAIN", "temporary failure"]], - [-3002, ["EAI_BADFLAGS", "bad ai_flags value"]], - [-3013, ["EAI_BADHINTS", "invalid value for hints"]], - [-3003, ["EAI_CANCELED", "request canceled"]], - [-3004, ["EAI_FAIL", "permanent failure"]], - [-3005, ["EAI_FAMILY", "ai_family not supported"]], - [-3006, ["EAI_MEMORY", "out of memory"]], - [-3007, ["EAI_NODATA", "no address"]], - [-3008, ["EAI_NONAME", "unknown node or service"]], - [-3009, ["EAI_OVERFLOW", "argument buffer overflow"]], - [-3014, ["EAI_PROTOCOL", "resolved protocol is unknown"]], - [-3010, ["EAI_SERVICE", "service not available for socket type"]], - [-3011, ["EAI_SOCKTYPE", "socket type not supported"]], - [-37, ["EALREADY", "connection already in progress"]], - [-9, ["EBADF", "bad file descriptor"]], - [-16, ["EBUSY", "resource busy or locked"]], - [-89, ["ECANCELED", "operation canceled"]], - [-4080, ["ECHARSET", "invalid Unicode character"]], - [-53, ["ECONNABORTED", "software caused connection abort"]], - [-61, ["ECONNREFUSED", "connection refused"]], - [-54, ["ECONNRESET", "connection reset by peer"]], - [-39, ["EDESTADDRREQ", "destination address required"]], - [-17, ["EEXIST", "file already exists"]], - [-14, ["EFAULT", "bad address in system call argument"]], - [-27, ["EFBIG", "file too large"]], - [-65, ["EHOSTUNREACH", "host is unreachable"]], - [-4, ["EINTR", "interrupted system call"]], - [-22, ["EINVAL", "invalid argument"]], - [-5, ["EIO", "i/o error"]], - [-56, ["EISCONN", "socket is already connected"]], - [-21, ["EISDIR", "illegal operation on a directory"]], - [-62, ["ELOOP", "too many symbolic links encountered"]], - [-24, ["EMFILE", "too many open files"]], - [-40, ["EMSGSIZE", "message too long"]], - [-63, ["ENAMETOOLONG", "name too long"]], - [-50, ["ENETDOWN", "network is down"]], - [-51, ["ENETUNREACH", "network is unreachable"]], - [-23, ["ENFILE", "file table overflow"]], - [-55, ["ENOBUFS", "no buffer space available"]], - [-19, ["ENODEV", "no such device"]], - [-2, ["ENOENT", "no such file or directory"]], - [-12, ["ENOMEM", "not enough memory"]], - [-4056, ["ENONET", "machine is not on the network"]], - [-42, ["ENOPROTOOPT", "protocol not available"]], - [-28, ["ENOSPC", "no space left on device"]], - [-78, ["ENOSYS", "function not implemented"]], - [-57, ["ENOTCONN", "socket is not connected"]], - [-20, ["ENOTDIR", "not a directory"]], - [-66, ["ENOTEMPTY", "directory not empty"]], - [-38, ["ENOTSOCK", "socket operation on non-socket"]], - [-45, ["ENOTSUP", "operation not supported on socket"]], - [-1, ["EPERM", "operation not permitted"]], - [-32, ["EPIPE", "broken pipe"]], - [-100, ["EPROTO", "protocol error"]], - [-43, ["EPROTONOSUPPORT", "protocol not supported"]], - [-41, ["EPROTOTYPE", "protocol wrong type for socket"]], - [-34, ["ERANGE", "result too large"]], - [-30, ["EROFS", "read-only file system"]], - [-58, ["ESHUTDOWN", "cannot send after transport endpoint shutdown"]], - [-29, ["ESPIPE", "invalid seek"]], - [-3, ["ESRCH", "no such process"]], - [-60, ["ETIMEDOUT", "connection timed out"]], - [-26, ["ETXTBSY", "text file is busy"]], - [-18, ["EXDEV", "cross-device link not permitted"]], - [-4094, ["UNKNOWN", "unknown error"]], - [-4095, ["EOF", "end of file"]], - [-6, ["ENXIO", "no such device or address"]], - [-31, ["EMLINK", "too many links"]], - [-64, ["EHOSTDOWN", "host is down"]], - [-4030, ["EREMOTEIO", "remote I/O error"]], - [-25, ["ENOTTY", "inappropriate ioctl for device"]], - [-79, ["EFTYPE", "inappropriate file type or format"]], - [-92, ["EILSEQ", "illegal byte sequence"]], -]; - -const linux: ErrMapData = [ - [-7, ["E2BIG", "argument list too long"]], - [-13, ["EACCES", "permission denied"]], - [-98, ["EADDRINUSE", "address already in use"]], - [-99, ["EADDRNOTAVAIL", "address not available"]], - [-97, ["EAFNOSUPPORT", "address family not supported"]], - [-11, ["EAGAIN", "resource temporarily unavailable"]], - [-3000, ["EAI_ADDRFAMILY", "address family not supported"]], - [-3001, ["EAI_AGAIN", "temporary failure"]], - [-3002, ["EAI_BADFLAGS", "bad ai_flags value"]], - [-3013, ["EAI_BADHINTS", "invalid value for hints"]], - [-3003, ["EAI_CANCELED", "request canceled"]], - [-3004, ["EAI_FAIL", "permanent failure"]], - [-3005, ["EAI_FAMILY", "ai_family not supported"]], - [-3006, ["EAI_MEMORY", "out of memory"]], - [-3007, ["EAI_NODATA", "no address"]], - [-3008, ["EAI_NONAME", "unknown node or service"]], - [-3009, ["EAI_OVERFLOW", "argument buffer overflow"]], - [-3014, ["EAI_PROTOCOL", "resolved protocol is unknown"]], - [-3010, ["EAI_SERVICE", "service not available for socket type"]], - [-3011, ["EAI_SOCKTYPE", "socket type not supported"]], - [-114, ["EALREADY", "connection already in progress"]], - [-9, ["EBADF", "bad file descriptor"]], - [-16, ["EBUSY", "resource busy or locked"]], - [-125, ["ECANCELED", "operation canceled"]], - [-4080, ["ECHARSET", "invalid Unicode character"]], - [-103, ["ECONNABORTED", "software caused connection abort"]], - [-111, ["ECONNREFUSED", "connection refused"]], - [-104, ["ECONNRESET", "connection reset by peer"]], - [-89, ["EDESTADDRREQ", "destination address required"]], - [-17, ["EEXIST", "file already exists"]], - [-14, ["EFAULT", "bad address in system call argument"]], - [-27, ["EFBIG", "file too large"]], - [-113, ["EHOSTUNREACH", "host is unreachable"]], - [-4, ["EINTR", "interrupted system call"]], - [-22, ["EINVAL", "invalid argument"]], - [-5, ["EIO", "i/o error"]], - [-106, ["EISCONN", "socket is already connected"]], - [-21, ["EISDIR", "illegal operation on a directory"]], - [-40, ["ELOOP", "too many symbolic links encountered"]], - [-24, ["EMFILE", "too many open files"]], - [-90, ["EMSGSIZE", "message too long"]], - [-36, ["ENAMETOOLONG", "name too long"]], - [-100, ["ENETDOWN", "network is down"]], - [-101, ["ENETUNREACH", "network is unreachable"]], - [-23, ["ENFILE", "file table overflow"]], - [-105, ["ENOBUFS", "no buffer space available"]], - [-19, ["ENODEV", "no such device"]], - [-2, ["ENOENT", "no such file or directory"]], - [-12, ["ENOMEM", "not enough memory"]], - [-64, ["ENONET", "machine is not on the network"]], - [-92, ["ENOPROTOOPT", "protocol not available"]], - [-28, ["ENOSPC", "no space left on device"]], - [-38, ["ENOSYS", "function not implemented"]], - [-107, ["ENOTCONN", "socket is not connected"]], - [-20, ["ENOTDIR", "not a directory"]], - [-39, ["ENOTEMPTY", "directory not empty"]], - [-88, ["ENOTSOCK", "socket operation on non-socket"]], - [-95, ["ENOTSUP", "operation not supported on socket"]], - [-1, ["EPERM", "operation not permitted"]], - [-32, ["EPIPE", "broken pipe"]], - [-71, ["EPROTO", "protocol error"]], - [-93, ["EPROTONOSUPPORT", "protocol not supported"]], - [-91, ["EPROTOTYPE", "protocol wrong type for socket"]], - [-34, ["ERANGE", "result too large"]], - [-30, ["EROFS", "read-only file system"]], - [-108, ["ESHUTDOWN", "cannot send after transport endpoint shutdown"]], - [-29, ["ESPIPE", "invalid seek"]], - [-3, ["ESRCH", "no such process"]], - [-110, ["ETIMEDOUT", "connection timed out"]], - [-26, ["ETXTBSY", "text file is busy"]], - [-18, ["EXDEV", "cross-device link not permitted"]], - [-4094, ["UNKNOWN", "unknown error"]], - [-4095, ["EOF", "end of file"]], - [-6, ["ENXIO", "no such device or address"]], - [-31, ["EMLINK", "too many links"]], - [-112, ["EHOSTDOWN", "host is down"]], - [-121, ["EREMOTEIO", "remote I/O error"]], - [-25, ["ENOTTY", "inappropriate ioctl for device"]], - [-4028, ["EFTYPE", "inappropriate file type or format"]], - [-84, ["EILSEQ", "illegal byte sequence"]], -]; - -const { os } = Deno.build; -export const errorMap = new Map<number, [string, string]>( - os === "windows" - ? windows - : os === "darwin" - ? darwin - : os === "linux" - ? linux - : unreachable(), -); -export class ERR_ENCODING_NOT_SUPPORTED extends NodeRangeError { - constructor(x: string) { - super( - "ERR_ENCODING_NOT_SUPPORTED", - `The "${x}" encoding is not supported`, - ); - } -} -export class ERR_EVAL_ESM_CANNOT_PRINT extends NodeError { - constructor() { - super( - "ERR_EVAL_ESM_CANNOT_PRINT", - `--print cannot be used with ESM input`, - ); - } -} -export class ERR_EVENT_RECURSION extends NodeError { - constructor(x: string) { - super( - "ERR_EVENT_RECURSION", - `The event "${x}" is already being dispatched`, - ); - } -} -export class ERR_FEATURE_UNAVAILABLE_ON_PLATFORM extends NodeTypeError { - constructor(x: string) { - super( - "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM", - `The feature ${x} is unavailable on the current platform, which is being used to run Node.js`, - ); - } -} -export class ERR_FS_FILE_TOO_LARGE extends NodeRangeError { - constructor(x: string) { - super( - "ERR_FS_FILE_TOO_LARGE", - `File size (${x}) is greater than 2 GB`, - ); - } -} -export class ERR_FS_INVALID_SYMLINK_TYPE extends NodeError { - constructor(x: string) { - super( - "ERR_FS_INVALID_SYMLINK_TYPE", - `Symlink type must be one of "dir", "file", or "junction". Received "${x}"`, - ); - } -} -export class ERR_HTTP2_ALTSVC_INVALID_ORIGIN extends NodeTypeError { - constructor() { - super( - "ERR_HTTP2_ALTSVC_INVALID_ORIGIN", - `HTTP/2 ALTSVC frames require a valid origin`, - ); - } -} -export class ERR_HTTP2_ALTSVC_LENGTH extends NodeTypeError { - constructor() { - super( - "ERR_HTTP2_ALTSVC_LENGTH", - `HTTP/2 ALTSVC frames are limited to 16382 bytes`, - ); - } -} -export class ERR_HTTP2_CONNECT_AUTHORITY extends NodeError { - constructor() { - super( - "ERR_HTTP2_CONNECT_AUTHORITY", - `:authority header is required for CONNECT requests`, - ); - } -} -export class ERR_HTTP2_CONNECT_PATH extends NodeError { - constructor() { - super( - "ERR_HTTP2_CONNECT_PATH", - `The :path header is forbidden for CONNECT requests`, - ); - } -} -export class ERR_HTTP2_CONNECT_SCHEME extends NodeError { - constructor() { - super( - "ERR_HTTP2_CONNECT_SCHEME", - `The :scheme header is forbidden for CONNECT requests`, - ); - } -} -export class ERR_HTTP2_GOAWAY_SESSION extends NodeError { - constructor() { - super( - "ERR_HTTP2_GOAWAY_SESSION", - `New streams cannot be created after receiving a GOAWAY`, - ); - } -} -export class ERR_HTTP2_HEADERS_AFTER_RESPOND extends NodeError { - constructor() { - super( - "ERR_HTTP2_HEADERS_AFTER_RESPOND", - `Cannot specify additional headers after response initiated`, - ); - } -} -export class ERR_HTTP2_HEADERS_SENT extends NodeError { - constructor() { - super( - "ERR_HTTP2_HEADERS_SENT", - `Response has already been initiated.`, - ); - } -} -export class ERR_HTTP2_HEADER_SINGLE_VALUE extends NodeTypeError { - constructor(x: string) { - super( - "ERR_HTTP2_HEADER_SINGLE_VALUE", - `Header field "${x}" must only have a single value`, - ); - } -} -export class ERR_HTTP2_INFO_STATUS_NOT_ALLOWED extends NodeRangeError { - constructor() { - super( - "ERR_HTTP2_INFO_STATUS_NOT_ALLOWED", - `Informational status codes cannot be used`, - ); - } -} -export class ERR_HTTP2_INVALID_CONNECTION_HEADERS extends NodeTypeError { - constructor(x: string) { - super( - "ERR_HTTP2_INVALID_CONNECTION_HEADERS", - `HTTP/1 Connection specific headers are forbidden: "${x}"`, - ); - } -} -export class ERR_HTTP2_INVALID_HEADER_VALUE extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_HTTP2_INVALID_HEADER_VALUE", - `Invalid value "${x}" for header "${y}"`, - ); - } -} -export class ERR_HTTP2_INVALID_INFO_STATUS extends NodeRangeError { - constructor(x: string) { - super( - "ERR_HTTP2_INVALID_INFO_STATUS", - `Invalid informational status code: ${x}`, - ); - } -} -export class ERR_HTTP2_INVALID_ORIGIN extends NodeTypeError { - constructor() { - super( - "ERR_HTTP2_INVALID_ORIGIN", - `HTTP/2 ORIGIN frames require a valid origin`, - ); - } -} -export class ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH extends NodeRangeError { - constructor() { - super( - "ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH", - `Packed settings length must be a multiple of six`, - ); - } -} -export class ERR_HTTP2_INVALID_PSEUDOHEADER extends NodeTypeError { - constructor(x: string) { - super( - "ERR_HTTP2_INVALID_PSEUDOHEADER", - `"${x}" is an invalid pseudoheader or is used incorrectly`, - ); - } -} -export class ERR_HTTP2_INVALID_SESSION extends NodeError { - constructor() { - super( - "ERR_HTTP2_INVALID_SESSION", - `The session has been destroyed`, - ); - } -} -export class ERR_HTTP2_INVALID_STREAM extends NodeError { - constructor() { - super( - "ERR_HTTP2_INVALID_STREAM", - `The stream has been destroyed`, - ); - } -} -export class ERR_HTTP2_MAX_PENDING_SETTINGS_ACK extends NodeError { - constructor() { - super( - "ERR_HTTP2_MAX_PENDING_SETTINGS_ACK", - `Maximum number of pending settings acknowledgements`, - ); - } -} -export class ERR_HTTP2_NESTED_PUSH extends NodeError { - constructor() { - super( - "ERR_HTTP2_NESTED_PUSH", - `A push stream cannot initiate another push stream.`, - ); - } -} -export class ERR_HTTP2_NO_SOCKET_MANIPULATION extends NodeError { - constructor() { - super( - "ERR_HTTP2_NO_SOCKET_MANIPULATION", - `HTTP/2 sockets should not be directly manipulated (e.g. read and written)`, - ); - } -} -export class ERR_HTTP2_ORIGIN_LENGTH extends NodeTypeError { - constructor() { - super( - "ERR_HTTP2_ORIGIN_LENGTH", - `HTTP/2 ORIGIN frames are limited to 16382 bytes`, - ); - } -} -export class ERR_HTTP2_OUT_OF_STREAMS extends NodeError { - constructor() { - super( - "ERR_HTTP2_OUT_OF_STREAMS", - `No stream ID is available because maximum stream ID has been reached`, - ); - } -} -export class ERR_HTTP2_PAYLOAD_FORBIDDEN extends NodeError { - constructor(x: string) { - super( - "ERR_HTTP2_PAYLOAD_FORBIDDEN", - `Responses with ${x} status must not have a payload`, - ); - } -} -export class ERR_HTTP2_PING_CANCEL extends NodeError { - constructor() { - super( - "ERR_HTTP2_PING_CANCEL", - `HTTP2 ping cancelled`, - ); - } -} -export class ERR_HTTP2_PING_LENGTH extends NodeRangeError { - constructor() { - super( - "ERR_HTTP2_PING_LENGTH", - `HTTP2 ping payload must be 8 bytes`, - ); - } -} -export class ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED extends NodeTypeError { - constructor() { - super( - "ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED", - `Cannot set HTTP/2 pseudo-headers`, - ); - } -} -export class ERR_HTTP2_PUSH_DISABLED extends NodeError { - constructor() { - super( - "ERR_HTTP2_PUSH_DISABLED", - `HTTP/2 client has disabled push streams`, - ); - } -} -export class ERR_HTTP2_SEND_FILE extends NodeError { - constructor() { - super( - "ERR_HTTP2_SEND_FILE", - `Directories cannot be sent`, - ); - } -} -export class ERR_HTTP2_SEND_FILE_NOSEEK extends NodeError { - constructor() { - super( - "ERR_HTTP2_SEND_FILE_NOSEEK", - `Offset or length can only be specified for regular files`, - ); - } -} -export class ERR_HTTP2_SESSION_ERROR extends NodeError { - constructor(x: string) { - super( - "ERR_HTTP2_SESSION_ERROR", - `Session closed with error code ${x}`, - ); - } -} -export class ERR_HTTP2_SETTINGS_CANCEL extends NodeError { - constructor() { - super( - "ERR_HTTP2_SETTINGS_CANCEL", - `HTTP2 session settings canceled`, - ); - } -} -export class ERR_HTTP2_SOCKET_BOUND extends NodeError { - constructor() { - super( - "ERR_HTTP2_SOCKET_BOUND", - `The socket is already bound to an Http2Session`, - ); - } -} -export class ERR_HTTP2_SOCKET_UNBOUND extends NodeError { - constructor() { - super( - "ERR_HTTP2_SOCKET_UNBOUND", - `The socket has been disconnected from the Http2Session`, - ); - } -} -export class ERR_HTTP2_STATUS_101 extends NodeError { - constructor() { - super( - "ERR_HTTP2_STATUS_101", - `HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2`, - ); - } -} -export class ERR_HTTP2_STATUS_INVALID extends NodeRangeError { - constructor(x: string) { - super( - "ERR_HTTP2_STATUS_INVALID", - `Invalid status code: ${x}`, - ); - } -} -export class ERR_HTTP2_STREAM_ERROR extends NodeError { - constructor(x: string) { - super( - "ERR_HTTP2_STREAM_ERROR", - `Stream closed with error code ${x}`, - ); - } -} -export class ERR_HTTP2_STREAM_SELF_DEPENDENCY extends NodeError { - constructor() { - super( - "ERR_HTTP2_STREAM_SELF_DEPENDENCY", - `A stream cannot depend on itself`, - ); - } -} -export class ERR_HTTP2_TRAILERS_ALREADY_SENT extends NodeError { - constructor() { - super( - "ERR_HTTP2_TRAILERS_ALREADY_SENT", - `Trailing headers have already been sent`, - ); - } -} -export class ERR_HTTP2_TRAILERS_NOT_READY extends NodeError { - constructor() { - super( - "ERR_HTTP2_TRAILERS_NOT_READY", - `Trailing headers cannot be sent until after the wantTrailers event is emitted`, - ); - } -} -export class ERR_HTTP2_UNSUPPORTED_PROTOCOL extends NodeError { - constructor(x: string) { - super( - "ERR_HTTP2_UNSUPPORTED_PROTOCOL", - `protocol "${x}" is unsupported.`, - ); - } -} -export class ERR_HTTP_HEADERS_SENT extends NodeError { - constructor(x: string) { - super( - "ERR_HTTP_HEADERS_SENT", - `Cannot ${x} headers after they are sent to the client`, - ); - } -} -export class ERR_HTTP_INVALID_HEADER_VALUE extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_HTTP_INVALID_HEADER_VALUE", - `Invalid value "${x}" for header "${y}"`, - ); - } -} -export class ERR_HTTP_INVALID_STATUS_CODE extends NodeRangeError { - constructor(x: string) { - super( - "ERR_HTTP_INVALID_STATUS_CODE", - `Invalid status code: ${x}`, - ); - } -} -export class ERR_HTTP_SOCKET_ENCODING extends NodeError { - constructor() { - super( - "ERR_HTTP_SOCKET_ENCODING", - `Changing the socket encoding is not allowed per RFC7230 Section 3.`, - ); - } -} -export class ERR_HTTP_TRAILER_INVALID extends NodeError { - constructor() { - super( - "ERR_HTTP_TRAILER_INVALID", - `Trailers are invalid with this transfer encoding`, - ); - } -} -export class ERR_INCOMPATIBLE_OPTION_PAIR extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_INCOMPATIBLE_OPTION_PAIR", - `Option "${x}" cannot be used in combination with option "${y}"`, - ); - } -} -export class ERR_INPUT_TYPE_NOT_ALLOWED extends NodeError { - constructor() { - super( - "ERR_INPUT_TYPE_NOT_ALLOWED", - `--input-type can only be used with string input via --eval, --print, or STDIN`, - ); - } -} -export class ERR_INSPECTOR_ALREADY_ACTIVATED extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_ALREADY_ACTIVATED", - `Inspector is already activated. Close it with inspector.close() before activating it again.`, - ); - } -} -export class ERR_INSPECTOR_ALREADY_CONNECTED extends NodeError { - constructor(x: string) { - super( - "ERR_INSPECTOR_ALREADY_CONNECTED", - `${x} is already connected`, - ); - } -} -export class ERR_INSPECTOR_CLOSED extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_CLOSED", - `Session was closed`, - ); - } -} -export class ERR_INSPECTOR_COMMAND extends NodeError { - constructor(x: number, y: string) { - super( - "ERR_INSPECTOR_COMMAND", - `Inspector error ${x}: ${y}`, - ); - } -} -export class ERR_INSPECTOR_NOT_ACTIVE extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_NOT_ACTIVE", - `Inspector is not active`, - ); - } -} -export class ERR_INSPECTOR_NOT_AVAILABLE extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_NOT_AVAILABLE", - `Inspector is not available`, - ); - } -} -export class ERR_INSPECTOR_NOT_CONNECTED extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_NOT_CONNECTED", - `Session is not connected`, - ); - } -} -export class ERR_INSPECTOR_NOT_WORKER extends NodeError { - constructor() { - super( - "ERR_INSPECTOR_NOT_WORKER", - `Current thread is not a worker`, - ); - } -} -export class ERR_INVALID_ASYNC_ID extends NodeRangeError { - constructor(x: string, y: string) { - super( - "ERR_INVALID_ASYNC_ID", - `Invalid ${x} value: ${y}`, - ); - } -} -export class ERR_INVALID_BUFFER_SIZE extends NodeRangeError { - constructor(x: string) { - super( - "ERR_INVALID_BUFFER_SIZE", - `Buffer size must be a multiple of ${x}`, - ); - } -} -export class ERR_INVALID_CALLBACK extends NodeTypeError { - constructor(object: unknown) { - super( - "ERR_INVALID_CALLBACK", - `Callback must be a function. Received ${JSON.stringify(object)}`, - ); - } -} -export class ERR_INVALID_CURSOR_POS extends NodeTypeError { - constructor() { - super( - "ERR_INVALID_CURSOR_POS", - `Cannot set cursor row without setting its column`, - ); - } -} -export class ERR_INVALID_FD extends NodeRangeError { - constructor(x: string) { - super( - "ERR_INVALID_FD", - `"fd" must be a positive integer: ${x}`, - ); - } -} -export class ERR_INVALID_FD_TYPE extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_FD_TYPE", - `Unsupported fd type: ${x}`, - ); - } -} -export class ERR_INVALID_FILE_URL_HOST extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_FILE_URL_HOST", - `File URL host must be "localhost" or empty on ${x}`, - ); - } -} -export class ERR_INVALID_FILE_URL_PATH extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_FILE_URL_PATH", - `File URL path ${x}`, - ); - } -} -export class ERR_INVALID_HANDLE_TYPE extends NodeTypeError { - constructor() { - super( - "ERR_INVALID_HANDLE_TYPE", - `This handle type cannot be sent`, - ); - } -} -export class ERR_INVALID_HTTP_TOKEN extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_INVALID_HTTP_TOKEN", - `${x} must be a valid HTTP token ["${y}"]`, - ); - } -} -export class ERR_INVALID_IP_ADDRESS extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_IP_ADDRESS", - `Invalid IP address: ${x}`, - ); - } -} -export class ERR_INVALID_OPT_VALUE_ENCODING extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_OPT_VALUE_ENCODING", - `The value "${x}" is invalid for option "encoding"`, - ); - } -} -export class ERR_INVALID_PERFORMANCE_MARK extends NodeError { - constructor(x: string) { - super( - "ERR_INVALID_PERFORMANCE_MARK", - `The "${x}" performance mark has not been set`, - ); - } -} -export class ERR_INVALID_PROTOCOL extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_INVALID_PROTOCOL", - `Protocol "${x}" not supported. Expected "${y}"`, - ); - } -} -export class ERR_INVALID_REPL_EVAL_CONFIG extends NodeTypeError { - constructor() { - super( - "ERR_INVALID_REPL_EVAL_CONFIG", - `Cannot specify both "breakEvalOnSigint" and "eval" for REPL`, - ); - } -} -export class ERR_INVALID_REPL_INPUT extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_REPL_INPUT", - `${x}`, - ); - } -} -export class ERR_INVALID_SYNC_FORK_INPUT extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_SYNC_FORK_INPUT", - `Asynchronous forks do not support Buffer, TypedArray, DataView or string input: ${x}`, - ); - } -} -export class ERR_INVALID_THIS extends NodeTypeError { - constructor(x: string) { - super( - "ERR_INVALID_THIS", - `Value of "this" must be of type ${x}`, - ); - } -} -export class ERR_INVALID_TUPLE extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_INVALID_TUPLE", - `${x} must be an iterable ${y} tuple`, - ); - } -} -export class ERR_INVALID_URI extends NodeURIError { - constructor() { - super( - "ERR_INVALID_URI", - `URI malformed`, - ); - } -} -export class ERR_IPC_CHANNEL_CLOSED extends NodeError { - constructor() { - super( - "ERR_IPC_CHANNEL_CLOSED", - `Channel closed`, - ); - } -} -export class ERR_IPC_DISCONNECTED extends NodeError { - constructor() { - super( - "ERR_IPC_DISCONNECTED", - `IPC channel is already disconnected`, - ); - } -} -export class ERR_IPC_ONE_PIPE extends NodeError { - constructor() { - super( - "ERR_IPC_ONE_PIPE", - `Child process can have only one IPC pipe`, - ); - } -} -export class ERR_IPC_SYNC_FORK extends NodeError { - constructor() { - super( - "ERR_IPC_SYNC_FORK", - `IPC cannot be used with synchronous forks`, - ); - } -} -export class ERR_MANIFEST_DEPENDENCY_MISSING extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_MANIFEST_DEPENDENCY_MISSING", - `Manifest resource ${x} does not list ${y} as a dependency specifier`, - ); - } -} -export class ERR_MANIFEST_INTEGRITY_MISMATCH extends NodeSyntaxError { - constructor(x: string) { - super( - "ERR_MANIFEST_INTEGRITY_MISMATCH", - `Manifest resource ${x} has multiple entries but integrity lists do not match`, - ); - } -} -export class ERR_MANIFEST_INVALID_RESOURCE_FIELD extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_MANIFEST_INVALID_RESOURCE_FIELD", - `Manifest resource ${x} has invalid property value for ${y}`, - ); - } -} -export class ERR_MANIFEST_TDZ extends NodeError { - constructor() { - super( - "ERR_MANIFEST_TDZ", - `Manifest initialization has not yet run`, - ); - } -} -export class ERR_MANIFEST_UNKNOWN_ONERROR extends NodeSyntaxError { - constructor(x: string) { - super( - "ERR_MANIFEST_UNKNOWN_ONERROR", - `Manifest specified unknown error behavior "${x}".`, - ); - } -} -export class ERR_METHOD_NOT_IMPLEMENTED extends NodeError { - constructor(x: string) { - super( - "ERR_METHOD_NOT_IMPLEMENTED", - `The ${x} method is not implemented`, - ); - } -} -export class ERR_MISSING_ARGS extends NodeTypeError { - constructor(...args: string[]) { - args = args.map((a) => `"${a}"`); - - let msg = "The "; - switch (args.length) { - case 1: - msg += `${args[0]} argument`; - break; - case 2: - msg += `${args[0]} and ${args[1]} arguments`; - break; - default: - msg += args.slice(0, args.length - 1).join(", "); - msg += `, and ${args[args.length - 1]} arguments`; - break; - } - super( - "ERR_MISSING_ARGS", - `${msg} must be specified`, - ); - } -} -export class ERR_MISSING_OPTION extends NodeTypeError { - constructor(x: string) { - super( - "ERR_MISSING_OPTION", - `${x} is required`, - ); - } -} -export class ERR_MULTIPLE_CALLBACK extends NodeError { - constructor() { - super( - "ERR_MULTIPLE_CALLBACK", - `Callback called multiple times`, - ); - } -} -export class ERR_NAPI_CONS_FUNCTION extends NodeTypeError { - constructor() { - super( - "ERR_NAPI_CONS_FUNCTION", - `Constructor must be a function`, - ); - } -} -export class ERR_NAPI_INVALID_DATAVIEW_ARGS extends NodeRangeError { - constructor() { - super( - "ERR_NAPI_INVALID_DATAVIEW_ARGS", - `byte_offset + byte_length should be less than or equal to the size in bytes of the array passed in`, - ); - } -} -export class ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT extends NodeRangeError { - constructor(x: string, y: string) { - super( - "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", - `start offset of ${x} should be a multiple of ${y}`, - ); - } -} -export class ERR_NAPI_INVALID_TYPEDARRAY_LENGTH extends NodeRangeError { - constructor() { - super( - "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", - `Invalid typed array length`, - ); - } -} -export class ERR_NO_CRYPTO extends NodeError { - constructor() { - super( - "ERR_NO_CRYPTO", - `Node.js is not compiled with OpenSSL crypto support`, - ); - } -} -export class ERR_NO_ICU extends NodeTypeError { - constructor(x: string) { - super( - "ERR_NO_ICU", - `${x} is not supported on Node.js compiled without ICU`, - ); - } -} -export class ERR_QUICCLIENTSESSION_FAILED extends NodeError { - constructor(x: string) { - super( - "ERR_QUICCLIENTSESSION_FAILED", - `Failed to create a new QuicClientSession: ${x}`, - ); - } -} -export class ERR_QUICCLIENTSESSION_FAILED_SETSOCKET extends NodeError { - constructor() { - super( - "ERR_QUICCLIENTSESSION_FAILED_SETSOCKET", - `Failed to set the QuicSocket`, - ); - } -} -export class ERR_QUICSESSION_DESTROYED extends NodeError { - constructor(x: string) { - super( - "ERR_QUICSESSION_DESTROYED", - `Cannot call ${x} after a QuicSession has been destroyed`, - ); - } -} -export class ERR_QUICSESSION_INVALID_DCID extends NodeError { - constructor(x: string) { - super( - "ERR_QUICSESSION_INVALID_DCID", - `Invalid DCID value: ${x}`, - ); - } -} -export class ERR_QUICSESSION_UPDATEKEY extends NodeError { - constructor() { - super( - "ERR_QUICSESSION_UPDATEKEY", - `Unable to update QuicSession keys`, - ); - } -} -export class ERR_QUICSOCKET_DESTROYED extends NodeError { - constructor(x: string) { - super( - "ERR_QUICSOCKET_DESTROYED", - `Cannot call ${x} after a QuicSocket has been destroyed`, - ); - } -} -export class ERR_QUICSOCKET_INVALID_STATELESS_RESET_SECRET_LENGTH - extends NodeError { - constructor() { - super( - "ERR_QUICSOCKET_INVALID_STATELESS_RESET_SECRET_LENGTH", - `The stateResetToken must be exactly 16-bytes in length`, - ); - } -} -export class ERR_QUICSOCKET_LISTENING extends NodeError { - constructor() { - super( - "ERR_QUICSOCKET_LISTENING", - `This QuicSocket is already listening`, - ); - } -} -export class ERR_QUICSOCKET_UNBOUND extends NodeError { - constructor(x: string) { - super( - "ERR_QUICSOCKET_UNBOUND", - `Cannot call ${x} before a QuicSocket has been bound`, - ); - } -} -export class ERR_QUICSTREAM_DESTROYED extends NodeError { - constructor(x: string) { - super( - "ERR_QUICSTREAM_DESTROYED", - `Cannot call ${x} after a QuicStream has been destroyed`, - ); - } -} -export class ERR_QUICSTREAM_INVALID_PUSH extends NodeError { - constructor() { - super( - "ERR_QUICSTREAM_INVALID_PUSH", - `Push streams are only supported on client-initiated, bidirectional streams`, - ); - } -} -export class ERR_QUICSTREAM_OPEN_FAILED extends NodeError { - constructor() { - super( - "ERR_QUICSTREAM_OPEN_FAILED", - `Opening a new QuicStream failed`, - ); - } -} -export class ERR_QUICSTREAM_UNSUPPORTED_PUSH extends NodeError { - constructor() { - super( - "ERR_QUICSTREAM_UNSUPPORTED_PUSH", - `Push streams are not supported on this QuicSession`, - ); - } -} -export class ERR_QUIC_TLS13_REQUIRED extends NodeError { - constructor() { - super( - "ERR_QUIC_TLS13_REQUIRED", - `QUIC requires TLS version 1.3`, - ); - } -} -export class ERR_SCRIPT_EXECUTION_INTERRUPTED extends NodeError { - constructor() { - super( - "ERR_SCRIPT_EXECUTION_INTERRUPTED", - "Script execution was interrupted by `SIGINT`", - ); - } -} -export class ERR_SERVER_ALREADY_LISTEN extends NodeError { - constructor() { - super( - "ERR_SERVER_ALREADY_LISTEN", - `Listen method has been called more than once without closing.`, - ); - } -} -export class ERR_SERVER_NOT_RUNNING extends NodeError { - constructor() { - super( - "ERR_SERVER_NOT_RUNNING", - `Server is not running.`, - ); - } -} -export class ERR_SOCKET_ALREADY_BOUND extends NodeError { - constructor() { - super( - "ERR_SOCKET_ALREADY_BOUND", - `Socket is already bound`, - ); - } -} -export class ERR_SOCKET_BAD_BUFFER_SIZE extends NodeTypeError { - constructor() { - super( - "ERR_SOCKET_BAD_BUFFER_SIZE", - `Buffer size must be a positive integer`, - ); - } -} -export class ERR_SOCKET_BAD_TYPE extends NodeTypeError { - constructor() { - super( - "ERR_SOCKET_BAD_TYPE", - `Bad socket type specified. Valid types are: udp4, udp6`, - ); - } -} -export class ERR_SOCKET_CLOSED extends NodeError { - constructor() { - super( - "ERR_SOCKET_CLOSED", - `Socket is closed`, - ); - } -} -export class ERR_SOCKET_DGRAM_IS_CONNECTED extends NodeError { - constructor() { - super( - "ERR_SOCKET_DGRAM_IS_CONNECTED", - `Already connected`, - ); - } -} -export class ERR_SOCKET_DGRAM_NOT_CONNECTED extends NodeError { - constructor() { - super( - "ERR_SOCKET_DGRAM_NOT_CONNECTED", - `Not connected`, - ); - } -} -export class ERR_SOCKET_DGRAM_NOT_RUNNING extends NodeError { - constructor() { - super( - "ERR_SOCKET_DGRAM_NOT_RUNNING", - `Not running`, - ); - } -} -export class ERR_SRI_PARSE extends NodeSyntaxError { - constructor(name: string, char: string, position: number) { - super( - "ERR_SRI_PARSE", - `Subresource Integrity string ${name} had an unexpected ${char} at position ${position}`, - ); - } -} -export class ERR_STREAM_ALREADY_FINISHED extends NodeError { - constructor(x: string) { - super( - "ERR_STREAM_ALREADY_FINISHED", - `Cannot call ${x} after a stream was finished`, - ); - } -} -export class ERR_STREAM_CANNOT_PIPE extends NodeError { - constructor() { - super( - "ERR_STREAM_CANNOT_PIPE", - `Cannot pipe, not readable`, - ); - } -} -export class ERR_STREAM_DESTROYED extends NodeError { - constructor(x: string) { - super( - "ERR_STREAM_DESTROYED", - `Cannot call ${x} after a stream was destroyed`, - ); - } -} -export class ERR_STREAM_NULL_VALUES extends NodeTypeError { - constructor() { - super( - "ERR_STREAM_NULL_VALUES", - `May not write null values to stream`, - ); - } -} -export class ERR_STREAM_PREMATURE_CLOSE extends NodeError { - constructor() { - super( - "ERR_STREAM_PREMATURE_CLOSE", - `Premature close`, - ); - } -} -export class ERR_STREAM_PUSH_AFTER_EOF extends NodeError { - constructor() { - 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`, - ); - } -} -export class ERR_STREAM_WRAP extends NodeError { - constructor() { - super( - "ERR_STREAM_WRAP", - `Stream has StringDecoder set or is in objectMode`, - ); - } -} -export class ERR_STREAM_WRITE_AFTER_END extends NodeError { - constructor() { - super( - "ERR_STREAM_WRITE_AFTER_END", - `write after end`, - ); - } -} -export class ERR_SYNTHETIC extends NodeError { - constructor() { - super( - "ERR_SYNTHETIC", - `JavaScript Callstack`, - ); - } -} -export class ERR_TLS_DH_PARAM_SIZE extends NodeError { - constructor(x: string) { - super( - "ERR_TLS_DH_PARAM_SIZE", - `DH parameter size ${x} is less than 2048`, - ); - } -} -export class ERR_TLS_HANDSHAKE_TIMEOUT extends NodeError { - constructor() { - super( - "ERR_TLS_HANDSHAKE_TIMEOUT", - `TLS handshake timeout`, - ); - } -} -export class ERR_TLS_INVALID_CONTEXT extends NodeTypeError { - constructor(x: string) { - super( - "ERR_TLS_INVALID_CONTEXT", - `${x} must be a SecureContext`, - ); - } -} -export class ERR_TLS_INVALID_STATE extends NodeError { - constructor() { - super( - "ERR_TLS_INVALID_STATE", - `TLS socket connection must be securely established`, - ); - } -} -export class ERR_TLS_INVALID_PROTOCOL_VERSION extends NodeTypeError { - constructor(protocol: string, x: string) { - super( - "ERR_TLS_INVALID_PROTOCOL_VERSION", - `${protocol} is not a valid ${x} TLS protocol version`, - ); - } -} -export class ERR_TLS_PROTOCOL_VERSION_CONFLICT extends NodeTypeError { - constructor(prevProtocol: string, protocol: string) { - super( - "ERR_TLS_PROTOCOL_VERSION_CONFLICT", - `TLS protocol version ${prevProtocol} conflicts with secureProtocol ${protocol}`, - ); - } -} -export class ERR_TLS_RENEGOTIATION_DISABLED extends NodeError { - constructor() { - super( - "ERR_TLS_RENEGOTIATION_DISABLED", - `TLS session renegotiation disabled for this socket`, - ); - } -} -export class ERR_TLS_REQUIRED_SERVER_NAME extends NodeError { - constructor() { - super( - "ERR_TLS_REQUIRED_SERVER_NAME", - `"servername" is required parameter for Server.addContext`, - ); - } -} -export class ERR_TLS_SESSION_ATTACK extends NodeError { - constructor() { - super( - "ERR_TLS_SESSION_ATTACK", - `TLS session renegotiation attack detected`, - ); - } -} -export class ERR_TLS_SNI_FROM_SERVER extends NodeError { - constructor() { - super( - "ERR_TLS_SNI_FROM_SERVER", - `Cannot issue SNI from a TLS server-side socket`, - ); - } -} -export class ERR_TRACE_EVENTS_CATEGORY_REQUIRED extends NodeTypeError { - constructor() { - super( - "ERR_TRACE_EVENTS_CATEGORY_REQUIRED", - `At least one category is required`, - ); - } -} -export class ERR_TRACE_EVENTS_UNAVAILABLE extends NodeError { - constructor() { - super( - "ERR_TRACE_EVENTS_UNAVAILABLE", - `Trace events are unavailable`, - ); - } -} -export class ERR_UNAVAILABLE_DURING_EXIT extends NodeError { - constructor() { - super( - "ERR_UNAVAILABLE_DURING_EXIT", - `Cannot call function in process exit handler`, - ); - } -} -export class ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET extends NodeError { - constructor() { - super( - "ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET", - "`process.setupUncaughtExceptionCapture()` was called while a capture callback was already active", - ); - } -} -export class ERR_UNESCAPED_CHARACTERS extends NodeTypeError { - constructor(x: string) { - super( - "ERR_UNESCAPED_CHARACTERS", - `${x} contains unescaped characters`, - ); - } -} -export class ERR_UNKNOWN_BUILTIN_MODULE extends NodeError { - constructor(x: string) { - super( - "ERR_UNKNOWN_BUILTIN_MODULE", - `No such built-in module: ${x}`, - ); - } -} -export class ERR_UNKNOWN_CREDENTIAL extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_UNKNOWN_CREDENTIAL", - `${x} identifier does not exist: ${y}`, - ); - } -} -export class ERR_UNKNOWN_ENCODING extends NodeTypeError { - constructor(x: string) { - super( - "ERR_UNKNOWN_ENCODING", - `Unknown encoding: ${x}`, - ); - } -} -export class ERR_UNKNOWN_FILE_EXTENSION extends NodeTypeError { - constructor(x: string, y: string) { - super( - "ERR_UNKNOWN_FILE_EXTENSION", - `Unknown file extension "${x}" for ${y}`, - ); - } -} -export class ERR_UNKNOWN_MODULE_FORMAT extends NodeRangeError { - constructor(x: string) { - super( - "ERR_UNKNOWN_MODULE_FORMAT", - `Unknown module format: ${x}`, - ); - } -} -export class ERR_UNKNOWN_SIGNAL extends NodeTypeError { - constructor(x: string) { - super( - "ERR_UNKNOWN_SIGNAL", - `Unknown signal: ${x}`, - ); - } -} -export class ERR_UNSUPPORTED_DIR_IMPORT extends NodeError { - constructor(x: string, y: string) { - super( - "ERR_UNSUPPORTED_DIR_IMPORT", - `Directory import '${x}' is not supported resolving ES modules, imported from ${y}`, - ); - } -} -export class ERR_UNSUPPORTED_ESM_URL_SCHEME extends NodeError { - constructor() { - super( - "ERR_UNSUPPORTED_ESM_URL_SCHEME", - `Only file and data URLs are supported by the default ESM loader`, - ); - } -} -export class ERR_V8BREAKITERATOR extends NodeError { - constructor() { - super( - "ERR_V8BREAKITERATOR", - `Full ICU data not installed. See https://github.com/nodejs/node/wiki/Intl`, - ); - } -} -export class ERR_VALID_PERFORMANCE_ENTRY_TYPE extends NodeError { - constructor() { - super( - "ERR_VALID_PERFORMANCE_ENTRY_TYPE", - `At least one valid performance entry type is required`, - ); - } -} -export class ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING extends NodeTypeError { - constructor() { - super( - "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING", - `A dynamic import callback was not specified.`, - ); - } -} -export class ERR_VM_MODULE_ALREADY_LINKED extends NodeError { - constructor() { - super( - "ERR_VM_MODULE_ALREADY_LINKED", - `Module has already been linked`, - ); - } -} -export class ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA extends NodeError { - constructor() { - super( - "ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA", - `Cached data cannot be created for a module which has been evaluated`, - ); - } -} -export class ERR_VM_MODULE_DIFFERENT_CONTEXT extends NodeError { - constructor() { - super( - "ERR_VM_MODULE_DIFFERENT_CONTEXT", - `Linked modules must use the same context`, - ); - } -} -export class ERR_VM_MODULE_LINKING_ERRORED extends NodeError { - constructor() { - super( - "ERR_VM_MODULE_LINKING_ERRORED", - `Linking has already failed for the provided module`, - ); - } -} -export class ERR_VM_MODULE_NOT_MODULE extends NodeError { - constructor() { - super( - "ERR_VM_MODULE_NOT_MODULE", - `Provided module is not an instance of Module`, - ); - } -} -export class ERR_VM_MODULE_STATUS extends NodeError { - constructor(x: string) { - super( - "ERR_VM_MODULE_STATUS", - `Module status ${x}`, - ); - } -} -export class ERR_WASI_ALREADY_STARTED extends NodeError { - constructor() { - super( - "ERR_WASI_ALREADY_STARTED", - `WASI instance has already started`, - ); - } -} -export class ERR_WORKER_INIT_FAILED extends NodeError { - constructor(x: string) { - super( - "ERR_WORKER_INIT_FAILED", - `Worker initialization failure: ${x}`, - ); - } -} -export class ERR_WORKER_NOT_RUNNING extends NodeError { - constructor() { - super( - "ERR_WORKER_NOT_RUNNING", - `Worker instance not running`, - ); - } -} -export class ERR_WORKER_OUT_OF_MEMORY extends NodeError { - constructor(x: string) { - super( - "ERR_WORKER_OUT_OF_MEMORY", - `Worker terminated due to reaching memory limit: ${x}`, - ); - } -} -export class ERR_WORKER_UNSERIALIZABLE_ERROR extends NodeError { - constructor() { - super( - "ERR_WORKER_UNSERIALIZABLE_ERROR", - `Serializing an uncaught exception failed`, - ); - } -} -export class ERR_WORKER_UNSUPPORTED_EXTENSION extends NodeTypeError { - constructor(x: string) { - super( - "ERR_WORKER_UNSUPPORTED_EXTENSION", - `The worker script extension must be ".js", ".mjs", or ".cjs". Received "${x}"`, - ); - } -} -export class ERR_WORKER_UNSUPPORTED_OPERATION extends NodeTypeError { - constructor(x: string) { - super( - "ERR_WORKER_UNSUPPORTED_OPERATION", - `${x} is not supported in workers`, - ); - } -} -export class ERR_ZLIB_INITIALIZATION_FAILED extends NodeError { - constructor() { - super( - "ERR_ZLIB_INITIALIZATION_FAILED", - `Initialization failed`, - ); - } -} -export class ERR_FALSY_VALUE_REJECTION extends NodeError { - reason: string; - constructor(reason: string) { - super( - "ERR_FALSY_VALUE_REJECTION", - "Promise was rejected with falsy value", - ); - this.reason = reason; - } -} -export class ERR_HTTP2_INVALID_SETTING_VALUE extends NodeRangeError { - actual: unknown; - min?: number; - max?: number; - - constructor(name: string, actual: unknown, min?: number, max?: number) { - super( - "ERR_HTTP2_INVALID_SETTING_VALUE", - `Invalid value for setting "${name}": ${actual}`, - ); - this.actual = actual; - if (min !== undefined) { - this.min = min; - this.max = max; - } - } -} -export class ERR_HTTP2_STREAM_CANCEL extends NodeError { - cause?: Error; - constructor(error: Error) { - super( - "ERR_HTTP2_STREAM_CANCEL", - typeof error.message === "string" - ? `The pending stream has been canceled (caused by: ${error.message})` - : "The pending stream has been canceled", - ); - if (error) { - this.cause = error; - } - } -} - -export class ERR_INVALID_ADDRESS_FAMILY extends NodeRangeError { - host: string; - port: number; - constructor(addressType: string, host: string, port: number) { - super( - "ERR_INVALID_ADDRESS_FAMILY", - `Invalid address family: ${addressType} ${host}:${port}`, - ); - this.host = host; - this.port = port; - } -} - -export class ERR_INVALID_CHAR extends NodeTypeError { - constructor(name: string, field?: string) { - super( - "ERR_INVALID_CHAR", - field - ? `Invalid character in ${name}` - : `Invalid character in ${name} ["${field}"]`, - ); - } -} - -export class ERR_INVALID_OPT_VALUE extends NodeTypeError { - constructor(name: string, value: unknown) { - super( - "ERR_INVALID_OPT_VALUE", - `The value "${value}" is invalid for option "${name}"`, - ); - } -} - -export class ERR_INVALID_RETURN_PROPERTY extends NodeTypeError { - constructor(input: string, name: string, prop: string, value: string) { - super( - "ERR_INVALID_RETURN_PROPERTY", - `Expected a valid ${input} to be returned for the "${prop}" from the "${name}" function but got ${value}.`, - ); - } -} - -// deno-lint-ignore no-explicit-any -function buildReturnPropertyType(value: any) { - if (value && value.constructor && value.constructor.name) { - return `instance of ${value.constructor.name}`; - } else { - return `type ${typeof value}`; - } -} - -export class ERR_INVALID_RETURN_PROPERTY_VALUE extends NodeTypeError { - constructor(input: string, name: string, prop: string, value: unknown) { - super( - "ERR_INVALID_RETURN_PROPERTY_VALUE", - `Expected ${input} to be returned for the "${prop}" from the "${name}" function but got ${ - buildReturnPropertyType(value) - }.`, - ); - } -} - -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 ${ - buildReturnPropertyType(value) - }.`, - ); - } -} - -export class ERR_INVALID_URL extends NodeTypeError { - input: string; - constructor(input: string) { - super( - "ERR_INVALID_URL", - `Invalid URL: ${input}`, - ); - this.input = input; - } -} diff --git a/std/node/_fs/_fs_access.ts b/std/node/_fs/_fs_access.ts deleted file mode 100644 index 3211e1640..000000000 --- a/std/node/_fs/_fs_access.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { notImplemented } from "../_utils.ts"; - -/** Revist once https://github.com/denoland/deno/issues/4017 lands */ - -// TODO(bartlomieju) 'path' can also be a Buffer. Neither of these polyfills -//is available yet. See https://github.com/denoland/deno/issues/3403 -export function access( - _path: string | URL, - _modeOrCallback: number | ((...args: unknown[]) => void), - _callback?: CallbackWithError, -): void { - notImplemented("Not yet available"); -} - -// TODO(bartlomieju) 'path' can also be a Buffer. Neither of these polyfills -// is available yet. See https://github.com/denoland/deno/issues/3403 -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export function accessSync(path: string | URL, mode?: number): void { - notImplemented("Not yet available"); -} diff --git a/std/node/_fs/_fs_appendFile.ts b/std/node/_fs/_fs_appendFile.ts deleted file mode 100644 index ee01b9cc8..000000000 --- a/std/node/_fs/_fs_appendFile.ts +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - CallbackWithError, - getOpenOptions, - isFileOptions, - WriteFileOptions, -} from "./_fs_common.ts"; -import { Encodings, notImplemented } from "../_utils.ts"; -import { fromFileUrl } from "../path.ts"; - -/** - * TODO: Also accept 'data' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function appendFile( - pathOrRid: string | number | URL, - data: string | Uint8Array, - optionsOrCallback: Encodings | WriteFileOptions | CallbackWithError, - callback?: CallbackWithError, -): void { - pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; - const callbackFn: CallbackWithError | undefined = - optionsOrCallback instanceof Function ? optionsOrCallback : callback; - const options: Encodings | WriteFileOptions | undefined = - optionsOrCallback instanceof Function ? undefined : optionsOrCallback; - if (!callbackFn) { - throw new Error("No callback function supplied"); - } - - validateEncoding(options); - let rid = -1; - const buffer: Uint8Array = data instanceof Uint8Array - ? data - : new TextEncoder().encode(data); - new Promise((resolve, reject) => { - if (typeof pathOrRid === "number") { - rid = pathOrRid; - Deno.write(rid, buffer).then(resolve, reject); - } else { - const mode: number | undefined = isFileOptions(options) - ? options.mode - : undefined; - const flag: string | undefined = isFileOptions(options) - ? options.flag - : undefined; - - if (mode) { - // TODO(bartlomieju) rework once https://github.com/denoland/deno/issues/4017 completes - notImplemented("Deno does not yet support setting mode on create"); - } - Deno.open(pathOrRid as string, getOpenOptions(flag)) - .then(({ rid: openedFileRid }) => { - rid = openedFileRid; - return Deno.write(openedFileRid, buffer); - }) - .then(resolve, reject); - } - }) - .then(() => { - closeRidIfNecessary(typeof pathOrRid === "string", rid); - callbackFn(null); - }, (err) => { - closeRidIfNecessary(typeof pathOrRid === "string", rid); - callbackFn(err); - }); -} - -function closeRidIfNecessary(isPathString: boolean, rid: number): void { - if (isPathString && rid != -1) { - //Only close if a path was supplied and a rid allocated - Deno.close(rid); - } -} - -/** - * TODO: Also accept 'data' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function appendFileSync( - pathOrRid: string | number | URL, - data: string | Uint8Array, - options?: Encodings | WriteFileOptions, -): void { - let rid = -1; - - validateEncoding(options); - pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; - - try { - if (typeof pathOrRid === "number") { - rid = pathOrRid; - } else { - const mode: number | undefined = isFileOptions(options) - ? options.mode - : undefined; - const flag: string | undefined = isFileOptions(options) - ? options.flag - : undefined; - - if (mode) { - // TODO(bartlomieju) rework once https://github.com/denoland/deno/issues/4017 completes - notImplemented("Deno does not yet support setting mode on create"); - } - - const file = Deno.openSync(pathOrRid, getOpenOptions(flag)); - rid = file.rid; - } - - const buffer: Uint8Array = data instanceof Uint8Array - ? data - : new TextEncoder().encode(data); - - Deno.writeSync(rid, buffer); - } finally { - closeRidIfNecessary(typeof pathOrRid === "string", rid); - } -} - -function validateEncoding( - encodingOption: Encodings | WriteFileOptions | undefined, -): void { - if (!encodingOption) return; - - if (typeof encodingOption === "string") { - if (encodingOption !== "utf8") { - throw new Error("Only 'utf8' encoding is currently supported"); - } - } else if (encodingOption.encoding && encodingOption.encoding !== "utf8") { - throw new Error("Only 'utf8' encoding is currently supported"); - } -} diff --git a/std/node/_fs/_fs_appendFile_test.ts b/std/node/_fs/_fs_appendFile_test.ts deleted file mode 100644 index 6a77974fd..000000000 --- a/std/node/_fs/_fs_appendFile_test.ts +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals, assertThrows, fail } from "../../testing/asserts.ts"; -import { appendFile, appendFileSync } from "./_fs_appendFile.ts"; -import { fromFileUrl } from "../path.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; - -const decoder = new TextDecoder("utf-8"); - -Deno.test({ - name: "No callback Fn results in Error", - fn() { - assertThrows( - () => { - appendFile("some/path", "some data", "utf8"); - }, - Error, - "No callback function supplied", - ); - }, -}); - -Deno.test({ - name: "Unsupported encoding results in error()", - fn() { - assertThrows( - () => { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - appendFile("some/path", "some data", "made-up-encoding", () => {}); - }, - Error, - "Only 'utf8' encoding is currently supported", - ); - assertThrows( - () => { - appendFile( - "some/path", - "some data", - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - { encoding: "made-up-encoding" }, - () => {}, - ); - }, - Error, - "Only 'utf8' encoding is currently supported", - ); - assertThrows( - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - () => appendFileSync("some/path", "some data", "made-up-encoding"), - Error, - "Only 'utf8' encoding is currently supported", - ); - assertThrows( - () => - appendFileSync("some/path", "some data", { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - encoding: "made-up-encoding", - }), - Error, - "Only 'utf8' encoding is currently supported", - ); - }, -}); - -Deno.test({ - name: "Async: Data is written to passed in rid", - async fn() { - const tempFile: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(tempFile, { - create: true, - write: true, - read: true, - }); - await new Promise<void>((resolve, reject) => { - appendFile(file.rid, "hello world", (err) => { - if (err) reject(); - else resolve(); - }); - }) - .then(async () => { - const data = await Deno.readFile(tempFile); - assertEquals(decoder.decode(data), "hello world"); - }, () => { - fail("No error expected"); - }) - .finally(async () => { - Deno.close(file.rid); - await Deno.remove(tempFile); - }); - }, -}); - -Deno.test({ - name: "Async: Data is written to passed in file path", - async fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - await new Promise<void>((resolve, reject) => { - appendFile("_fs_appendFile_test_file.txt", "hello world", (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(async () => { - assertEquals(Deno.resources(), openResourcesBeforeAppend); - const data = await Deno.readFile("_fs_appendFile_test_file.txt"); - assertEquals(decoder.decode(data), "hello world"); - }, (err) => { - fail("No error was expected: " + err); - }) - .finally(async () => { - await Deno.remove("_fs_appendFile_test_file.txt"); - }); - }, -}); - -Deno.test({ - name: "Async: Data is written to passed in URL", - async fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - const fileURL = new URL("_fs_appendFile_test_file.txt", import.meta.url); - await new Promise<void>((resolve, reject) => { - appendFile(fileURL, "hello world", (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(async () => { - assertEquals(Deno.resources(), openResourcesBeforeAppend); - const data = await Deno.readFile(fromFileUrl(fileURL)); - assertEquals(decoder.decode(data), "hello world"); - }, (err) => { - fail("No error was expected: " + err); - }) - .finally(async () => { - await Deno.remove(fromFileUrl(fileURL)); - }); - }, -}); - -Deno.test({ - name: - "Async: Callback is made with error if attempting to append data to an existing file with 'ax' flag", - async fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - const tempFile: string = await Deno.makeTempFile(); - await new Promise<void>((resolve, reject) => { - appendFile(tempFile, "hello world", { flag: "ax" }, (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(() => { - fail("Expected error to be thrown"); - }, () => { - assertEquals(Deno.resources(), openResourcesBeforeAppend); - }) - .finally(async () => { - await Deno.remove(tempFile); - }); - }, -}); - -Deno.test({ - name: "Sync: Data is written to passed in rid", - fn() { - const tempFile: string = Deno.makeTempFileSync(); - const file: Deno.File = Deno.openSync(tempFile, { - create: true, - write: true, - read: true, - }); - appendFileSync(file.rid, "hello world"); - Deno.close(file.rid); - const data = Deno.readFileSync(tempFile); - assertEquals(decoder.decode(data), "hello world"); - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "Sync: Data is written to passed in file path", - fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - appendFileSync("_fs_appendFile_test_file_sync.txt", "hello world"); - assertEquals(Deno.resources(), openResourcesBeforeAppend); - const data = Deno.readFileSync("_fs_appendFile_test_file_sync.txt"); - assertEquals(decoder.decode(data), "hello world"); - Deno.removeSync("_fs_appendFile_test_file_sync.txt"); - }, -}); - -Deno.test({ - name: - "Sync: error thrown if attempting to append data to an existing file with 'ax' flag", - fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - const tempFile: string = Deno.makeTempFileSync(); - assertThrows( - () => appendFileSync(tempFile, "hello world", { flag: "ax" }), - Deno.errors.AlreadyExists, - "", - ); - assertEquals(Deno.resources(), openResourcesBeforeAppend); - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "Sync: Data is written in Uint8Array to passed in file path", - fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - const testData = new TextEncoder().encode("hello world"); - appendFileSync("_fs_appendFile_test_file_sync.txt", testData); - assertEquals(Deno.resources(), openResourcesBeforeAppend); - const data = Deno.readFileSync("_fs_appendFile_test_file_sync.txt"); - assertEquals(data, testData); - Deno.removeSync("_fs_appendFile_test_file_sync.txt"); - }, -}); - -Deno.test({ - name: "Async: Data is written in Uint8Array to passed in file path", - async fn() { - const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); - const testData = new TextEncoder().encode("hello world"); - await new Promise<void>((resolve, reject) => { - appendFile("_fs_appendFile_test_file.txt", testData, (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(async () => { - assertEquals(Deno.resources(), openResourcesBeforeAppend); - const data = await Deno.readFile("_fs_appendFile_test_file.txt"); - assertEquals(data, testData); - }, (err) => { - fail("No error was expected: " + err); - }) - .finally(async () => { - await Deno.remove("_fs_appendFile_test_file.txt"); - }); - }, -}); - -Deno.test("[std/node/fs] appendFile callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_appendFile.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { appendFile } from ${JSON.stringify(importUrl)}`, - invocation: `appendFile(${JSON.stringify(tempFile)}, "hello world", `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_chmod.ts b/std/node/_fs/_fs_chmod.ts deleted file mode 100644 index bf4031d2c..000000000 --- a/std/node/_fs/_fs_chmod.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { fromFileUrl } from "../path.ts"; - -const allowedModes = /^[0-7]{3}/; - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function chmod( - path: string | URL, - mode: string | number, - callback: CallbackWithError, -): void { - path = path instanceof URL ? fromFileUrl(path) : path; - - Deno.chmod(path, getResolvedMode(mode)).then(() => callback(null), callback); -} - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function chmodSync(path: string | URL, mode: string | number): void { - path = path instanceof URL ? fromFileUrl(path) : path; - Deno.chmodSync(path, getResolvedMode(mode)); -} - -function getResolvedMode(mode: string | number): number { - if (typeof mode === "number") { - return mode; - } - - if (typeof mode === "string" && !allowedModes.test(mode)) { - throw new Error("Unrecognized mode: " + mode); - } - - return parseInt(mode, 8); -} diff --git a/std/node/_fs/_fs_chmod_test.ts b/std/node/_fs/_fs_chmod_test.ts deleted file mode 100644 index 4d8647782..000000000 --- a/std/node/_fs/_fs_chmod_test.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { chmod, chmodSync } from "./_fs_chmod.ts"; - -Deno.test({ - name: "ASYNC: Permissions are changed (non-Windows)", - ignore: Deno.build.os === "windows", - async fn() { - const tempFile: string = await Deno.makeTempFile(); - const originalFileMode: number | null = (await Deno.lstat(tempFile)).mode; - await new Promise<void>((resolve, reject) => { - chmod(tempFile, 0o777, (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(() => { - const newFileMode: number | null = Deno.lstatSync(tempFile).mode; - assert(newFileMode && originalFileMode); - assert(newFileMode === 33279 && newFileMode > originalFileMode); - }, () => { - fail(); - }) - .finally(() => { - Deno.removeSync(tempFile); - }); - }, -}); - -Deno.test({ - name: "SYNC: Permissions are changed (non-Windows)", - ignore: Deno.build.os === "windows", - fn() { - const tempFile: string = Deno.makeTempFileSync(); - const originalFileMode: number | null = Deno.lstatSync(tempFile).mode; - chmodSync(tempFile, "777"); - - const newFileMode: number | null = Deno.lstatSync(tempFile).mode; - assert(newFileMode && originalFileMode); - assert(newFileMode === 33279 && newFileMode > originalFileMode); - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "[std/node/fs] chmod callback isn't called twice if error is thrown", - ignore: Deno.build.os === "windows", - async fn() { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_chmod.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { chmod } from ${JSON.stringify(importUrl)}`, - invocation: `chmod(${JSON.stringify(tempFile)}, 0o777, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); - }, -}); diff --git a/std/node/_fs/_fs_chown.ts b/std/node/_fs/_fs_chown.ts deleted file mode 100644 index f9e7326ce..000000000 --- a/std/node/_fs/_fs_chown.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { fromFileUrl } from "../path.ts"; - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function chown( - path: string | URL, - uid: number, - gid: number, - callback: CallbackWithError, -): void { - path = path instanceof URL ? fromFileUrl(path) : path; - - Deno.chown(path, uid, gid).then(() => callback(null), callback); -} - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function chownSync(path: string | URL, uid: number, gid: number): void { - path = path instanceof URL ? fromFileUrl(path) : path; - - Deno.chownSync(path, uid, gid); -} diff --git a/std/node/_fs/_fs_chown_test.ts b/std/node/_fs/_fs_chown_test.ts deleted file mode 100644 index 8d74f657a..000000000 --- a/std/node/_fs/_fs_chown_test.ts +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { chown, chownSync } from "./_fs_chown.ts"; - -// chown is difficult to test. Best we can do is set the existing user id/group -// id again -const ignore = Deno.build.os == "windows"; - -Deno.test({ - ignore, - name: "ASYNC: setting existing uid/gid works as expected (non-Windows)", - async fn() { - const tempFile: string = await Deno.makeTempFile(); - const originalUserId: number | null = (await Deno.lstat(tempFile)).uid; - const originalGroupId: number | null = (await Deno.lstat(tempFile)).gid; - await new Promise<void>((resolve, reject) => { - chown(tempFile, originalUserId!, originalGroupId!, (err) => { - if (err) reject(err); - else resolve(); - }); - }) - .then(() => { - const newUserId: number | null = Deno.lstatSync(tempFile).uid; - const newGroupId: number | null = Deno.lstatSync(tempFile).gid; - assertEquals(newUserId, originalUserId); - assertEquals(newGroupId, originalGroupId); - }, () => { - fail(); - }) - .finally(() => { - Deno.removeSync(tempFile); - }); - }, -}); - -Deno.test({ - ignore, - name: "SYNC: setting existing uid/gid works as expected (non-Windows)", - fn() { - const tempFile: string = Deno.makeTempFileSync(); - const originalUserId: number | null = Deno.lstatSync(tempFile).uid; - const originalGroupId: number | null = Deno.lstatSync(tempFile).gid; - chownSync(tempFile, originalUserId!, originalGroupId!); - - const newUserId: number | null = Deno.lstatSync(tempFile).uid; - const newGroupId: number | null = Deno.lstatSync(tempFile).gid; - assertEquals(newUserId, originalUserId); - assertEquals(newGroupId, originalGroupId); - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "[std/node/fs] chown callback isn't called twice if error is thrown", - ignore: Deno.build.os === "windows", - async fn() { - const tempFile = await Deno.makeTempFile(); - const { uid, gid } = await Deno.lstat(tempFile); - const importUrl = new URL("./_fs_chown.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { chown } from ${JSON.stringify(importUrl)}`, - invocation: `chown(${JSON.stringify(tempFile)}, ${uid}, ${gid}, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); - }, -}); diff --git a/std/node/_fs/_fs_close.ts b/std/node/_fs/_fs_close.ts deleted file mode 100644 index 721827421..000000000 --- a/std/node/_fs/_fs_close.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; - -export function close(fd: number, callback: CallbackWithError): void { - setTimeout(() => { - let error = null; - try { - Deno.close(fd); - } catch (err) { - error = err; - } - callback(error); - }, 0); -} - -export function closeSync(fd: number): void { - Deno.close(fd); -} diff --git a/std/node/_fs/_fs_close_test.ts b/std/node/_fs/_fs_close_test.ts deleted file mode 100644 index df5a93240..000000000 --- a/std/node/_fs/_fs_close_test.ts +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, assertThrows, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { close, closeSync } from "./_fs_close.ts"; - -Deno.test({ - name: "ASYNC: File is closed", - async fn() { - const tempFile: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(tempFile); - - assert(Deno.resources()[file.rid]); - await new Promise<void>((resolve, reject) => { - close(file.rid, (err) => { - if (err !== null) reject(); - else resolve(); - }); - }) - .then(() => { - assert(!Deno.resources()[file.rid]); - }, () => { - fail("No error expected"); - }) - .finally(async () => { - await Deno.remove(tempFile); - }); - }, -}); - -Deno.test({ - name: "ASYNC: Invalid fd", - async fn() { - await new Promise<void>((resolve, reject) => { - close(-1, (err) => { - if (err !== null) return resolve(); - reject(); - }); - }); - }, -}); - -Deno.test({ - name: "close callback should be asynchronous", - async fn() { - const tempFile: string = Deno.makeTempFileSync(); - const file: Deno.File = Deno.openSync(tempFile); - - let foo: string; - const promise = new Promise<void>((resolve) => { - close(file.rid, () => { - assert(foo === "bar"); - resolve(); - }); - foo = "bar"; - }); - - await promise; - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "SYNC: File is closed", - fn() { - const tempFile: string = Deno.makeTempFileSync(); - const file: Deno.File = Deno.openSync(tempFile); - - assert(Deno.resources()[file.rid]); - closeSync(file.rid); - assert(!Deno.resources()[file.rid]); - Deno.removeSync(tempFile); - }, -}); - -Deno.test({ - name: "SYNC: Invalid fd", - fn() { - assertThrows(() => closeSync(-1)); - }, -}); - -Deno.test("[std/node/fs] close callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_close.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: ` - import { close } from ${JSON.stringify(importUrl)}; - - const file = await Deno.open(${JSON.stringify(tempFile)}); - `, - invocation: "close(file.rid, ", - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_common.ts b/std/node/_fs/_fs_common.ts deleted file mode 100644 index c233b2d76..000000000 --- a/std/node/_fs/_fs_common.ts +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - BinaryEncodings, - Encodings, - notImplemented, - TextEncodings, -} from "../_utils.ts"; - -export type CallbackWithError = (err: Error | null) => void; - -export interface FileOptions { - encoding?: Encodings; - flag?: string; -} - -export type TextOptionsArgument = - | TextEncodings - | ({ encoding: TextEncodings } & FileOptions); -export type BinaryOptionsArgument = - | BinaryEncodings - | ({ encoding: BinaryEncodings } & FileOptions); -export type FileOptionsArgument = Encodings | FileOptions; - -export interface WriteFileOptions extends FileOptions { - mode?: number; -} - -export function isFileOptions( - fileOptions: string | WriteFileOptions | undefined, -): fileOptions is FileOptions { - if (!fileOptions) return false; - - return ( - (fileOptions as FileOptions).encoding != undefined || - (fileOptions as FileOptions).flag != undefined || - (fileOptions as WriteFileOptions).mode != undefined - ); -} - -export function getEncoding( - optOrCallback?: - | FileOptions - | WriteFileOptions - // deno-lint-ignore no-explicit-any - | ((...args: any[]) => any) - | Encodings - | null, -): Encodings | null { - if (!optOrCallback || typeof optOrCallback === "function") { - return null; - } - - const encoding = typeof optOrCallback === "string" - ? optOrCallback - : optOrCallback.encoding; - if (!encoding) return null; - return encoding; -} - -export function checkEncoding(encoding: Encodings | null): Encodings | null { - if (!encoding) return null; - - encoding = encoding.toLowerCase() as Encodings; - if (["utf8", "hex", "base64"].includes(encoding)) return encoding; - - if (encoding === "utf-8") { - return "utf8"; - } - if (encoding === "binary") { - return "binary"; - // before this was buffer, however buffer is not used in Node - // node -e "require('fs').readFile('../world.txt', 'buffer', console.log)" - } - - const notImplementedEncodings = ["utf16le", "latin1", "ascii", "ucs2"]; - - if (notImplementedEncodings.includes(encoding as string)) { - notImplemented(`"${encoding}" encoding`); - } - - throw new Error(`The value "${encoding}" is invalid for option "encoding"`); -} - -export function getOpenOptions(flag: string | undefined): Deno.OpenOptions { - if (!flag) { - return { create: true, append: true }; - } - - let openOptions: Deno.OpenOptions; - switch (flag) { - case "a": { - // 'a': Open file for appending. The file is created if it does not exist. - openOptions = { create: true, append: true }; - break; - } - case "ax": { - // 'ax': Like 'a' but fails if the path exists. - openOptions = { createNew: true, write: true, append: true }; - break; - } - case "a+": { - // 'a+': Open file for reading and appending. The file is created if it does not exist. - openOptions = { read: true, create: true, append: true }; - break; - } - case "ax+": { - // 'ax+': Like 'a+' but fails if the path exists. - openOptions = { read: true, createNew: true, append: true }; - break; - } - case "r": { - // 'r': Open file for reading. An exception occurs if the file does not exist. - openOptions = { read: true }; - break; - } - case "r+": { - // 'r+': Open file for reading and writing. An exception occurs if the file does not exist. - openOptions = { read: true, write: true }; - break; - } - case "w": { - // 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists). - openOptions = { create: true, write: true, truncate: true }; - break; - } - case "wx": { - // 'wx': Like 'w' but fails if the path exists. - openOptions = { createNew: true, write: true }; - break; - } - case "w+": { - // 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists). - openOptions = { create: true, write: true, truncate: true, read: true }; - break; - } - case "wx+": { - // 'wx+': Like 'w+' but fails if the path exists. - openOptions = { createNew: true, write: true, read: true }; - break; - } - case "as": { - // 'as': Open file for appending in synchronous mode. The file is created if it does not exist. - openOptions = { create: true, append: true }; - break; - } - case "as+": { - // 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist. - openOptions = { create: true, read: true, append: true }; - break; - } - case "rs+": { - // 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache. - openOptions = { create: true, read: true, write: true }; - break; - } - default: { - throw new Error(`Unrecognized file system flag: ${flag}`); - } - } - - return openOptions; -} diff --git a/std/node/_fs/_fs_constants.ts b/std/node/_fs/_fs_constants.ts deleted file mode 100644 index 7f740276b..000000000 --- a/std/node/_fs/_fs_constants.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -//File access constants -export const F_OK = 0; -export const R_OK = 4; -export const W_OK = 2; -export const X_OK = 1; - -//File mode constants -export const S_IRUSR = 0o400; //read by owner -export const S_IWUSR = 0o200; //write by owner -export const S_IXUSR = 0o100; //execute/search by owner -export const S_IRGRP = 0o40; //read by group -export const S_IWGRP = 0o20; //write by group -export const S_IXGRP = 0o10; //execute/search by group -export const S_IROTH = 0o4; //read by others -export const S_IWOTH = 0o2; //write by others -export const S_IXOTH = 0o1; //execute/search by others diff --git a/std/node/_fs/_fs_copy.ts b/std/node/_fs/_fs_copy.ts deleted file mode 100644 index 3242b97b3..000000000 --- a/std/node/_fs/_fs_copy.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { fromFileUrl } from "../path.ts"; - -export function copyFile( - source: string | URL, - destination: string, - callback: CallbackWithError, -): void { - source = source instanceof URL ? fromFileUrl(source) : source; - - Deno.copyFile(source, destination).then(() => callback(null), callback); -} - -export function copyFileSync(source: string | URL, destination: string): void { - source = source instanceof URL ? fromFileUrl(source) : source; - Deno.copyFileSync(source, destination); -} diff --git a/std/node/_fs/_fs_copy_test.ts b/std/node/_fs/_fs_copy_test.ts deleted file mode 100644 index 4fdf78cb0..000000000 --- a/std/node/_fs/_fs_copy_test.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import * as path from "../../path/mod.ts"; -import { assert } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { copyFile, copyFileSync } from "./_fs_copy.ts"; -import { existsSync } from "./_fs_exists.ts"; - -const destFile = "./destination.txt"; - -Deno.test({ - name: "[std/node/fs] copy file", - fn: async () => { - const sourceFile = Deno.makeTempFileSync(); - const err = await new Promise((resolve) => { - copyFile(sourceFile, destFile, (err?: Error | null) => resolve(err)); - }); - assert(!err); - assert(existsSync(destFile)); - Deno.removeSync(sourceFile); - Deno.removeSync(destFile); - }, -}); - -Deno.test({ - name: "[std/node/fs] copy file sync", - fn: () => { - const sourceFile = Deno.makeTempFileSync(); - copyFileSync(sourceFile, destFile); - assert(existsSync(destFile)); - Deno.removeSync(sourceFile); - Deno.removeSync(destFile); - }, -}); - -Deno.test("[std/node/fs] copyFile callback isn't called twice if error is thrown", async () => { - // The correct behaviour is not to catch any errors thrown, - // but that means there'll be an uncaught error and the test will fail. - // So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code. - // (assertThrowsAsync won't work because there's no way to catch the error.) - const tempDir = await Deno.makeTempDir(); - const tempFile1 = path.join(tempDir, "file1.txt"); - const tempFile2 = path.join(tempDir, "file2.txt"); - await Deno.writeTextFile(tempFile1, "hello world"); - const importUrl = new URL("./_fs_copy.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { copyFile } from ${JSON.stringify(importUrl)}`, - invocation: `copyFile(${JSON.stringify(tempFile1)}, - ${JSON.stringify(tempFile2)}, `, - async cleanup() { - await Deno.remove(tempDir, { recursive: true }); - }, - }); -}); diff --git a/std/node/_fs/_fs_dir.ts b/std/node/_fs/_fs_dir.ts deleted file mode 100644 index 4f7beec31..000000000 --- a/std/node/_fs/_fs_dir.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import Dirent from "./_fs_dirent.ts"; -import { assert } from "../../_util/assert.ts"; - -export default class Dir { - private dirPath: string | Uint8Array; - private syncIterator!: Iterator<Deno.DirEntry> | null; - private asyncIterator!: AsyncIterator<Deno.DirEntry> | null; - - constructor(path: string | Uint8Array) { - this.dirPath = path; - } - - get path(): string { - if (this.dirPath instanceof Uint8Array) { - return new TextDecoder().decode(this.dirPath); - } - return this.dirPath; - } - - // deno-lint-ignore no-explicit-any - read(callback?: (...args: any[]) => void): Promise<Dirent | null> { - return new Promise((resolve, reject) => { - if (!this.asyncIterator) { - this.asyncIterator = Deno.readDir(this.path)[Symbol.asyncIterator](); - } - assert(this.asyncIterator); - this.asyncIterator - .next() - .then(({ value }) => { - resolve(value ? value : null); - if (callback) { - callback(null, value ? value : null); - } - }, (err) => { - if (callback) { - callback(err); - } - reject(err); - }); - }); - } - - readSync(): Dirent | null { - if (!this.syncIterator) { - this.syncIterator = Deno.readDirSync(this.path)![Symbol.iterator](); - } - - const file: Deno.DirEntry = this.syncIterator.next().value; - - return file ? new Dirent(file) : null; - } - - /** - * Unlike Node, Deno does not require managing resource ids for reading - * directories, and therefore does not need to close directories when - * finished reading. - */ - // deno-lint-ignore no-explicit-any - close(callback?: (...args: any[]) => void): Promise<void> { - return new Promise((resolve) => { - if (callback) { - callback(null); - } - resolve(); - }); - } - - /** - * Unlike Node, Deno does not require managing resource ids for reading - * directories, and therefore does not need to close directories when - * finished reading - */ - closeSync(): void { - //No op - } - - async *[Symbol.asyncIterator](): AsyncIterableIterator<Dirent> { - try { - while (true) { - const dirent: Dirent | null = await this.read(); - if (dirent === null) { - break; - } - yield dirent; - } - } finally { - await this.close(); - } - } -} diff --git a/std/node/_fs/_fs_dir_test.ts b/std/node/_fs/_fs_dir_test.ts deleted file mode 100644 index f12563fd5..000000000 --- a/std/node/_fs/_fs_dir_test.ts +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import Dir from "./_fs_dir.ts"; -import type Dirent from "./_fs_dirent.ts"; - -Deno.test({ - name: "Closing current directory with callback is successful", - fn() { - let calledBack = false; - // deno-lint-ignore no-explicit-any - new Dir(".").close((valOrErr: any) => { - assert(!valOrErr); - calledBack = true; - }); - assert(calledBack); - }, -}); - -Deno.test({ - name: "Closing current directory without callback returns void Promise", - async fn() { - await new Dir(".").close(); - }, -}); - -Deno.test({ - name: "Closing current directory synchronously works", - fn() { - new Dir(".").closeSync(); - }, -}); - -Deno.test({ - name: "Path is correctly returned", - fn() { - assertEquals(new Dir("std/node").path, "std/node"); - - const enc: Uint8Array = new TextEncoder().encode("std/node"); - assertEquals(new Dir(enc).path, "std/node"); - }, -}); - -Deno.test({ - name: "read returns null for empty directory", - async fn() { - const testDir: string = Deno.makeTempDirSync(); - try { - const file: Dirent | null = await new Dir(testDir).read(); - assert(file === null); - - let calledBack = false; - const fileFromCallback: Dirent | null = await new Dir( - testDir, - // deno-lint-ignore no-explicit-any - ).read((err: any, res: Dirent) => { - assert(res === null); - assert(err === null); - calledBack = true; - }); - assert(fileFromCallback === null); - assert(calledBack); - - assertEquals(new Dir(testDir).readSync(), null); - } finally { - Deno.removeSync(testDir); - } - }, -}); - -Deno.test({ - name: "Async read returns one file at a time", - async fn() { - const testDir: string = Deno.makeTempDirSync(); - const f1 = Deno.createSync(testDir + "/foo.txt"); - f1.close(); - const f2 = Deno.createSync(testDir + "/bar.txt"); - f2.close(); - - try { - let secondCallback = false; - const dir: Dir = new Dir(testDir); - const firstRead: Dirent | null = await dir.read(); - const secondRead: Dirent | null = await dir.read( - // deno-lint-ignore no-explicit-any - (err: any, secondResult: Dirent) => { - assert( - secondResult.name === "bar.txt" || - secondResult.name === "foo.txt", - ); - secondCallback = true; - }, - ); - const thirdRead: Dirent | null = await dir.read(); - const fourthRead: Dirent | null = await dir.read(); - - if (firstRead?.name === "foo.txt") { - assertEquals(secondRead?.name, "bar.txt"); - } else if (firstRead?.name === "bar.txt") { - assertEquals(secondRead?.name, "foo.txt"); - } else { - fail("File not found during read"); - } - assert(secondCallback); - assert(thirdRead === null); - assert(fourthRead === null); - } finally { - Deno.removeSync(testDir, { recursive: true }); - } - }, -}); - -Deno.test({ - name: "Sync read returns one file at a time", - fn() { - const testDir: string = Deno.makeTempDirSync(); - const f1 = Deno.createSync(testDir + "/foo.txt"); - f1.close(); - const f2 = Deno.createSync(testDir + "/bar.txt"); - f2.close(); - - try { - const dir: Dir = new Dir(testDir); - const firstRead: Dirent | null = dir.readSync(); - const secondRead: Dirent | null = dir.readSync(); - const thirdRead: Dirent | null = dir.readSync(); - const fourthRead: Dirent | null = dir.readSync(); - - if (firstRead?.name === "foo.txt") { - assertEquals(secondRead?.name, "bar.txt"); - } else if (firstRead?.name === "bar.txt") { - assertEquals(secondRead?.name, "foo.txt"); - } else { - fail("File not found during read"); - } - assert(thirdRead === null); - assert(fourthRead === null); - } finally { - Deno.removeSync(testDir, { recursive: true }); - } - }, -}); - -Deno.test({ - name: "Async iteration over existing directory", - async fn() { - const testDir: string = Deno.makeTempDirSync(); - const f1 = Deno.createSync(testDir + "/foo.txt"); - f1.close(); - const f2 = Deno.createSync(testDir + "/bar.txt"); - f2.close(); - - try { - const dir: Dir = new Dir(testDir); - const results: Array<string | null> = []; - - for await (const file of dir[Symbol.asyncIterator]()) { - results.push(file.name); - } - - assert(results.length === 2); - assert(results.includes("foo.txt")); - assert(results.includes("bar.txt")); - } finally { - Deno.removeSync(testDir, { recursive: true }); - } - }, -}); - -Deno.test("[std/node/fs] Dir.close callback isn't called twice if error is thrown", async () => { - const tempDir = await Deno.makeTempDir(); - const importUrl = new URL("./_fs_dir.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: ` - import Dir from ${JSON.stringify(importUrl)}; - - const dir = new Dir(${JSON.stringify(tempDir)}); - `, - invocation: "dir.close(", - async cleanup() { - await Deno.remove(tempDir); - }, - }); -}); - -Deno.test("[std/node/fs] Dir.read callback isn't called twice if error is thrown", async () => { - const tempDir = await Deno.makeTempDir(); - const importUrl = new URL("./_fs_dir.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: ` - import Dir from ${JSON.stringify(importUrl)}; - - const dir = new Dir(${JSON.stringify(tempDir)}); - `, - invocation: "dir.read(", - async cleanup() { - await Deno.remove(tempDir); - }, - }); -}); diff --git a/std/node/_fs/_fs_dirent.ts b/std/node/_fs/_fs_dirent.ts deleted file mode 100644 index b44ebcb02..000000000 --- a/std/node/_fs/_fs_dirent.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { notImplemented } from "../_utils.ts"; - -export default class Dirent { - constructor(private entry: Deno.DirEntry) {} - - isBlockDevice(): boolean { - notImplemented("Deno does not yet support identification of block devices"); - return false; - } - - isCharacterDevice(): boolean { - notImplemented( - "Deno does not yet support identification of character devices", - ); - return false; - } - - isDirectory(): boolean { - return this.entry.isDirectory; - } - - isFIFO(): boolean { - notImplemented( - "Deno does not yet support identification of FIFO named pipes", - ); - return false; - } - - isFile(): boolean { - return this.entry.isFile; - } - - isSocket(): boolean { - notImplemented("Deno does not yet support identification of sockets"); - return false; - } - - isSymbolicLink(): boolean { - return this.entry.isSymlink; - } - - get name(): string | null { - return this.entry.name; - } -} diff --git a/std/node/_fs/_fs_dirent_test.ts b/std/node/_fs/_fs_dirent_test.ts deleted file mode 100644 index ad599c84c..000000000 --- a/std/node/_fs/_fs_dirent_test.ts +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals, assertThrows } from "../../testing/asserts.ts"; -import Dirent from "./_fs_dirent.ts"; - -class DirEntryMock implements Deno.DirEntry { - name = ""; - isFile = false; - isDirectory = false; - isSymlink = false; -} - -Deno.test({ - name: "Directories are correctly identified", - fn() { - const entry: DirEntryMock = new DirEntryMock(); - entry.isDirectory = true; - entry.isFile = false; - entry.isSymlink = false; - assert(new Dirent(entry).isDirectory()); - assert(!new Dirent(entry).isFile()); - assert(!new Dirent(entry).isSymbolicLink()); - }, -}); - -Deno.test({ - name: "Files are correctly identified", - fn() { - const entry: DirEntryMock = new DirEntryMock(); - entry.isDirectory = false; - entry.isFile = true; - entry.isSymlink = false; - assert(!new Dirent(entry).isDirectory()); - assert(new Dirent(entry).isFile()); - assert(!new Dirent(entry).isSymbolicLink()); - }, -}); - -Deno.test({ - name: "Symlinks are correctly identified", - fn() { - const entry: DirEntryMock = new DirEntryMock(); - entry.isDirectory = false; - entry.isFile = false; - entry.isSymlink = true; - assert(!new Dirent(entry).isDirectory()); - assert(!new Dirent(entry).isFile()); - assert(new Dirent(entry).isSymbolicLink()); - }, -}); - -Deno.test({ - name: "File name is correct", - fn() { - const entry: DirEntryMock = new DirEntryMock(); - entry.name = "my_file"; - assertEquals(new Dirent(entry).name, "my_file"); - }, -}); - -Deno.test({ - name: "Socket and FIFO pipes aren't yet available", - fn() { - const entry: DirEntryMock = new DirEntryMock(); - assertThrows( - () => { - new Dirent(entry).isFIFO(); - }, - Error, - "does not yet support", - ); - assertThrows( - () => { - new Dirent(entry).isSocket(); - }, - Error, - "does not yet support", - ); - }, -}); diff --git a/std/node/_fs/_fs_exists.ts b/std/node/_fs/_fs_exists.ts deleted file mode 100644 index 5cfa26a9d..000000000 --- a/std/node/_fs/_fs_exists.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { fromFileUrl } from "../path.ts"; - -type ExitsCallback = (exists: boolean) => void; - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - * Deprecated in node api - */ -export function exists(path: string | URL, callback: ExitsCallback): void { - path = path instanceof URL ? fromFileUrl(path) : path; - Deno.lstat(path).then(() => callback(true), () => callback(false)); -} - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer or URL type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function existsSync(path: string | URL): boolean { - path = path instanceof URL ? fromFileUrl(path) : path; - try { - Deno.lstatSync(path); - return true; - } catch (err) { - if (err instanceof Deno.errors.NotFound) { - return false; - } - throw err; - } -} diff --git a/std/node/_fs/_fs_exists_test.ts b/std/node/_fs/_fs_exists_test.ts deleted file mode 100644 index ab0ae5c15..000000000 --- a/std/node/_fs/_fs_exists_test.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertStringIncludes, -} from "../../testing/asserts.ts"; -import { exists, existsSync } from "./_fs_exists.ts"; - -Deno.test("existsFile", async function () { - const availableFile = await new Promise((resolve) => { - const tmpFilePath = Deno.makeTempFileSync(); - exists(tmpFilePath, (exists: boolean) => { - Deno.removeSync(tmpFilePath); - resolve(exists); - }); - }); - const notAvailableFile = await new Promise((resolve) => { - exists("./notAvailable.txt", (exists: boolean) => resolve(exists)); - }); - assertEquals(availableFile, true); - assertEquals(notAvailableFile, false); -}); - -Deno.test("existsSyncFile", function () { - const tmpFilePath = Deno.makeTempFileSync(); - assertEquals(existsSync(tmpFilePath), true); - Deno.removeSync(tmpFilePath); - assertEquals(existsSync("./notAvailable.txt"), false); -}); - -Deno.test("[std/node/fs] exists callback isn't called twice if error is thrown", async () => { - // This doesn't use `assertCallbackErrorUncaught()` because `exists()` doesn't return a standard node callback, which is what it expects. - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_exists.ts", import.meta.url); - const p = Deno.run({ - cmd: [ - Deno.execPath(), - "eval", - "--no-check", - ` - import { exists } from ${JSON.stringify(importUrl)}; - - exists(${JSON.stringify(tempFile)}, (exists) => { - // If the bug is present and the callback is called again with false (meaning an error occured), - // don't throw another error, so if the subprocess fails we know it had the correct behaviour. - if (exists) throw new Error("success"); - });`, - ], - stderr: "piped", - }); - const status = await p.status(); - const stderr = new TextDecoder().decode(await Deno.readAll(p.stderr)); - p.close(); - p.stderr.close(); - await Deno.remove(tempFile); - assert(!status.success); - assertStringIncludes(stderr, "Error: success"); -}); diff --git a/std/node/_fs/_fs_link.ts b/std/node/_fs/_fs_link.ts deleted file mode 100644 index 14a8189cb..000000000 --- a/std/node/_fs/_fs_link.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { fromFileUrl } from "../path.ts"; - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function link( - existingPath: string | URL, - newPath: string | URL, - callback: CallbackWithError, -): void { - existingPath = existingPath instanceof URL - ? fromFileUrl(existingPath) - : existingPath; - newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath; - - Deno.link(existingPath, newPath).then(() => callback(null), callback); -} - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -export function linkSync( - existingPath: string | URL, - newPath: string | URL, -): void { - existingPath = existingPath instanceof URL - ? fromFileUrl(existingPath) - : existingPath; - newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath; - - Deno.linkSync(existingPath, newPath); -} diff --git a/std/node/_fs/_fs_link_test.ts b/std/node/_fs/_fs_link_test.ts deleted file mode 100644 index 9e2aeb8b6..000000000 --- a/std/node/_fs/_fs_link_test.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import * as path from "../../path/mod.ts"; -import { assert, assertEquals, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { link, linkSync } from "./_fs_link.ts"; - -Deno.test({ - name: "ASYNC: hard linking files works as expected", - async fn() { - const tempFile: string = await Deno.makeTempFile(); - const linkedFile: string = tempFile + ".link"; - await new Promise<void>((res, rej) => { - link(tempFile, linkedFile, (err) => { - if (err) rej(err); - else res(); - }); - }) - .then(() => { - assertEquals(Deno.statSync(tempFile), Deno.statSync(linkedFile)); - }, () => { - fail("Expected to succeed"); - }) - .finally(() => { - Deno.removeSync(tempFile); - Deno.removeSync(linkedFile); - }); - }, -}); - -Deno.test({ - name: "ASYNC: hard linking files passes error to callback", - async fn() { - let failed = false; - await new Promise<void>((res, rej) => { - link("no-such-file", "no-such-file", (err) => { - if (err) rej(err); - else res(); - }); - }) - .then(() => { - fail("Expected to succeed"); - }, (err) => { - assert(err); - failed = true; - }); - assert(failed); - }, -}); - -Deno.test({ - name: "SYNC: hard linking files works as expected", - fn() { - const tempFile: string = Deno.makeTempFileSync(); - const linkedFile: string = tempFile + ".link"; - linkSync(tempFile, linkedFile); - - assertEquals(Deno.statSync(tempFile), Deno.statSync(linkedFile)); - Deno.removeSync(tempFile); - Deno.removeSync(linkedFile); - }, -}); - -Deno.test("[std/node/fs] link callback isn't called twice if error is thrown", async () => { - const tempDir = await Deno.makeTempDir(); - const tempFile = path.join(tempDir, "file.txt"); - const linkFile = path.join(tempDir, "link.txt"); - await Deno.writeTextFile(tempFile, "hello world"); - const importUrl = new URL("./_fs_link.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { link } from ${JSON.stringify(importUrl)}`, - invocation: `link(${JSON.stringify(tempFile)}, - ${JSON.stringify(linkFile)}, `, - async cleanup() { - await Deno.remove(tempDir, { recursive: true }); - }, - }); -}); diff --git a/std/node/_fs/_fs_lstat.ts b/std/node/_fs/_fs_lstat.ts deleted file mode 100644 index 55624cd5e..000000000 --- a/std/node/_fs/_fs_lstat.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - BigIntStats, - CFISBIS, - statCallback, - statCallbackBigInt, - statOptions, - Stats, -} from "./_fs_stat.ts"; - -export function lstat(path: string | URL, callback: statCallback): void; -export function lstat( - path: string | URL, - options: { bigint: false }, - callback: statCallback, -): void; -export function lstat( - path: string | URL, - options: { bigint: true }, - callback: statCallbackBigInt, -): void; -export function lstat( - path: string | URL, - optionsOrCallback: statCallback | statCallbackBigInt | statOptions, - maybeCallback?: statCallback | statCallbackBigInt, -) { - const callback = - (typeof optionsOrCallback === "function" - ? optionsOrCallback - : maybeCallback) as ( - ...args: [Error] | [null, BigIntStats | Stats] - ) => void; - const options = typeof optionsOrCallback === "object" - ? optionsOrCallback - : { bigint: false }; - - if (!callback) throw new Error("No callback function supplied"); - - Deno.lstat(path).then( - (stat) => callback(null, CFISBIS(stat, options.bigint)), - (err) => callback(err), - ); -} - -export function lstatSync(path: string | URL): Stats; -export function lstatSync( - path: string | URL, - options: { bigint: false }, -): Stats; -export function lstatSync( - path: string | URL, - options: { bigint: true }, -): BigIntStats; -export function lstatSync( - path: string | URL, - options?: statOptions, -): Stats | BigIntStats { - const origin = Deno.lstatSync(path); - return CFISBIS(origin, options?.bigint || false); -} diff --git a/std/node/_fs/_fs_lstat_test.ts b/std/node/_fs/_fs_lstat_test.ts deleted file mode 100644 index b8c562538..000000000 --- a/std/node/_fs/_fs_lstat_test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { lstat, lstatSync } from "./_fs_lstat.ts"; -import { fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts"; -import type { BigIntStats, Stats } from "./_fs_stat.ts"; - -Deno.test({ - name: "ASYNC: get a file Stats (lstat)", - async fn() { - const file = Deno.makeTempFileSync(); - await new Promise<Stats>((resolve, reject) => { - lstat(file, (err, stat) => { - if (err) reject(err); - resolve(stat); - }); - }) - .then((stat) => { - assertStats(stat, Deno.lstatSync(file)); - }, () => fail()) - .finally(() => { - Deno.removeSync(file); - }); - }, -}); - -Deno.test({ - name: "SYNC: get a file Stats (lstat)", - fn() { - const file = Deno.makeTempFileSync(); - assertStats(lstatSync(file), Deno.lstatSync(file)); - }, -}); - -Deno.test({ - name: "ASYNC: get a file BigInt Stats (lstat)", - async fn() { - const file = Deno.makeTempFileSync(); - await new Promise<BigIntStats>((resolve, reject) => { - lstat(file, { bigint: true }, (err, stat) => { - if (err) reject(err); - resolve(stat); - }); - }) - .then( - (stat) => assertStatsBigInt(stat, Deno.lstatSync(file)), - () => fail(), - ) - .finally(() => Deno.removeSync(file)); - }, -}); - -Deno.test({ - name: "SYNC: BigInt Stats (lstat)", - fn() { - const file = Deno.makeTempFileSync(); - assertStatsBigInt(lstatSync(file, { bigint: true }), Deno.lstatSync(file)); - }, -}); - -Deno.test("[std/node/fs] lstat callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_lstat.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { lstat } from ${JSON.stringify(importUrl)}`, - invocation: `lstat(${JSON.stringify(tempFile)}, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_mkdir.ts b/std/node/_fs/_fs_mkdir.ts deleted file mode 100644 index 94cc24a42..000000000 --- a/std/node/_fs/_fs_mkdir.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { CallbackWithError } from "./_fs_common.ts"; -import { fromFileUrl } from "../path.ts"; - -/** - * TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these - * are implemented. See https://github.com/denoland/deno/issues/3403 - */ -type MkdirOptions = - | { recursive?: boolean; mode?: number | undefined } - | number - | boolean; - -export function mkdir( - path: string | URL, - options?: MkdirOptions | CallbackWithError, - callback?: CallbackWithError, -): void { - path = path instanceof URL ? fromFileUrl(path) : path; - - let mode = 0o777; - let recursive = false; - - if (typeof options == "function") { - callback = options; - } else if (typeof options === "number") { - mode = options; - } else if (typeof options === "boolean") { - recursive = options; - } else if (options) { - if (options.recursive !== undefined) recursive = options.recursive; - if (options.mode !== undefined) mode = options.mode; - } - if (typeof recursive !== "boolean") { - throw new Deno.errors.InvalidData( - "invalid recursive option , must be a boolean", - ); - } - Deno.mkdir(path, { recursive, mode }) - .then(() => { - if (typeof callback === "function") { - callback(null); - } - }, (err) => { - if (typeof callback === "function") { - callback(err); - } - }); -} - -export function mkdirSync(path: string | URL, options?: MkdirOptions): void { - path = path instanceof URL ? fromFileUrl(path) : path; - let mode = 0o777; - let recursive = false; - - if (typeof options === "number") { - mode = options; - } else if (typeof options === "boolean") { - recursive = options; - } else if (options) { - if (options.recursive !== undefined) recursive = options.recursive; - if (options.mode !== undefined) mode = options.mode; - } - if (typeof recursive !== "boolean") { - throw new Deno.errors.InvalidData( - "invalid recursive option , must be a boolean", - ); - } - - Deno.mkdirSync(path, { recursive, mode }); -} diff --git a/std/node/_fs/_fs_mkdir_test.ts b/std/node/_fs/_fs_mkdir_test.ts deleted file mode 100644 index c13d065fe..000000000 --- a/std/node/_fs/_fs_mkdir_test.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import * as path from "../../path/mod.ts"; -import { assert } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { mkdir, mkdirSync } from "./_fs_mkdir.ts"; -import { existsSync } from "./_fs_exists.ts"; - -const tmpDir = "./tmpdir"; - -Deno.test({ - name: "[node/fs] mkdir", - fn: async () => { - const result = await new Promise((resolve) => { - mkdir(tmpDir, (err) => { - err && resolve(false); - resolve(existsSync(tmpDir)); - Deno.removeSync(tmpDir); - }); - }); - assert(result); - }, -}); - -Deno.test({ - name: "[node/fs] mkdirSync", - fn: () => { - mkdirSync(tmpDir); - assert(existsSync(tmpDir)); - Deno.removeSync(tmpDir); - }, -}); - -Deno.test("[std/node/fs] mkdir callback isn't called twice if error is thrown", async () => { - const tempDir = await Deno.makeTempDir(); - const subdir = path.join(tempDir, "subdir"); - const importUrl = new URL("./_fs_mkdir.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { mkdir } from ${JSON.stringify(importUrl)}`, - invocation: `mkdir(${JSON.stringify(subdir)}, `, - async cleanup() { - await Deno.remove(tempDir, { recursive: true }); - }, - }); -}); diff --git a/std/node/_fs/_fs_mkdtemp.ts b/std/node/_fs/_fs_mkdtemp.ts deleted file mode 100644 index 226399aa4..000000000 --- a/std/node/_fs/_fs_mkdtemp.ts +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { existsSync } from "./_fs_exists.ts"; -import { mkdir, mkdirSync } from "./_fs_mkdir.ts"; -import { - ERR_INVALID_CALLBACK, - ERR_INVALID_OPT_VALUE_ENCODING, -} from "../_errors.ts"; - -export type mkdtempCallback = ( - err: Error | null, - directory?: string, -) => void; - -// https://nodejs.org/dist/latest-v15.x/docs/api/fs.html#fs_fs_mkdtemp_prefix_options_callback -export function mkdtemp(prefix: string, callback: mkdtempCallback): void; -export function mkdtemp( - prefix: string, - options: { encoding: string } | string, - callback: mkdtempCallback, -): void; -export function mkdtemp( - prefix: string, - optionsOrCallback: { encoding: string } | string | mkdtempCallback, - maybeCallback?: mkdtempCallback, -): void { - const callback: mkdtempCallback | undefined = - typeof optionsOrCallback == "function" ? optionsOrCallback : maybeCallback; - if (!callback) throw new ERR_INVALID_CALLBACK(callback); - - const encoding: string | undefined = parseEncoding(optionsOrCallback); - const path = tempDirPath(prefix); - - mkdir( - path, - { recursive: false, mode: 0o700 }, - (err: Error | null | undefined) => { - if (err) callback(err); - else callback(null, decode(path, encoding)); - }, - ); -} - -// https://nodejs.org/dist/latest-v15.x/docs/api/fs.html#fs_fs_mkdtempsync_prefix_options -export function mkdtempSync( - prefix: string, - options?: { encoding: string } | string, -): string { - const encoding: string | undefined = parseEncoding(options); - const path = tempDirPath(prefix); - - mkdirSync(path, { recursive: false, mode: 0o700 }); - return decode(path, encoding); -} - -function parseEncoding( - optionsOrCallback?: { encoding: string } | string | mkdtempCallback, -): string | undefined { - let encoding: string | undefined; - if (typeof optionsOrCallback == "function") encoding = undefined; - else if (optionsOrCallback instanceof Object) { - encoding = optionsOrCallback?.encoding; - } else encoding = optionsOrCallback; - - if (encoding) { - try { - new TextDecoder(encoding); - } catch (error) { - throw new ERR_INVALID_OPT_VALUE_ENCODING(encoding); - } - } - - return encoding; -} - -function decode(str: string, encoding?: string): string { - if (!encoding) return str; - else { - const decoder = new TextDecoder(encoding); - const encoder = new TextEncoder(); - return decoder.decode(encoder.encode(str)); - } -} - -const CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; -function randomName(): string { - return [...Array(6)].map(() => - CHARS[Math.floor(Math.random() * CHARS.length)] - ).join(""); -} - -function tempDirPath(prefix: string): string { - let path: string; - do { - path = prefix + randomName(); - } while (existsSync(path)); - - return path; -} diff --git a/std/node/_fs/_fs_mkdtemp_test.ts b/std/node/_fs/_fs_mkdtemp_test.ts deleted file mode 100644 index d41c52794..000000000 --- a/std/node/_fs/_fs_mkdtemp_test.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertThrows, - assertThrowsAsync, -} from "../../testing/asserts.ts"; -import { mkdtemp, mkdtempSync } from "./_fs_mkdtemp.ts"; -import { existsSync } from "./_fs_exists.ts"; -import { env } from "../process.ts"; -import { isWindows } from "../../_util/os.ts"; -import { promisify } from "../_util/_util_promisify.ts"; - -const prefix = isWindows ? env.TEMP + "\\" : (env.TMPDIR || "/tmp") + "/"; -const doesNotExists = "/does/not/exists/"; -const options = { encoding: "ascii" }; -const badOptions = { encoding: "bogus" }; - -const mkdtempP = promisify(mkdtemp); - -Deno.test({ - name: "[node/fs] mkdtemp", - fn: async () => { - const directory = await mkdtempP(prefix); - assert(existsSync(directory)); - Deno.removeSync(directory); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtemp (does not exists)", - fn: async () => { - await assertThrowsAsync(() => mkdtempP(doesNotExists)); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtemp (with options)", - fn: async () => { - const directory = await mkdtempP(prefix, options); - assert(existsSync(directory)); - Deno.removeSync(directory); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtemp (with bad options)", - fn: async () => { - await assertThrowsAsync(() => mkdtempP(prefix, badOptions)); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtempSync", - fn: () => { - const directory = mkdtempSync(prefix); - const dirExists = existsSync(directory); - Deno.removeSync(directory); - assert(dirExists); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtempSync (does not exists)", - fn: () => { - assertThrows(() => mkdtempSync(doesNotExists)); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtempSync (with options)", - fn: () => { - const directory = mkdtempSync(prefix, options); - const dirExists = existsSync(directory); - Deno.removeSync(directory); - assert(dirExists); - }, -}); - -Deno.test({ - name: "[node/fs] mkdtempSync (with bad options)", - fn: () => { - assertThrows(() => mkdtempSync(prefix, badOptions)); - }, -}); diff --git a/std/node/_fs/_fs_open.ts b/std/node/_fs/_fs_open.ts deleted file mode 100644 index 55ecbdc1e..000000000 --- a/std/node/_fs/_fs_open.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { existsSync } from "../../fs/mod.ts"; -import { fromFileUrl } from "../path.ts"; -import { getOpenOptions } from "./_fs_common.ts"; - -type openFlags = - | "a" - | "ax" - | "a+" - | "ax+" - | "as" - | "as+" - | "r" - | "r+" - | "rs+" - | "w" - | "wx" - | "w+" - | "wx+"; - -type openCallback = (err: Error | null, fd: number) => void; - -function convertFlagAndModeToOptions( - flag?: openFlags, - mode?: number, -): Deno.OpenOptions | undefined { - if (!flag && !mode) return undefined; - if (!flag && mode) return { mode }; - return { ...getOpenOptions(flag), mode }; -} - -export function open(path: string | URL, callback: openCallback): void; -export function open( - path: string | URL, - flags: openFlags, - callback: openCallback, -): void; -export function open( - path: string | URL, - flags: openFlags, - mode: number, - callback: openCallback, -): void; -export function open( - path: string | URL, - flagsOrCallback: openCallback | openFlags, - callbackOrMode?: openCallback | number, - maybeCallback?: openCallback, -) { - const flags = typeof flagsOrCallback === "string" - ? flagsOrCallback - : undefined; - const callback = typeof flagsOrCallback === "function" - ? flagsOrCallback - : typeof callbackOrMode === "function" - ? callbackOrMode - : maybeCallback; - const mode = typeof callbackOrMode === "number" ? callbackOrMode : undefined; - path = path instanceof URL ? fromFileUrl(path) : path; - - if (!callback) throw new Error("No callback function supplied"); - - if (["ax", "ax+", "wx", "wx+"].includes(flags || "") && existsSync(path)) { - const err = new Error(`EEXIST: file already exists, open '${path}'`); - (callback as (err: Error) => void)(err); - } else { - if (flags === "as" || flags === "as+") { - let err: Error | null = null, res: number; - try { - res = openSync(path, flags, mode); - } catch (error) { - err = error; - } - if (err) { - (callback as (err: Error) => void)(err); - } else { - callback(null, res!); - } - return; - } - Deno.open(path, convertFlagAndModeToOptions(flags, mode)).then( - (file) => callback(null, file.rid), - (err) => (callback as (err: Error) => void)(err), - ); - } -} - -export function openSync(path: string | URL): number; -export function openSync(path: string | URL, flags?: openFlags): number; -export function openSync(path: string | URL, mode?: number): number; -export function openSync( - path: string | URL, - flags?: openFlags, - mode?: number, -): number; -export function openSync( - path: string | URL, - flagsOrMode?: openFlags | number, - maybeMode?: number, -) { - const flags = typeof flagsOrMode === "string" ? flagsOrMode : undefined; - const mode = typeof flagsOrMode === "number" ? flagsOrMode : maybeMode; - path = path instanceof URL ? fromFileUrl(path) : path; - - if (["ax", "ax+", "wx", "wx+"].includes(flags || "") && existsSync(path)) { - throw new Error(`EEXIST: file already exists, open '${path}'`); - } - - return Deno.openSync(path, convertFlagAndModeToOptions(flags, mode)).rid; -} diff --git a/std/node/_fs/_fs_open_test.ts b/std/node/_fs/_fs_open_test.ts deleted file mode 100644 index f32a8ce0a..000000000 --- a/std/node/_fs/_fs_open_test.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - assert, - assertEquals, - assertThrows, - fail, -} from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { open, openSync } from "./_fs_open.ts"; -import { join, parse } from "../../path/mod.ts"; -import { existsSync } from "../../fs/mod.ts"; -import { closeSync } from "./_fs_close.ts"; - -const tempDir = parse(Deno.makeTempFileSync()).dir; - -Deno.test({ - name: "ASYNC: open file", - async fn() { - const file = Deno.makeTempFileSync(); - let fd1: number; - await new Promise<number>((resolve, reject) => { - open(file, (err, fd) => { - if (err) reject(err); - resolve(fd); - }); - }) - .then((fd) => { - fd1 = fd; - assert(Deno.resources()[fd], `${fd}`); - }, () => fail()) - .finally(() => closeSync(fd1)); - }, -}); - -Deno.test({ - name: "SYNC: open file", - fn() { - const file = Deno.makeTempFileSync(); - const fd = openSync(file); - assert(Deno.resources()[fd]); - closeSync(fd); - }, -}); - -Deno.test({ - name: "open with flag 'a'", - fn() { - const file = join(tempDir, "some_random_file"); - const fd = openSync(file, "a"); - assertEquals(typeof fd, "number"); - assertEquals(existsSync(file), true); - assert(Deno.resources()[fd]); - closeSync(fd); - }, -}); - -Deno.test({ - name: "open with flag 'ax'", - fn() { - const file = Deno.makeTempFileSync(); - assertThrows( - () => { - openSync(file, "ax"); - }, - Error, - `EEXIST: file already exists, open '${file}'`, - ); - Deno.removeSync(file); - }, -}); - -Deno.test({ - name: "open with flag 'a+'", - fn() { - const file = join(tempDir, "some_random_file2"); - const fd = openSync(file, "a+"); - assertEquals(typeof fd, "number"); - assertEquals(existsSync(file), true); - closeSync(fd); - }, -}); - -Deno.test({ - name: "open with flag 'ax+'", - fn() { - const file = Deno.makeTempFileSync(); - assertThrows( - () => { - openSync(file, "ax+"); - }, - Error, - `EEXIST: file already exists, open '${file}'`, - ); - Deno.removeSync(file); - }, -}); - -Deno.test({ - name: "open with flag 'as'", - fn() { - const file = join(tempDir, "some_random_file10"); - const fd = openSync(file, "as"); - assertEquals(existsSync(file), true); - assertEquals(typeof fd, "number"); - closeSync(fd); - }, -}); - -Deno.test({ - name: "open with flag 'as+'", - fn() { - const file = join(tempDir, "some_random_file10"); - const fd = openSync(file, "as+"); - assertEquals(existsSync(file), true); - assertEquals(typeof fd, "number"); - closeSync(fd); - }, -}); - -Deno.test({ - name: "open with flag 'r'", - fn() { - const file = join(tempDir, "some_random_file3"); - assertThrows(() => { - openSync(file, "r"); - }, Error); - }, -}); - -Deno.test({ - name: "open with flag 'r+'", - fn() { - const file = join(tempDir, "some_random_file4"); - assertThrows(() => { - openSync(file, "r+"); - }, Error); - }, -}); - -Deno.test({ - name: "open with flag 'w'", - fn() { - const file = Deno.makeTempFileSync(); - Deno.writeTextFileSync(file, "hi there"); - const fd = openSync(file, "w"); - assertEquals(typeof fd, "number"); - assertEquals(Deno.readTextFileSync(file), ""); - closeSync(fd); - - const file2 = join(tempDir, "some_random_file5"); - const fd2 = openSync(file2, "w"); - assertEquals(typeof fd2, "number"); - assertEquals(existsSync(file2), true); - closeSync(fd2); - }, -}); - -Deno.test({ - name: "open with flag 'wx'", - fn() { - const file = Deno.makeTempFileSync(); - Deno.writeTextFileSync(file, "hi there"); - const fd = openSync(file, "w"); - assertEquals(typeof fd, "number"); - assertEquals(Deno.readTextFileSync(file), ""); - closeSync(fd); - - const file2 = Deno.makeTempFileSync(); - assertThrows( - () => { - openSync(file2, "wx"); - }, - Error, - `EEXIST: file already exists, open '${file2}'`, - ); - }, -}); - -Deno.test({ - name: "open with flag 'w+'", - fn() { - const file = Deno.makeTempFileSync(); - Deno.writeTextFileSync(file, "hi there"); - const fd = openSync(file, "w+"); - assertEquals(typeof fd, "number"); - assertEquals(Deno.readTextFileSync(file), ""); - closeSync(fd); - - const file2 = join(tempDir, "some_random_file6"); - const fd2 = openSync(file2, "w+"); - assertEquals(typeof fd2, "number"); - assertEquals(existsSync(file2), true); - closeSync(fd2); - }, -}); - -Deno.test({ - name: "open with flag 'wx+'", - fn() { - const file = Deno.makeTempFileSync(); - assertThrows( - () => { - openSync(file, "wx+"); - }, - Error, - `EEXIST: file already exists, open '${file}'`, - ); - Deno.removeSync(file); - }, -}); - -Deno.test("[std/node/fs] open callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_open.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { open } from ${JSON.stringify(importUrl)}`, - invocation: `open(${JSON.stringify(tempFile)}, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_readFile.ts b/std/node/_fs/_fs_readFile.ts deleted file mode 100644 index 4ad763e25..000000000 --- a/std/node/_fs/_fs_readFile.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - BinaryOptionsArgument, - FileOptionsArgument, - getEncoding, - TextOptionsArgument, -} from "./_fs_common.ts"; -import { Buffer } from "../buffer.ts"; -import { fromFileUrl } from "../path.ts"; -import { BinaryEncodings, Encodings, TextEncodings } from "../_utils.ts"; - -function maybeDecode(data: Uint8Array, encoding: TextEncodings): string; -function maybeDecode( - data: Uint8Array, - encoding: BinaryEncodings | null, -): Buffer; -function maybeDecode( - data: Uint8Array, - encoding: Encodings | null, -): string | Buffer { - const buffer = new Buffer(data.buffer, data.byteOffset, data.byteLength); - if (encoding && encoding !== "binary") return buffer.toString(encoding); - return buffer; -} - -type TextCallback = (err: Error | null, data?: string) => void; -type BinaryCallback = (err: Error | null, data?: Buffer) => void; -type GenericCallback = (err: Error | null, data?: string | Buffer) => void; -type Callback = TextCallback | BinaryCallback | GenericCallback; - -export function readFile( - path: string | URL, - options: TextOptionsArgument, - callback: TextCallback, -): void; -export function readFile( - path: string | URL, - options: BinaryOptionsArgument, - callback: BinaryCallback, -): void; -export function readFile( - path: string | URL, - options: null | undefined | FileOptionsArgument, - callback: BinaryCallback, -): void; -export function readFile(path: string | URL, callback: BinaryCallback): void; -export function readFile( - path: string | URL, - optOrCallback?: FileOptionsArgument | Callback | null | undefined, - callback?: Callback, -): void { - path = path instanceof URL ? fromFileUrl(path) : path; - let cb: Callback | undefined; - if (typeof optOrCallback === "function") { - cb = optOrCallback; - } else { - cb = callback; - } - - const encoding = getEncoding(optOrCallback); - - const p = Deno.readFile(path); - - if (cb) { - p.then((data: Uint8Array) => { - if (encoding && encoding !== "binary") { - const text = maybeDecode(data, encoding); - return (cb as TextCallback)(null, text); - } - const buffer = maybeDecode(data, encoding); - (cb as BinaryCallback)(null, buffer); - }, (err) => cb && cb(err)); - } -} - -export function readFileSync( - path: string | URL, - opt: TextOptionsArgument, -): string; -export function readFileSync( - path: string | URL, - opt?: BinaryOptionsArgument, -): Buffer; -export function readFileSync( - path: string | URL, - opt?: FileOptionsArgument, -): string | Buffer { - path = path instanceof URL ? fromFileUrl(path) : path; - const data = Deno.readFileSync(path); - const encoding = getEncoding(opt); - if (encoding && encoding !== "binary") { - const text = maybeDecode(data, encoding); - return text; - } - const buffer = maybeDecode(data, encoding); - return buffer; -} diff --git a/std/node/_fs/_fs_readFile_test.ts b/std/node/_fs/_fs_readFile_test.ts deleted file mode 100644 index 7af32c8a1..000000000 --- a/std/node/_fs/_fs_readFile_test.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { readFile, readFileSync } from "./_fs_readFile.ts"; -import * as path from "../../path/mod.ts"; -import { assert, assertEquals } from "../../testing/asserts.ts"; - -const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); -const testData = path.resolve(moduleDir, "testdata", "hello.txt"); - -Deno.test("readFileSuccess", async function () { - const data = await new Promise((res, rej) => { - readFile(testData, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world"); -}); - -Deno.test("readFileEncodeUtf8Success", async function () { - const data = await new Promise((res, rej) => { - readFile(testData, { encoding: "utf8" }, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); -}); - -Deno.test("readFileEncodeHexSuccess", async function () { - const data = await new Promise((res, rej) => { - readFile(testData, { encoding: "hex" }, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - - assertEquals(typeof data, "string"); - assertEquals(data as string, "68656c6c6f20776f726c64"); -}); - -Deno.test("readFileEncodeBase64Success", async function () { - const data = await new Promise((res, rej) => { - readFile(testData, { encoding: "base64" }, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "aGVsbG8gd29ybGQ="); -}); - -Deno.test("readFileEncodingAsString", async function () { - const data = await new Promise((res, rej) => { - readFile(testData, "utf8", (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - - assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); -}); - -Deno.test("readFileSyncSuccess", function () { - const data = readFileSync(testData); - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world"); -}); - -Deno.test("readFileEncodeUtf8Success", function () { - const data = readFileSync(testData, { encoding: "utf8" }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); -}); - -Deno.test("readFileEncodeHexSuccess", function () { - const data = readFileSync(testData, { encoding: "hex" }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "68656c6c6f20776f726c64"); -}); - -Deno.test("readFileEncodeBase64Success", function () { - const data = readFileSync(testData, { encoding: "base64" }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "aGVsbG8gd29ybGQ="); -}); - -Deno.test("readFileEncodeAsString", function () { - const data = readFileSync(testData, "utf8"); - assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); -}); - -Deno.test("[std/node/fs] readFile callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_readFile.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { readFile } from ${JSON.stringify(importUrl)}`, - invocation: `readFile(${JSON.stringify(tempFile)}, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_readdir.ts b/std/node/_fs/_fs_readdir.ts deleted file mode 100644 index e36bf5ecf..000000000 --- a/std/node/_fs/_fs_readdir.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { asyncIterableToCallback } from "./_fs_watch.ts"; -import Dirent from "./_fs_dirent.ts"; -import { fromFileUrl } from "../path.ts"; - -function toDirent(val: Deno.DirEntry): Dirent { - return new Dirent(val); -} - -type readDirOptions = { - encoding?: string; - withFileTypes?: boolean; -}; - -type readDirCallback = (err: Error | null, files: string[]) => void; - -type readDirCallbackDirent = (err: Error | null, files: Dirent[]) => void; - -type readDirBoth = ( - ...args: [Error] | [null, string[] | Dirent[] | Array<string | Dirent>] -) => void; - -export function readdir( - path: string | URL, - options: { withFileTypes?: false; encoding?: string }, - callback: readDirCallback, -): void; -export function readdir( - path: string | URL, - options: { withFileTypes: true; encoding?: string }, - callback: readDirCallbackDirent, -): void; -export function readdir(path: string | URL, callback: readDirCallback): void; -export function readdir( - path: string | URL, - optionsOrCallback: readDirOptions | readDirCallback | readDirCallbackDirent, - maybeCallback?: readDirCallback | readDirCallbackDirent, -) { - const callback = - (typeof optionsOrCallback === "function" - ? optionsOrCallback - : maybeCallback) as readDirBoth | undefined; - const options = typeof optionsOrCallback === "object" - ? optionsOrCallback - : null; - const result: Array<string | Dirent> = []; - path = path instanceof URL ? fromFileUrl(path) : path; - - if (!callback) throw new Error("No callback function supplied"); - - if (options?.encoding) { - try { - new TextDecoder(options.encoding); - } catch (error) { - throw new Error( - `TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "${options.encoding}" is invalid for option "encoding"`, - ); - } - } - - try { - asyncIterableToCallback(Deno.readDir(path), (val, done) => { - if (typeof path !== "string") return; - if (done) { - callback(null, result); - return; - } - if (options?.withFileTypes) { - result.push(toDirent(val)); - } else result.push(decode(val.name)); - }); - } catch (error) { - callback(error); - } -} - -function decode(str: string, encoding?: string): string { - if (!encoding) return str; - else { - const decoder = new TextDecoder(encoding); - const encoder = new TextEncoder(); - return decoder.decode(encoder.encode(str)); - } -} - -export function readdirSync( - path: string | URL, - options: { withFileTypes: true; encoding?: string }, -): Dirent[]; -export function readdirSync( - path: string | URL, - options?: { withFileTypes?: false; encoding?: string }, -): string[]; -export function readdirSync( - path: string | URL, - options?: readDirOptions, -): Array<string | Dirent> { - const result = []; - path = path instanceof URL ? fromFileUrl(path) : path; - - if (options?.encoding) { - try { - new TextDecoder(options.encoding); - } catch (error) { - throw new Error( - `TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "${options.encoding}" is invalid for option "encoding"`, - ); - } - } - - for (const file of Deno.readDirSync(path)) { - if (options?.withFileTypes) { - result.push(toDirent(file)); - } else result.push(decode(file.name)); - } - return result; -} diff --git a/std/node/_fs/_fs_readdir_test.ts b/std/node/_fs/_fs_readdir_test.ts deleted file mode 100644 index 165cb8141..000000000 --- a/std/node/_fs/_fs_readdir_test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { assertEquals, assertNotEquals, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { readdir, readdirSync } from "./_fs_readdir.ts"; -import { join } from "../../path/mod.ts"; - -Deno.test({ - name: "ASYNC: reading empty directory", - async fn() { - const dir = Deno.makeTempDirSync(); - await new Promise<string[]>((resolve, reject) => { - readdir(dir, (err, files) => { - if (err) reject(err); - resolve(files); - }); - }) - .then((files) => assertEquals(files, []), () => fail()) - .finally(() => Deno.removeSync(dir)); - }, -}); - -function assertEqualsArrayAnyOrder<T>(actual: T[], expected: T[]) { - assertEquals(actual.length, expected.length); - for (const item of expected) { - const index = actual.indexOf(item); - assertNotEquals(index, -1); - expected = expected.splice(index, 1); - } -} - -Deno.test({ - name: "ASYNC: reading non-empty directory", - async fn() { - const dir = Deno.makeTempDirSync(); - Deno.writeTextFileSync(join(dir, "file1.txt"), "hi"); - Deno.writeTextFileSync(join(dir, "file2.txt"), "hi"); - Deno.mkdirSync(join(dir, "some_dir")); - await new Promise<string[]>((resolve, reject) => { - readdir(dir, (err, files) => { - if (err) reject(err); - resolve(files); - }); - }) - .then( - (files) => - assertEqualsArrayAnyOrder( - files, - ["file1.txt", "some_dir", "file2.txt"], - ), - () => fail(), - ) - .finally(() => Deno.removeSync(dir, { recursive: true })); - }, -}); - -Deno.test({ - name: "SYNC: reading empty the directory", - fn() { - const dir = Deno.makeTempDirSync(); - assertEquals(readdirSync(dir), []); - }, -}); - -Deno.test({ - name: "SYNC: reading non-empty directory", - fn() { - const dir = Deno.makeTempDirSync(); - Deno.writeTextFileSync(join(dir, "file1.txt"), "hi"); - Deno.writeTextFileSync(join(dir, "file2.txt"), "hi"); - Deno.mkdirSync(join(dir, "some_dir")); - assertEqualsArrayAnyOrder( - readdirSync(dir), - ["file1.txt", "some_dir", "file2.txt"], - ); - }, -}); - -Deno.test("[std/node/fs] readdir callback isn't called twice if error is thrown", async () => { - // The correct behaviour is not to catch any errors thrown, - // but that means there'll be an uncaught error and the test will fail. - // So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code. - // (assertThrowsAsync won't work because there's no way to catch the error.) - const tempDir = await Deno.makeTempDir(); - const importUrl = new URL("./_fs_readdir.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { readdir } from ${JSON.stringify(importUrl)}`, - invocation: `readdir(${JSON.stringify(tempDir)}, `, - async cleanup() { - await Deno.remove(tempDir); - }, - }); -}); diff --git a/std/node/_fs/_fs_readlink.ts b/std/node/_fs/_fs_readlink.ts deleted file mode 100644 index 37a7a108f..000000000 --- a/std/node/_fs/_fs_readlink.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - intoCallbackAPIWithIntercept, - MaybeEmpty, - notImplemented, -} from "../_utils.ts"; -import { fromFileUrl } from "../path.ts"; - -type ReadlinkCallback = ( - err: MaybeEmpty<Error>, - linkString: MaybeEmpty<string | Uint8Array>, -) => void; - -interface ReadlinkOptions { - encoding?: string | null; -} - -function maybeEncode( - data: string, - encoding: string | null, -): string | Uint8Array { - if (encoding === "buffer") { - return new TextEncoder().encode(data); - } - return data; -} - -function getEncoding( - optOrCallback?: ReadlinkOptions | ReadlinkCallback, -): string | null { - if (!optOrCallback || typeof optOrCallback === "function") { - return null; - } else { - if (optOrCallback.encoding) { - if ( - optOrCallback.encoding === "utf8" || - optOrCallback.encoding === "utf-8" - ) { - return "utf8"; - } else if (optOrCallback.encoding === "buffer") { - return "buffer"; - } else { - notImplemented(); - } - } - return null; - } -} - -export function readlink( - path: string | URL, - optOrCallback: ReadlinkCallback | ReadlinkOptions, - callback?: ReadlinkCallback, -): void { - path = path instanceof URL ? fromFileUrl(path) : path; - - let cb: ReadlinkCallback | undefined; - if (typeof optOrCallback === "function") { - cb = optOrCallback; - } else { - cb = callback; - } - - const encoding = getEncoding(optOrCallback); - - intoCallbackAPIWithIntercept<string, Uint8Array | string>( - Deno.readLink, - (data: string): string | Uint8Array => maybeEncode(data, encoding), - cb, - path, - ); -} - -export function readlinkSync( - path: string | URL, - opt?: ReadlinkOptions, -): string | Uint8Array { - path = path instanceof URL ? fromFileUrl(path) : path; - - return maybeEncode(Deno.readLinkSync(path), getEncoding(opt)); -} diff --git a/std/node/_fs/_fs_readlink_test.ts b/std/node/_fs/_fs_readlink_test.ts deleted file mode 100644 index cb3dd25b4..000000000 --- a/std/node/_fs/_fs_readlink_test.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { readlink, readlinkSync } from "./_fs_readlink.ts"; -import { assert, assertEquals } from "../../testing/asserts.ts"; -import * as path from "../path.ts"; - -const testDir = Deno.makeTempDirSync(); -const oldname = path.join(testDir, "oldname"); -const newname = path.join(testDir, "newname"); - -if (Deno.build.os === "windows") { - Deno.symlinkSync(oldname, newname, { type: "file" }); -} else { - Deno.symlinkSync(oldname, newname); -} - -Deno.test({ - name: "readlinkSuccess", - async fn() { - const data = await new Promise((res, rej) => { - readlink(newname, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - - assertEquals(typeof data, "string"); - assertEquals(data as string, oldname); - }, -}); - -Deno.test({ - name: "readlinkEncodeBufferSuccess", - async fn() { - const data = await new Promise((res, rej) => { - readlink(newname, { encoding: "buffer" }, (err, data) => { - if (err) { - rej(err); - } - res(data); - }); - }); - - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data as Uint8Array), oldname); - }, -}); - -Deno.test({ - name: "readlinkSyncSuccess", - fn() { - const data = readlinkSync(newname); - assertEquals(typeof data, "string"); - assertEquals(data as string, oldname); - }, -}); - -Deno.test({ - name: "readlinkEncodeBufferSuccess", - fn() { - const data = readlinkSync(newname, { encoding: "buffer" }); - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data as Uint8Array), oldname); - }, -}); - -Deno.test("[std/node/fs] readlink callback isn't called twice if error is thrown", async () => { - const importUrl = new URL("./_fs_readlink.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { readlink } from ${JSON.stringify(importUrl)}`, - invocation: `readlink(${JSON.stringify(newname)}, `, - }); -}); diff --git a/std/node/_fs/_fs_realpath.ts b/std/node/_fs/_fs_realpath.ts deleted file mode 100644 index 95e699d65..000000000 --- a/std/node/_fs/_fs_realpath.ts +++ /dev/null @@ -1,23 +0,0 @@ -type Options = { encoding: string }; -type Callback = (err: Error | null, path?: string) => void; - -export function realpath( - path: string, - options?: Options | Callback, - callback?: Callback, -) { - if (typeof options === "function") { - callback = options; - } - if (!callback) { - throw new Error("No callback function supplied"); - } - Deno.realPath(path).then( - (path) => callback!(null, path), - (err) => callback!(err), - ); -} - -export function realpathSync(path: string): string { - return Deno.realPathSync(path); -} diff --git a/std/node/_fs/_fs_realpath_test.ts b/std/node/_fs/_fs_realpath_test.ts deleted file mode 100644 index 08eb3ef16..000000000 --- a/std/node/_fs/_fs_realpath_test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as path from "../../path/mod.ts"; -import { assertEquals } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { realpath, realpathSync } from "./_fs_realpath.ts"; - -Deno.test("realpath", async function () { - const tempFile = await Deno.makeTempFile(); - const tempFileAlias = tempFile + ".alias"; - await Deno.symlink(tempFile, tempFileAlias); - const realPath = await new Promise((resolve, reject) => { - realpath(tempFile, (err, path) => { - if (err) { - reject(err); - return; - } - resolve(path); - }); - }); - const realSymLinkPath = await new Promise((resolve, reject) => { - realpath(tempFileAlias, (err, path) => { - if (err) { - reject(err); - return; - } - resolve(path); - }); - }); - assertEquals(realPath, realSymLinkPath); -}); - -Deno.test("realpathSync", function () { - const tempFile = Deno.makeTempFileSync(); - const tempFileAlias = tempFile + ".alias"; - Deno.symlinkSync(tempFile, tempFileAlias); - const realPath = realpathSync(tempFile); - const realSymLinkPath = realpathSync(tempFileAlias); - assertEquals(realPath, realSymLinkPath); -}); - -Deno.test("[std/node/fs] realpath callback isn't called twice if error is thrown", async () => { - const tempDir = await Deno.makeTempDir(); - const tempFile = path.join(tempDir, "file.txt"); - const linkFile = path.join(tempDir, "link.txt"); - await Deno.writeTextFile(tempFile, "hello world"); - await Deno.symlink(tempFile, linkFile, { type: "file" }); - const importUrl = new URL("./_fs_realpath.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { realpath } from ${JSON.stringify(importUrl)}`, - invocation: `realpath(${JSON.stringify(`${tempDir}/link.txt`)}, `, - async cleanup() { - await Deno.remove(tempDir, { recursive: true }); - }, - }); -}); diff --git a/std/node/_fs/_fs_rename.ts b/std/node/_fs/_fs_rename.ts deleted file mode 100644 index b121eacf9..000000000 --- a/std/node/_fs/_fs_rename.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { fromFileUrl } from "../path.ts"; - -export function rename( - oldPath: string | URL, - newPath: string | URL, - callback: (err?: Error) => void, -) { - oldPath = oldPath instanceof URL ? fromFileUrl(oldPath) : oldPath; - newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath; - - if (!callback) throw new Error("No callback function supplied"); - - Deno.rename(oldPath, newPath).then((_) => callback(), callback); -} - -export function renameSync(oldPath: string | URL, newPath: string | URL) { - oldPath = oldPath instanceof URL ? fromFileUrl(oldPath) : oldPath; - newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath; - - Deno.renameSync(oldPath, newPath); -} diff --git a/std/node/_fs/_fs_rename_test.ts b/std/node/_fs/_fs_rename_test.ts deleted file mode 100644 index e35e5282e..000000000 --- a/std/node/_fs/_fs_rename_test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { assertEquals, fail } from "../../testing/asserts.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { rename, renameSync } from "./_fs_rename.ts"; -import { existsSync } from "../../fs/mod.ts"; -import { join, parse } from "../../path/mod.ts"; - -Deno.test({ - name: "ASYNC: renaming a file", - async fn() { - const file = Deno.makeTempFileSync(); - const newPath = join(parse(file).dir, `${parse(file).base}_renamed`); - await new Promise<void>((resolve, reject) => { - rename(file, newPath, (err) => { - if (err) reject(err); - resolve(); - }); - }) - .then(() => { - assertEquals(existsSync(newPath), true); - assertEquals(existsSync(file), false); - }, () => fail()) - .finally(() => { - if (existsSync(file)) Deno.removeSync(file); - if (existsSync(newPath)) Deno.removeSync(newPath); - }); - }, -}); - -Deno.test({ - name: "SYNC: renaming a file", - fn() { - const file = Deno.makeTempFileSync(); - const newPath = join(parse(file).dir, `${parse(file).base}_renamed`); - renameSync(file, newPath); - assertEquals(existsSync(newPath), true); - assertEquals(existsSync(file), false); - }, -}); - -Deno.test("[std/node/fs] rename callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_rename.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { rename } from ${JSON.stringify(importUrl)}`, - invocation: `rename(${JSON.stringify(tempFile)}, - ${JSON.stringify(`${tempFile}.newname`)}, `, - async cleanup() { - await Deno.remove(`${tempFile}.newname`); - }, - }); -}); diff --git a/std/node/_fs/_fs_rmdir.ts b/std/node/_fs/_fs_rmdir.ts deleted file mode 100644 index e82e696e3..000000000 --- a/std/node/_fs/_fs_rmdir.ts +++ /dev/null @@ -1,35 +0,0 @@ -type rmdirOptions = { - maxRetries?: number; - recursive?: boolean; - retryDelay?: number; -}; - -type rmdirCallback = (err?: Error) => void; - -export function rmdir(path: string | URL, callback: rmdirCallback): void; -export function rmdir( - path: string | URL, - options: rmdirOptions, - callback: rmdirCallback, -): void; -export function rmdir( - path: string | URL, - optionsOrCallback: rmdirOptions | rmdirCallback, - maybeCallback?: rmdirCallback, -) { - const callback = typeof optionsOrCallback === "function" - ? optionsOrCallback - : maybeCallback; - const options = typeof optionsOrCallback === "object" - ? optionsOrCallback - : undefined; - - if (!callback) throw new Error("No callback function supplied"); - - Deno.remove(path, { recursive: options?.recursive }) - .then((_) => callback(), callback); -} - -export function rmdirSync(path: string | URL, options?: rmdirOptions) { - Deno.removeSync(path, { recursive: options?.recursive }); -} diff --git a/std/node/_fs/_fs_rmdir_test.ts b/std/node/_fs/_fs_rmdir_test.ts deleted file mode 100644 index 6f9c33274..000000000 --- a/std/node/_fs/_fs_rmdir_test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { assertEquals, fail } from "../../testing/asserts.ts"; -import { rmdir, rmdirSync } from "./_fs_rmdir.ts"; -import { closeSync } from "./_fs_close.ts"; -import { existsSync } from "../../fs/mod.ts"; -import { join } from "../../path/mod.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; - -Deno.test({ - name: "ASYNC: removing empty folder", - async fn() { - const dir = Deno.makeTempDirSync(); - await new Promise<void>((resolve, reject) => { - rmdir(dir, (err) => { - if (err) reject(err); - resolve(); - }); - }) - .then(() => assertEquals(existsSync(dir), false), () => fail()) - .finally(() => { - if (existsSync(dir)) Deno.removeSync(dir); - }); - }, -}); - -Deno.test({ - name: "SYNC: removing empty folder", - fn() { - const dir = Deno.makeTempDirSync(); - rmdirSync(dir); - assertEquals(existsSync(dir), false); - }, -}); - -function closeRes(before: Deno.ResourceMap, after: Deno.ResourceMap) { - for (const key in after) { - if (!before[key]) { - try { - closeSync(Number(key)); - } catch (error) { - return error; - } - } - } -} - -Deno.test({ - name: "ASYNC: removing non-empty folder", - async fn() { - const rBefore = Deno.resources(); - const dir = Deno.makeTempDirSync(); - Deno.createSync(join(dir, "file1.txt")); - Deno.createSync(join(dir, "file2.txt")); - Deno.mkdirSync(join(dir, "some_dir")); - Deno.createSync(join(dir, "some_dir", "file.txt")); - await new Promise<void>((resolve, reject) => { - rmdir(dir, { recursive: true }, (err) => { - if (err) reject(err); - resolve(); - }); - }) - .then(() => assertEquals(existsSync(dir), false), () => fail()) - .finally(() => { - if (existsSync(dir)) Deno.removeSync(dir, { recursive: true }); - const rAfter = Deno.resources(); - closeRes(rBefore, rAfter); - }); - }, - ignore: Deno.build.os === "windows", -}); - -Deno.test({ - name: "SYNC: removing non-empty folder", - fn() { - const rBefore = Deno.resources(); - const dir = Deno.makeTempDirSync(); - Deno.createSync(join(dir, "file1.txt")); - Deno.createSync(join(dir, "file2.txt")); - Deno.mkdirSync(join(dir, "some_dir")); - Deno.createSync(join(dir, "some_dir", "file.txt")); - rmdirSync(dir, { recursive: true }); - assertEquals(existsSync(dir), false); - // closing resources - const rAfter = Deno.resources(); - closeRes(rBefore, rAfter); - }, - ignore: Deno.build.os === "windows", -}); - -Deno.test("[std/node/fs] rmdir callback isn't called twice if error is thrown", async () => { - // The correct behaviour is not to catch any errors thrown, - // but that means there'll be an uncaught error and the test will fail. - // So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code. - // (assertThrowsAsync won't work because there's no way to catch the error.) - const tempDir = await Deno.makeTempDir(); - const importUrl = new URL("./_fs_rmdir.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { rmdir } from ${JSON.stringify(importUrl)}`, - invocation: `rmdir(${JSON.stringify(tempDir)}, `, - }); -}); diff --git a/std/node/_fs/_fs_stat.ts b/std/node/_fs/_fs_stat.ts deleted file mode 100644 index 4f7903d16..000000000 --- a/std/node/_fs/_fs_stat.ts +++ /dev/null @@ -1,289 +0,0 @@ -export type statOptions = { - bigint: boolean; -}; - -export type Stats = { - /** ID of the device containing the file. - * - * _Linux/Mac OS only._ */ - dev: number | null; - /** Inode number. - * - * _Linux/Mac OS only._ */ - ino: number | null; - /** **UNSTABLE**: Match behavior with Go on Windows for `mode`. - * - * The underlying raw `st_mode` bits that contain the standard Unix - * permissions for this file/directory. */ - mode: number | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ - nlink: number | null; - /** User ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - uid: number | null; - /** Group ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - gid: number | null; - /** Device ID of this file. - * - * _Linux/Mac OS only._ */ - rdev: number | null; - /** The size of the file, in bytes. */ - size: number; - /** Blocksize for filesystem I/O. - * - * _Linux/Mac OS only._ */ - blksize: number | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ - blocks: number | null; - /** The last modification time of the file. This corresponds to the `mtime` - * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This - * may not be available on all platforms. */ - mtime: Date | null; - /** The last access time of the file. This corresponds to the `atime` - * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not - * be available on all platforms. */ - atime: Date | null; - /** The creation time of the file. This corresponds to the `birthtime` - * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may - * not be available on all platforms. */ - birthtime: Date | null; - /** change time */ - ctime: Date | null; - /** atime in milliseconds */ - atimeMs: number | null; - /** atime in milliseconds */ - mtimeMs: number | null; - /** atime in milliseconds */ - ctimeMs: number | null; - /** atime in milliseconds */ - birthtimeMs: number | null; - isBlockDevice: () => boolean; - isCharacterDevice: () => boolean; - isDirectory: () => boolean; - isFIFO: () => boolean; - isFile: () => boolean; - isSocket: () => boolean; - isSymbolicLink: () => boolean; -}; - -export type BigIntStats = { - /** ID of the device containing the file. - * - * _Linux/Mac OS only._ */ - dev: BigInt | null; - /** Inode number. - * - * _Linux/Mac OS only._ */ - ino: BigInt | null; - /** **UNSTABLE**: Match behavior with Go on Windows for `mode`. - * - * The underlying raw `st_mode` bits that contain the standard Unix - * permissions for this file/directory. */ - mode: BigInt | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ - nlink: BigInt | null; - /** User ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - uid: BigInt | null; - /** Group ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - gid: BigInt | null; - /** Device ID of this file. - * - * _Linux/Mac OS only._ */ - rdev: BigInt | null; - /** The size of the file, in bytes. */ - size: BigInt; - /** Blocksize for filesystem I/O. - * - * _Linux/Mac OS only._ */ - blksize: BigInt | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ - blocks: BigInt | null; - /** The last modification time of the file. This corresponds to the `mtime` - * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This - * may not be available on all platforms. */ - mtime: Date | null; - /** The last access time of the file. This corresponds to the `atime` - * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not - * be available on all platforms. */ - atime: Date | null; - /** The creation time of the file. This corresponds to the `birthtime` - * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may - * not be available on all platforms. */ - birthtime: Date | null; - /** change time */ - ctime: Date | null; - /** atime in milliseconds */ - atimeMs: BigInt | null; - /** atime in milliseconds */ - mtimeMs: BigInt | null; - /** atime in milliseconds */ - ctimeMs: BigInt | null; - /** atime in nanoseconds */ - birthtimeMs: BigInt | null; - /** atime in nanoseconds */ - atimeNs: BigInt | null; - /** atime in nanoseconds */ - mtimeNs: BigInt | null; - /** atime in nanoseconds */ - ctimeNs: BigInt | null; - /** atime in nanoseconds */ - birthtimeNs: BigInt | null; - isBlockDevice: () => boolean; - isCharacterDevice: () => boolean; - isDirectory: () => boolean; - isFIFO: () => boolean; - isFile: () => boolean; - isSocket: () => boolean; - isSymbolicLink: () => boolean; -}; - -export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { - return { - dev: origin.dev, - ino: origin.ino, - mode: origin.mode, - nlink: origin.nlink, - uid: origin.uid, - gid: origin.gid, - rdev: origin.rdev, - size: origin.size, - blksize: origin.blksize, - blocks: origin.blocks, - mtime: origin.mtime, - atime: origin.atime, - birthtime: origin.birthtime, - mtimeMs: origin.mtime?.getTime() || null, - atimeMs: origin.atime?.getTime() || null, - birthtimeMs: origin.birthtime?.getTime() || null, - isFile: () => origin.isFile, - isDirectory: () => origin.isDirectory, - isSymbolicLink: () => origin.isSymlink, - // not sure about those - isBlockDevice: () => false, - isFIFO: () => false, - isCharacterDevice: () => false, - isSocket: () => false, - ctime: origin.mtime, - ctimeMs: origin.mtime?.getTime() || null, - }; -} - -function toBigInt(number?: number | null) { - if (number === null || number === undefined) return null; - return BigInt(number); -} - -export function convertFileInfoToBigIntStats( - origin: Deno.FileInfo, -): BigIntStats { - return { - dev: toBigInt(origin.dev), - ino: toBigInt(origin.ino), - mode: toBigInt(origin.mode), - nlink: toBigInt(origin.nlink), - uid: toBigInt(origin.uid), - gid: toBigInt(origin.gid), - rdev: toBigInt(origin.rdev), - size: toBigInt(origin.size) || 0n, - blksize: toBigInt(origin.blksize), - blocks: toBigInt(origin.blocks), - mtime: origin.mtime, - atime: origin.atime, - birthtime: origin.birthtime, - mtimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null, - atimeMs: origin.atime ? BigInt(origin.atime.getTime()) : null, - birthtimeMs: origin.birthtime ? BigInt(origin.birthtime.getTime()) : null, - mtimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null, - atimeNs: origin.atime ? BigInt(origin.atime.getTime()) * 1000000n : null, - birthtimeNs: origin.birthtime - ? BigInt(origin.birthtime.getTime()) * 1000000n - : null, - isFile: () => origin.isFile, - isDirectory: () => origin.isDirectory, - isSymbolicLink: () => origin.isSymlink, - // not sure about those - isBlockDevice: () => false, - isFIFO: () => false, - isCharacterDevice: () => false, - isSocket: () => false, - ctime: origin.mtime, - ctimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null, - ctimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null, - }; -} - -// shortcut for Convert File Info to Stats or BigIntStats -export function CFISBIS(fileInfo: Deno.FileInfo, bigInt: boolean) { - if (bigInt) return convertFileInfoToBigIntStats(fileInfo); - return convertFileInfoToStats(fileInfo); -} - -export type statCallbackBigInt = ( - err: Error | null, - stat: BigIntStats, -) => void; - -export type statCallback = (err: Error | null, stat: Stats) => void; - -export function stat(path: string | URL, callback: statCallback): void; -export function stat( - path: string | URL, - options: { bigint: false }, - callback: statCallback, -): void; -export function stat( - path: string | URL, - options: { bigint: true }, - callback: statCallbackBigInt, -): void; -export function stat( - path: string | URL, - optionsOrCallback: statCallback | statCallbackBigInt | statOptions, - maybeCallback?: statCallback | statCallbackBigInt, -) { - const callback = - (typeof optionsOrCallback === "function" - ? optionsOrCallback - : maybeCallback) as ( - ...args: [Error] | [null, BigIntStats | Stats] - ) => void; - const options = typeof optionsOrCallback === "object" - ? optionsOrCallback - : { bigint: false }; - - if (!callback) throw new Error("No callback function supplied"); - - Deno.stat(path).then( - (stat) => callback(null, CFISBIS(stat, options.bigint)), - (err) => callback(err), - ); -} - -export function statSync(path: string | URL): Stats; -export function statSync(path: string | URL, options: { bigint: false }): Stats; -export function statSync( - path: string | URL, - options: { bigint: true }, -): BigIntStats; -export function statSync( - path: string | URL, - options: statOptions = { bigint: false }, -): Stats | BigIntStats { - const origin = Deno.statSync(path); - return CFISBIS(origin, options.bigint); -} diff --git a/std/node/_fs/_fs_stat_test.ts b/std/node/_fs/_fs_stat_test.ts deleted file mode 100644 index 5a25cddcc..000000000 --- a/std/node/_fs/_fs_stat_test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { BigIntStats, stat, Stats, statSync } from "./_fs_stat.ts"; -import { assertEquals, fail } from "../../testing/asserts.ts"; - -export function assertStats(actual: Stats, expected: Deno.FileInfo) { - assertEquals(actual.dev, expected.dev); - assertEquals(actual.gid, expected.gid); - assertEquals(actual.size, expected.size); - assertEquals(actual.blksize, expected.blksize); - assertEquals(actual.blocks, expected.blocks); - assertEquals(actual.ino, expected.ino); - assertEquals(actual.gid, expected.gid); - assertEquals(actual.mode, expected.mode); - assertEquals(actual.nlink, expected.nlink); - assertEquals(actual.rdev, expected.rdev); - assertEquals(actual.uid, expected.uid); - assertEquals(actual.atime?.getTime(), expected.atime?.getTime()); - assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime()); - assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime()); - assertEquals(actual.atimeMs ?? undefined, expected.atime?.getTime()); - assertEquals(actual.mtimeMs ?? undefined, expected.mtime?.getTime()); - assertEquals(actual.birthtimeMs ?? undefined, expected.birthtime?.getTime()); - assertEquals(actual.isFile(), expected.isFile); - assertEquals(actual.isDirectory(), expected.isDirectory); - assertEquals(actual.isSymbolicLink(), expected.isSymlink); -} - -function toBigInt(num?: number | null) { - if (num === undefined || num === null) return null; - return BigInt(num); -} - -export function assertStatsBigInt( - actual: BigIntStats, - expected: Deno.FileInfo, -) { - assertEquals(actual.dev, toBigInt(expected.dev)); - assertEquals(actual.gid, toBigInt(expected.gid)); - assertEquals(actual.size, toBigInt(expected.size)); - assertEquals(actual.blksize, toBigInt(expected.blksize)); - assertEquals(actual.blocks, toBigInt(expected.blocks)); - assertEquals(actual.ino, toBigInt(expected.ino)); - assertEquals(actual.gid, toBigInt(expected.gid)); - assertEquals(actual.mode, toBigInt(expected.mode)); - assertEquals(actual.nlink, toBigInt(expected.nlink)); - assertEquals(actual.rdev, toBigInt(expected.rdev)); - assertEquals(actual.uid, toBigInt(expected.uid)); - assertEquals(actual.atime?.getTime(), expected.atime?.getTime()); - assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime()); - assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime()); - assertEquals( - actual.atimeMs === null ? undefined : Number(actual.atimeMs), - expected.atime?.getTime(), - ); - assertEquals( - actual.mtimeMs === null ? undefined : Number(actual.mtimeMs), - expected.mtime?.getTime(), - ); - assertEquals( - actual.birthtimeMs === null ? undefined : Number(actual.birthtimeMs), - expected.birthtime?.getTime(), - ); - assertEquals(actual.atimeNs === null, actual.atime === null); - assertEquals(actual.mtimeNs === null, actual.mtime === null); - assertEquals(actual.birthtimeNs === null, actual.birthtime === null); - assertEquals(actual.isFile(), expected.isFile); - assertEquals(actual.isDirectory(), expected.isDirectory); - assertEquals(actual.isSymbolicLink(), expected.isSymlink); -} - -Deno.test({ - name: "ASYNC: get a file Stats", - async fn() { - const file = Deno.makeTempFileSync(); - await new Promise<Stats>((resolve, reject) => { - stat(file, (err, stat) => { - if (err) reject(err); - resolve(stat); - }); - }) - .then((stat) => assertStats(stat, Deno.statSync(file)), () => fail()) - .finally(() => Deno.removeSync(file)); - }, -}); - -Deno.test({ - name: "SYNC: get a file Stats", - fn() { - const file = Deno.makeTempFileSync(); - assertStats(statSync(file), Deno.statSync(file)); - }, -}); - -Deno.test({ - name: "ASYNC: get a file BigInt Stats", - async fn() { - const file = Deno.makeTempFileSync(); - await new Promise<BigIntStats>((resolve, reject) => { - stat(file, { bigint: true }, (err, stat) => { - if (err) reject(err); - resolve(stat); - }); - }) - .then( - (stat) => assertStatsBigInt(stat, Deno.statSync(file)), - () => fail(), - ) - .finally(() => Deno.removeSync(file)); - }, -}); - -Deno.test({ - name: "SYNC: get a file BigInt Stats", - fn() { - const file = Deno.makeTempFileSync(); - assertStatsBigInt(statSync(file, { bigint: true }), Deno.statSync(file)); - }, -}); - -Deno.test("[std/node/fs] stat callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_stat.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { stat } from ${JSON.stringify(importUrl)}`, - invocation: `stat(${JSON.stringify(tempFile)}, `, - async cleanup() { - await Deno.remove(tempFile); - }, - }); -}); diff --git a/std/node/_fs/_fs_unlink.ts b/std/node/_fs/_fs_unlink.ts deleted file mode 100644 index 7349bee46..000000000 --- a/std/node/_fs/_fs_unlink.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function unlink(path: string | URL, callback: (err?: Error) => void) { - if (!callback) throw new Error("No callback function supplied"); - Deno.remove(path).then((_) => callback(), callback); -} - -export function unlinkSync(path: string | URL) { - Deno.removeSync(path); -} diff --git a/std/node/_fs/_fs_unlink_test.ts b/std/node/_fs/_fs_unlink_test.ts deleted file mode 100644 index 5021b1c38..000000000 --- a/std/node/_fs/_fs_unlink_test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { assertEquals, fail } from "../../testing/asserts.ts"; -import { existsSync } from "../../fs/mod.ts"; -import { assertCallbackErrorUncaught } from "../_utils.ts"; -import { unlink, unlinkSync } from "./_fs_unlink.ts"; - -Deno.test({ - name: "ASYNC: deleting a file", - async fn() { - const file = Deno.makeTempFileSync(); - await new Promise<void>((resolve, reject) => { - unlink(file, (err) => { - if (err) reject(err); - resolve(); - }); - }) - .then(() => assertEquals(existsSync(file), false), () => fail()) - .finally(() => { - if (existsSync(file)) Deno.removeSync(file); - }); - }, -}); - -Deno.test({ - name: "SYNC: Test deleting a file", - fn() { - const file = Deno.makeTempFileSync(); - unlinkSync(file); - assertEquals(existsSync(file), false); - }, -}); - -Deno.test("[std/node/fs] unlink callback isn't called twice if error is thrown", async () => { - const tempFile = await Deno.makeTempFile(); - const importUrl = new URL("./_fs_unlink.ts", import.meta.url); - await assertCallbackErrorUncaught({ - prelude: `import { unlink } from ${JSON.stringify(importUrl)}`, - invocation: `unlink(${JSON.stringify(tempFile)}, `, - }); -}); diff --git a/std/node/_fs/_fs_watch.ts b/std/node/_fs/_fs_watch.ts deleted file mode 100644 index a5f3bb9c1..000000000 --- a/std/node/_fs/_fs_watch.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { fromFileUrl } from "../path.ts"; -import { EventEmitter } from "../events.ts"; -import { notImplemented } from "../_utils.ts"; - -export function asyncIterableIteratorToCallback<T>( - iterator: AsyncIterableIterator<T>, - callback: (val: T, done?: boolean) => void, -) { - function next() { - iterator.next().then((obj) => { - if (obj.done) { - callback(obj.value, true); - return; - } - callback(obj.value); - next(); - }); - } - next(); -} - -export function asyncIterableToCallback<T>( - iter: AsyncIterable<T>, - callback: (val: T, done?: boolean) => void, -) { - const iterator = iter[Symbol.asyncIterator](); - function next() { - iterator.next().then((obj) => { - if (obj.done) { - callback(obj.value, true); - return; - } - callback(obj.value); - next(); - }); - } - next(); -} - -type watchOptions = { - persistent?: boolean; - recursive?: boolean; - encoding?: string; -}; - -type watchListener = (eventType: string, filename: string) => void; - -export function watch( - filename: string | URL, - options: watchOptions, - listener: watchListener, -): FSWatcher; -export function watch( - filename: string | URL, - listener: watchListener, -): FSWatcher; -export function watch( - filename: string | URL, - options: watchOptions, -): FSWatcher; -export function watch(filename: string | URL): FSWatcher; -export function watch( - filename: string | URL, - optionsOrListener?: watchOptions | watchListener, - optionsOrListener2?: watchOptions | watchListener, -) { - const listener = typeof optionsOrListener === "function" - ? optionsOrListener - : typeof optionsOrListener2 === "function" - ? optionsOrListener2 - : undefined; - const options = typeof optionsOrListener === "object" - ? optionsOrListener - : typeof optionsOrListener2 === "object" - ? optionsOrListener2 - : undefined; - filename = filename instanceof URL ? fromFileUrl(filename) : filename; - - const iterator = Deno.watchFs(filename, { - recursive: options?.recursive || false, - }); - - if (!listener) throw new Error("No callback function supplied"); - - const fsWatcher = new FSWatcher(() => { - if (iterator.return) iterator.return(); - }); - - fsWatcher.on("change", listener); - - asyncIterableIteratorToCallback<Deno.FsEvent>(iterator, (val, done) => { - if (done) return; - fsWatcher.emit("change", val.kind, val.paths[0]); - }); - - return fsWatcher; -} - -class FSWatcher extends EventEmitter { - close: () => void; - constructor(closer: () => void) { - super(); - this.close = closer; - } - ref() { - notImplemented("FSWatcher.ref() is not implemented"); - } - unref() { - notImplemented("FSWatcher.unref() is not implemented"); - } -} diff --git a/std/node/_fs/_fs_watch_test.ts b/std/node/_fs/_fs_watch_test.ts deleted file mode 100644 index 00fce4ffd..000000000 --- a/std/node/_fs/_fs_watch_test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { watch } from "./_fs_watch.ts"; -import { assertEquals, fail } from "../../testing/asserts.ts"; - -function wait(time: number) { - return new Promise((resolve) => { - setTimeout(resolve, time); - }); -} - -Deno.test({ - name: "watching a file", - async fn() { - const file = Deno.makeTempFileSync(); - const result: Array<[string, string]> = []; - const watcher = watch( - file, - (eventType, filename) => result.push([eventType, filename]), - ); - await wait(100); - Deno.writeTextFileSync(file, "something"); - await wait(100); - watcher.close(); - await wait(100); - assertEquals(result.length >= 1, true); - }, -}); diff --git a/std/node/_fs/_fs_writeFile.ts b/std/node/_fs/_fs_writeFile.ts deleted file mode 100644 index e68bd8884..000000000 --- a/std/node/_fs/_fs_writeFile.ts +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { Encodings, notImplemented } from "../_utils.ts"; -import { fromFileUrl } from "../path.ts"; -import { Buffer } from "../buffer.ts"; -import { - CallbackWithError, - checkEncoding, - getEncoding, - getOpenOptions, - isFileOptions, - WriteFileOptions, -} from "./_fs_common.ts"; - -export function writeFile( - pathOrRid: string | number | URL, - data: string | Uint8Array, - optOrCallback: Encodings | CallbackWithError | WriteFileOptions | undefined, - callback?: CallbackWithError, -): void { - const callbackFn: CallbackWithError | undefined = - optOrCallback instanceof Function ? optOrCallback : callback; - const options: Encodings | WriteFileOptions | undefined = - optOrCallback instanceof Function ? undefined : optOrCallback; - - if (!callbackFn) { - throw new TypeError("Callback must be a function."); - } - - pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; - - const flag: string | undefined = isFileOptions(options) - ? options.flag - : undefined; - - const mode: number | undefined = isFileOptions(options) - ? options.mode - : undefined; - - const encoding = checkEncoding(getEncoding(options)) || "utf8"; - const openOptions = getOpenOptions(flag || "w"); - - if (typeof data === "string") data = Buffer.from(data, encoding); - - const isRid = typeof pathOrRid === "number"; - let file; - - let error: Error | null = null; - (async (): Promise<void> => { - try { - file = isRid - ? new Deno.File(pathOrRid as number) - : await Deno.open(pathOrRid as string, openOptions); - - if (!isRid && mode) { - if (Deno.build.os === "windows") notImplemented(`"mode" on Windows`); - await Deno.chmod(pathOrRid as string, mode); - } - - await Deno.writeAll(file, data as Uint8Array); - } catch (e) { - error = e; - } finally { - // Make sure to close resource - if (!isRid && file) file.close(); - callbackFn(error); - } - })(); -} - -export function writeFileSync( - pathOrRid: string | number | URL, - data: string | Uint8Array, - options?: Encodings | WriteFileOptions, -): void { - pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; - - const flag: string | undefined = isFileOptions(options) - ? options.flag - : undefined; - - const mode: number | undefined = isFileOptions(options) - ? options.mode - : undefined; - - const encoding = checkEncoding(getEncoding(options)) || "utf8"; - const openOptions = getOpenOptions(flag || "w"); - - if (typeof data === "string") data = Buffer.from(data, encoding); - - const isRid = typeof pathOrRid === "number"; - let file; - - let error: Error | null = null; - try { - file = isRid - ? new Deno.File(pathOrRid as number) - : Deno.openSync(pathOrRid as string, openOptions); - - if (!isRid && mode) { - if (Deno.build.os === "windows") notImplemented(`"mode" on Windows`); - Deno.chmodSync(pathOrRid as string, mode); - } - - Deno.writeAllSync(file, data as Uint8Array); - } catch (e) { - error = e; - } finally { - // Make sure to close resource - if (!isRid && file) file.close(); - - if (error) throw error; - } -} diff --git a/std/node/_fs/_fs_writeFile_test.ts b/std/node/_fs/_fs_writeFile_test.ts deleted file mode 100644 index 561f71f88..000000000 --- a/std/node/_fs/_fs_writeFile_test.ts +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertNotEquals, - assertThrows, -} from "../../testing/asserts.ts"; -import { writeFile, writeFileSync } from "./_fs_writeFile.ts"; -import type { TextEncodings } from "../_utils.ts"; -import * as path from "../../path/mod.ts"; - -const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); -const testDataDir = path.resolve(moduleDir, "testdata"); -const decoder = new TextDecoder("utf-8"); - -Deno.test("Callback must be a function error", function fn() { - assertThrows( - () => { - writeFile("some/path", "some data", "utf8"); - }, - TypeError, - "Callback must be a function.", - ); -}); - -Deno.test("Invalid encoding results in error()", function testEncodingErrors() { - assertThrows( - () => { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - writeFile("some/path", "some data", "made-up-encoding", () => {}); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); - - assertThrows( - () => { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - writeFileSync("some/path", "some data", "made-up-encoding"); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); - - assertThrows( - () => { - writeFile( - "some/path", - "some data", - { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - encoding: "made-up-encoding", - }, - () => {}, - ); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); - - assertThrows( - () => { - writeFileSync("some/path", "some data", { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - encoding: "made-up-encoding", - }); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); -}); - -Deno.test( - "Unsupported encoding results in error()", - function testUnsupportedEncoding() { - assertThrows( - () => { - writeFile("some/path", "some data", "utf16le", () => {}); - }, - Error, - `Not implemented: "utf16le" encoding`, - ); - - assertThrows( - () => { - writeFileSync("some/path", "some data", "utf16le"); - }, - Error, - `Not implemented: "utf16le" encoding`, - ); - }, -); - -Deno.test( - "Data is written to correct rid", - async function testCorrectWriteUsingRid() { - const tempFile: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(tempFile, { - create: true, - write: true, - read: true, - }); - - await new Promise<void>((resolve, reject) => { - writeFile(file.rid, "hello world", (err) => { - if (err) return reject(err); - resolve(); - }); - }); - Deno.close(file.rid); - - const data = await Deno.readFile(tempFile); - await Deno.remove(tempFile); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test( - "Data is written to correct file", - async function testCorrectWriteUsingPath() { - const res = await new Promise((resolve) => { - writeFile("_fs_writeFile_test_file.txt", "hello world", resolve); - }); - - const data = await Deno.readFile("_fs_writeFile_test_file.txt"); - await Deno.remove("_fs_writeFile_test_file.txt"); - assertEquals(res, null); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test( - "Data is written to correct file encodings", - async function testCorrectWriteUsingDifferentEncodings() { - const encodings = [ - ["hex", "68656c6c6f20776f726c64"], - ["HEX", "68656c6c6f20776f726c64"], - ["base64", "aGVsbG8gd29ybGQ="], - ["BASE64", "aGVsbG8gd29ybGQ="], - ["utf8", "hello world"], - ["utf-8", "hello world"], - ]; - - for (const [encoding, value] of encodings) { - const res = await new Promise((resolve) => { - writeFile( - "_fs_writeFile_test_file.txt", - value, - encoding as TextEncodings, - resolve, - ); - }); - - const data = await Deno.readFile("_fs_writeFile_test_file.txt"); - await Deno.remove("_fs_writeFile_test_file.txt"); - assertEquals(res, null); - assertEquals(decoder.decode(data), "hello world"); - } - }, -); - -Deno.test("Path can be an URL", async function testCorrectWriteUsingURL() { - const url = new URL( - Deno.build.os === "windows" - ? "file:///" + - path - .join(testDataDir, "_fs_writeFile_test_file_url.txt") - .replace(/\\/g, "/") - : "file://" + path.join(testDataDir, "_fs_writeFile_test_file_url.txt"), - ); - const filePath = path.fromFileUrl(url); - const res = await new Promise((resolve) => { - writeFile(url, "hello world", resolve); - }); - assert(res === null); - - const data = await Deno.readFile(filePath); - await Deno.remove(filePath); - assertEquals(res, null); - assertEquals(decoder.decode(data), "hello world"); -}); - -Deno.test("Mode is correctly set", async function testCorrectFileMode() { - if (Deno.build.os === "windows") return; - const filename = "_fs_writeFile_test_file.txt"; - - const res = await new Promise((resolve) => { - writeFile(filename, "hello world", { mode: 0o777 }, resolve); - }); - - const fileInfo = await Deno.stat(filename); - await Deno.remove(filename); - assertEquals(res, null); - assert(fileInfo && fileInfo.mode); - assertEquals(fileInfo.mode & 0o777, 0o777); -}); - -Deno.test( - "Mode is not set when rid is passed", - async function testCorrectFileModeRid() { - if (Deno.build.os === "windows") return; - - const filename: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(filename, { - create: true, - write: true, - read: true, - }); - - await new Promise<void>((resolve, reject) => { - writeFile(file.rid, "hello world", { mode: 0o777 }, (err) => { - if (err) return reject(err); - resolve(); - }); - }); - Deno.close(file.rid); - - const fileInfo = await Deno.stat(filename); - await Deno.remove(filename); - assert(fileInfo.mode); - assertNotEquals(fileInfo.mode & 0o777, 0o777); - }, -); - -Deno.test( - "Data is written synchronously to correct rid", - function testCorrectWriteSyncUsingRid() { - const tempFile: string = Deno.makeTempFileSync(); - const file: Deno.File = Deno.openSync(tempFile, { - create: true, - write: true, - read: true, - }); - - writeFileSync(file.rid, "hello world"); - Deno.close(file.rid); - - const data = Deno.readFileSync(tempFile); - Deno.removeSync(tempFile); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test( - "Data is written to correct file encodings", - function testCorrectWriteSyncUsingDifferentEncodings() { - const encodings = [ - ["hex", "68656c6c6f20776f726c64"], - ["HEX", "68656c6c6f20776f726c64"], - ["base64", "aGVsbG8gd29ybGQ="], - ["BASE64", "aGVsbG8gd29ybGQ="], - ["utf8", "hello world"], - ["utf-8", "hello world"], - ]; - - for (const [encoding, value] of encodings) { - const file = "_fs_writeFileSync_test_file"; - writeFileSync(file, value, encoding as TextEncodings); - - const data = Deno.readFileSync(file); - Deno.removeSync(file); - assertEquals(decoder.decode(data), "hello world"); - } - }, -); - -Deno.test( - "Data is written synchronously to correct file", - function testCorrectWriteSyncUsingPath() { - const file = "_fs_writeFileSync_test_file"; - - writeFileSync(file, "hello world"); - - const data = Deno.readFileSync(file); - Deno.removeSync(file); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test("sync: Path can be an URL", function testCorrectWriteSyncUsingURL() { - const filePath = path.join( - testDataDir, - "_fs_writeFileSync_test_file_url.txt", - ); - const url = new URL( - Deno.build.os === "windows" - ? "file:///" + filePath.replace(/\\/g, "/") - : "file://" + filePath, - ); - writeFileSync(url, "hello world"); - - const data = Deno.readFileSync(filePath); - Deno.removeSync(filePath); - assertEquals(decoder.decode(data), "hello world"); -}); - -Deno.test( - "Mode is correctly set when writing synchronously", - function testCorrectFileModeSync() { - if (Deno.build.os === "windows") return; - const filename = "_fs_writeFileSync_test_file.txt"; - - writeFileSync(filename, "hello world", { mode: 0o777 }); - - const fileInfo = Deno.statSync(filename); - Deno.removeSync(filename); - assert(fileInfo && fileInfo.mode); - assertEquals(fileInfo.mode & 0o777, 0o777); - }, -); diff --git a/std/node/_fs/promises/_fs_readFile.ts b/std/node/_fs/promises/_fs_readFile.ts deleted file mode 100644 index 3067b301f..000000000 --- a/std/node/_fs/promises/_fs_readFile.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { - BinaryOptionsArgument, - FileOptionsArgument, - TextOptionsArgument, -} from "../_fs_common.ts"; -import { readFile as readFileCallback } from "../_fs_readFile.ts"; - -export function readFile( - path: string | URL, - options: TextOptionsArgument, -): Promise<string>; -export function readFile( - path: string | URL, - options?: BinaryOptionsArgument, -): Promise<Uint8Array>; -export function readFile( - path: string | URL, - options?: FileOptionsArgument, -): Promise<string | Uint8Array> { - return new Promise((resolve, reject) => { - readFileCallback(path, options, (err, data): void => { - if (err) return reject(err); - if (data == null) { - return reject(new Error("Invalid state: data missing, but no error")); - } - resolve(data); - }); - }); -} diff --git a/std/node/_fs/promises/_fs_readFile_test.ts b/std/node/_fs/promises/_fs_readFile_test.ts deleted file mode 100644 index 2810d1773..000000000 --- a/std/node/_fs/promises/_fs_readFile_test.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { readFile } from "./_fs_readFile.ts"; -import * as path from "../../../path/mod.ts"; -import { assert, assertEquals } from "../../../testing/asserts.ts"; - -const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); -const testData = path.resolve(moduleDir, "..", "testdata", "hello.txt"); - -Deno.test("readFileSuccess", async function () { - const data: Uint8Array = await readFile(testData); - - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data), "hello world"); -}); - -Deno.test("readFileBinarySuccess", async function () { - const data: Uint8Array = await readFile(testData, "binary"); - - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data), "hello world"); -}); - -Deno.test("readFileBinaryObjectSuccess", async function () { - const data: Uint8Array = await readFile(testData, { encoding: "binary" }); - - assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data), "hello world"); -}); - -Deno.test("readFileStringObjectSuccess", async function () { - const data: string = await readFile(testData, { encoding: "utf8" }); - - assertEquals(typeof data, "string"); - assertEquals(data, "hello world"); -}); - -Deno.test("readFileEncodeHexSuccess", async function () { - const data: string = await readFile(testData, { encoding: "hex" }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "68656c6c6f20776f726c64"); -}); - -Deno.test("readFileEncodeBase64Success", async function () { - const data: string = await readFile(testData, { encoding: "base64" }); - assertEquals(typeof data, "string"); - assertEquals(data as string, "aGVsbG8gd29ybGQ="); -}); - -Deno.test("readFileStringSuccess", async function () { - const data: string = await readFile(testData, "utf8"); - - assertEquals(typeof data, "string"); - assertEquals(data, "hello world"); -}); - -Deno.test("readFileError", async function () { - try { - await readFile("invalid-file", "utf8"); - } catch (e) { - assert(e instanceof Deno.errors.NotFound); - } -}); diff --git a/std/node/_fs/promises/_fs_writeFile.ts b/std/node/_fs/promises/_fs_writeFile.ts deleted file mode 100644 index 554b65d24..000000000 --- a/std/node/_fs/promises/_fs_writeFile.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { WriteFileOptions } from "../_fs_common.ts"; -import type { Encodings } from "../../_utils.ts"; - -import { writeFile as writeFileCallback } from "../_fs_writeFile.ts"; - -export function writeFile( - pathOrRid: string | number | URL, - data: string | Uint8Array, - options?: Encodings | WriteFileOptions, -): Promise<void> { - return new Promise((resolve, reject) => { - writeFileCallback(pathOrRid, data, options, (err?: Error | null) => { - if (err) return reject(err); - resolve(); - }); - }); -} diff --git a/std/node/_fs/promises/_fs_writeFile_test.ts b/std/node/_fs/promises/_fs_writeFile_test.ts deleted file mode 100644 index 644a416ca..000000000 --- a/std/node/_fs/promises/_fs_writeFile_test.ts +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertNotEquals, - assertThrowsAsync, -} from "../../../testing/asserts.ts"; -import { writeFile } from "./_fs_writeFile.ts"; -import type { TextEncodings } from "../../_utils.ts"; - -const decoder = new TextDecoder("utf-8"); - -Deno.test("Invalid encoding results in error()", function testEncodingErrors() { - assertThrowsAsync( - async () => { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - await writeFile("some/path", "some data", "made-up-encoding"); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); - assertThrowsAsync( - async () => { - await writeFile("some/path", "some data", { - // @ts-expect-error Type '"made-up-encoding"' is not assignable to type - encoding: "made-up-encoding", - }); - }, - Error, - `The value "made-up-encoding" is invalid for option "encoding"`, - ); -}); - -Deno.test( - "Unsupported encoding results in error()", - function testUnsupportedEncoding() { - assertThrowsAsync( - async () => { - await writeFile("some/path", "some data", "utf16le"); - }, - Error, - `Not implemented: "utf16le" encoding`, - ); - }, -); - -Deno.test( - "Data is written to correct rid", - async function testCorrectWriteUsingRid() { - const tempFile: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(tempFile, { - create: true, - write: true, - read: true, - }); - - await writeFile(file.rid, "hello world"); - Deno.close(file.rid); - - const data = await Deno.readFile(tempFile); - await Deno.remove(tempFile); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test( - "Data is written to correct file", - async function testCorrectWriteUsingPath() { - const openResourcesBeforeWrite: Deno.ResourceMap = Deno.resources(); - - await writeFile("_fs_writeFile_test_file.txt", "hello world"); - - assertEquals(Deno.resources(), openResourcesBeforeWrite); - const data = await Deno.readFile("_fs_writeFile_test_file.txt"); - await Deno.remove("_fs_writeFile_test_file.txt"); - assertEquals(decoder.decode(data), "hello world"); - }, -); - -Deno.test( - "Data is written to correct file encodings", - async function testCorrectWritePromiseUsingDifferentEncodings() { - const encodings = [ - ["hex", "68656c6c6f20776f726c64"], - ["HEX", "68656c6c6f20776f726c64"], - ["base64", "aGVsbG8gd29ybGQ="], - ["BASE64", "aGVsbG8gd29ybGQ="], - ["utf8", "hello world"], - ["utf-8", "hello world"], - ]; - - for (const [encoding, value] of encodings) { - await writeFile( - "_fs_writeFile_test_file.txt", - value, - encoding as TextEncodings, - ); - - const data = await Deno.readFile("_fs_writeFile_test_file.txt"); - await Deno.remove("_fs_writeFile_test_file.txt"); - assertEquals(decoder.decode(data), "hello world"); - } - }, -); - -Deno.test("Mode is correctly set", async function testCorrectFileMode() { - if (Deno.build.os === "windows") return; - const filename = "_fs_writeFile_test_file.txt"; - await writeFile(filename, "hello world", { mode: 0o777 }); - - const fileInfo = await Deno.stat(filename); - await Deno.remove(filename); - assert(fileInfo && fileInfo.mode); - assertEquals(fileInfo.mode & 0o777, 0o777); -}); - -Deno.test( - "Mode is not set when rid is passed", - async function testCorrectFileModeRid() { - if (Deno.build.os === "windows") return; - - const filename: string = await Deno.makeTempFile(); - const file: Deno.File = await Deno.open(filename, { - create: true, - write: true, - read: true, - }); - - await writeFile(file.rid, "hello world", { mode: 0o777 }); - Deno.close(file.rid); - - const fileInfo = await Deno.stat(filename); - await Deno.remove(filename); - assert(fileInfo.mode); - assertNotEquals(fileInfo.mode & 0o777, 0o777); - }, -); diff --git a/std/node/_fs/promises/mod.ts b/std/node/_fs/promises/mod.ts deleted file mode 100644 index 4cc6462b9..000000000 --- a/std/node/_fs/promises/mod.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { writeFile } from "./_fs_writeFile.ts"; -export { readFile } from "./_fs_readFile.ts"; diff --git a/std/node/_fs/testdata/hello.txt b/std/node/_fs/testdata/hello.txt deleted file mode 100644 index 95d09f2b1..000000000 --- a/std/node/_fs/testdata/hello.txt +++ /dev/null @@ -1 +0,0 @@ -hello world
\ No newline at end of file diff --git a/std/node/_stream/async_iterator.ts b/std/node/_stream/async_iterator.ts deleted file mode 100644 index 5369ef39c..000000000 --- a/std/node/_stream/async_iterator.ts +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import type { Buffer } from "../buffer.ts"; -import finished from "./end_of_stream.ts"; -import Readable from "./readable.ts"; -import type Stream from "./stream.ts"; -import { destroyer } from "./destroy.ts"; - -const kLastResolve = Symbol("lastResolve"); -const kLastReject = Symbol("lastReject"); -const kError = Symbol("error"); -const kEnded = Symbol("ended"); -const kLastPromise = Symbol("lastPromise"); -const kHandlePromise = Symbol("handlePromise"); -const kStream = Symbol("stream"); - -// TODO(Soremwar) -// Add Duplex streams -type IterableStreams = Stream | Readable; - -type IterableItem = Buffer | string | Uint8Array | undefined; -type ReadableIteratorResult = IteratorResult<IterableItem>; - -function initIteratorSymbols( - o: ReadableStreamAsyncIterator, - symbols: symbol[], -) { - const properties: PropertyDescriptorMap = {}; - for (const sym in symbols) { - properties[sym] = { - configurable: false, - enumerable: false, - writable: true, - }; - } - Object.defineProperties(o, properties); -} - -function createIterResult( - value: IterableItem, - done: boolean, -): ReadableIteratorResult { - return { value, done }; -} - -function readAndResolve(iter: ReadableStreamAsyncIterator) { - const resolve = iter[kLastResolve]; - if (resolve !== null) { - const data = iter[kStream].read(); - if (data !== null) { - iter[kLastPromise] = null; - iter[kLastResolve] = null; - iter[kLastReject] = null; - resolve(createIterResult(data, false)); - } - } -} - -function onReadable(iter: ReadableStreamAsyncIterator) { - queueMicrotask(() => readAndResolve(iter)); -} - -function wrapForNext( - lastPromise: Promise<ReadableIteratorResult>, - iter: ReadableStreamAsyncIterator, -) { - return ( - resolve: (value: ReadableIteratorResult) => void, - reject: (error: Error) => void, - ) => { - lastPromise.then(() => { - if (iter[kEnded]) { - resolve(createIterResult(undefined, true)); - return; - } - - iter[kHandlePromise](resolve, reject); - }, reject); - }; -} - -function finish(self: ReadableStreamAsyncIterator, err?: Error) { - return new Promise( - ( - resolve: (result: ReadableIteratorResult) => void, - reject: (error: Error) => void, - ) => { - const stream = self[kStream]; - - finished(stream, (err) => { - if (err && err.code !== "ERR_STREAM_PREMATURE_CLOSE") { - reject(err); - } else { - resolve(createIterResult(undefined, true)); - } - }); - destroyer(stream, err); - }, - ); -} - -const AsyncIteratorPrototype = Object.getPrototypeOf( - Object.getPrototypeOf(async function* () {}).prototype, -); - -export class ReadableStreamAsyncIterator - implements AsyncIterableIterator<IterableItem> { - [kEnded]: boolean; - [kError]: Error | null = null; - [kHandlePromise] = ( - resolve: (value: ReadableIteratorResult) => void, - reject: (value: Error) => void, - ) => { - const data = this[kStream].read(); - if (data) { - this[kLastPromise] = null; - this[kLastResolve] = null; - this[kLastReject] = null; - resolve(createIterResult(data, false)); - } else { - this[kLastResolve] = resolve; - this[kLastReject] = reject; - } - }; - [kLastPromise]: null | Promise<ReadableIteratorResult>; - [kLastReject]: null | ((value: Error) => void) = null; - [kLastResolve]: null | ((value: ReadableIteratorResult) => void) = null; - [kStream]: Readable; - [Symbol.asyncIterator] = AsyncIteratorPrototype[Symbol.asyncIterator]; - - constructor(stream: Readable) { - this[kEnded] = stream.readableEnded || stream._readableState.endEmitted; - this[kStream] = stream; - initIteratorSymbols(this, [ - kEnded, - kError, - kHandlePromise, - kLastPromise, - kLastReject, - kLastResolve, - kStream, - ]); - } - - get stream() { - return this[kStream]; - } - - next(): Promise<ReadableIteratorResult> { - const error = this[kError]; - if (error !== null) { - return Promise.reject(error); - } - - if (this[kEnded]) { - return Promise.resolve(createIterResult(undefined, true)); - } - - if (this[kStream].destroyed) { - return new Promise((resolve, reject) => { - if (this[kError]) { - reject(this[kError]); - } else if (this[kEnded]) { - resolve(createIterResult(undefined, true)); - } else { - finished(this[kStream], (err) => { - if (err && err.code !== "ERR_STREAM_PREMATURE_CLOSE") { - reject(err); - } else { - resolve(createIterResult(undefined, true)); - } - }); - } - }); - } - - const lastPromise = this[kLastPromise]; - let promise; - - if (lastPromise) { - promise = new Promise(wrapForNext(lastPromise, this)); - } else { - const data = this[kStream].read(); - if (data !== null) { - return Promise.resolve(createIterResult(data, false)); - } - - promise = new Promise(this[kHandlePromise]); - } - - this[kLastPromise] = promise; - - return promise; - } - - return(): Promise<ReadableIteratorResult> { - return finish(this); - } - - throw(err: Error): Promise<ReadableIteratorResult> { - return finish(this, err); - } -} - -const createReadableStreamAsyncIterator = (stream: IterableStreams) => { - // deno-lint-ignore no-explicit-any - if (typeof (stream as any).read !== "function") { - const src = stream; - stream = new Readable({ objectMode: true }).wrap(src); - finished(stream, (err) => destroyer(src, err)); - } - - const iterator = new ReadableStreamAsyncIterator(stream as Readable); - iterator[kLastPromise] = null; - - finished(stream, { writable: false }, (err) => { - if (err && err.code !== "ERR_STREAM_PREMATURE_CLOSE") { - const reject = iterator[kLastReject]; - if (reject !== null) { - iterator[kLastPromise] = null; - iterator[kLastResolve] = null; - iterator[kLastReject] = null; - reject(err); - } - iterator[kError] = err; - return; - } - - const resolve = iterator[kLastResolve]; - if (resolve !== null) { - iterator[kLastPromise] = null; - iterator[kLastResolve] = null; - iterator[kLastReject] = null; - resolve(createIterResult(undefined, true)); - } - iterator[kEnded] = true; - }); - - stream.on("readable", onReadable.bind(null, iterator)); - - return iterator; -}; - -export default createReadableStreamAsyncIterator; diff --git a/std/node/_stream/async_iterator_test.ts b/std/node/_stream/async_iterator_test.ts deleted file mode 100644 index 17698e0fd..000000000 --- a/std/node/_stream/async_iterator_test.ts +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import Readable from "./readable.ts"; -import Stream from "./stream.ts"; -import toReadableAsyncIterator from "./async_iterator.ts"; -import { deferred } from "../../async/mod.ts"; -import { assertEquals, assertThrowsAsync } from "../../testing/asserts.ts"; - -Deno.test("Stream to async iterator", async () => { - let destroyExecuted = 0; - const destroyExecutedExpected = 1; - const destroyExpectedExecutions = deferred(); - - class AsyncIteratorStream extends Stream { - constructor() { - super(); - } - - destroy() { - destroyExecuted++; - if (destroyExecuted == destroyExecutedExpected) { - destroyExpectedExecutions.resolve(); - } - } - - [Symbol.asyncIterator] = Readable.prototype[Symbol.asyncIterator]; - } - - const stream = new AsyncIteratorStream(); - - queueMicrotask(() => { - stream.emit("data", "hello"); - stream.emit("data", "world"); - stream.emit("end"); - }); - - let res = ""; - - for await (const d of stream) { - res += d; - } - assertEquals(res, "helloworld"); - - const destroyTimeout = setTimeout( - () => destroyExpectedExecutions.reject(), - 1000, - ); - await destroyExpectedExecutions; - clearTimeout(destroyTimeout); - assertEquals(destroyExecuted, destroyExecutedExpected); -}); - -Deno.test("Stream to async iterator throws on 'error' emitted", async () => { - let closeExecuted = 0; - const closeExecutedExpected = 1; - const closeExpectedExecutions = deferred(); - - let errorExecuted = 0; - const errorExecutedExpected = 1; - const errorExpectedExecutions = deferred(); - - class StreamImplementation extends Stream { - close() { - closeExecuted++; - if (closeExecuted == closeExecutedExpected) { - closeExpectedExecutions.resolve(); - } - } - } - - const stream = new StreamImplementation(); - queueMicrotask(() => { - stream.emit("data", 0); - stream.emit("data", 1); - stream.emit("error", new Error("asd")); - }); - - toReadableAsyncIterator(stream) - .next() - .catch((err) => { - errorExecuted++; - if (errorExecuted == errorExecutedExpected) { - errorExpectedExecutions.resolve(); - } - assertEquals(err.message, "asd"); - }); - - const closeTimeout = setTimeout( - () => closeExpectedExecutions.reject(), - 1000, - ); - const errorTimeout = setTimeout( - () => errorExpectedExecutions.reject(), - 1000, - ); - await closeExpectedExecutions; - await errorExpectedExecutions; - clearTimeout(closeTimeout); - clearTimeout(errorTimeout); - assertEquals(closeExecuted, closeExecutedExpected); - assertEquals(errorExecuted, errorExecutedExpected); -}); - -Deno.test("Async iterator matches values of Readable", async () => { - const readable = new Readable({ - objectMode: true, - read() {}, - }); - readable.push(0); - readable.push(1); - readable.push(null); - - const iter = readable[Symbol.asyncIterator](); - - assertEquals( - await iter.next().then(({ value }) => value), - 0, - ); - for await (const d of iter) { - assertEquals(d, 1); - } -}); - -Deno.test("Async iterator throws on Readable destroyed sync", async () => { - const message = "kaboom from read"; - - const readable = new Readable({ - objectMode: true, - read() { - this.destroy(new Error(message)); - }, - }); - - await assertThrowsAsync( - async () => { - // deno-lint-ignore no-empty - for await (const k of readable) {} - }, - Error, - message, - ); -}); - -Deno.test("Async iterator throws on Readable destroyed async", async () => { - const message = "kaboom"; - const readable = new Readable({ - read() {}, - }); - const iterator = readable[Symbol.asyncIterator](); - - readable.destroy(new Error(message)); - - await assertThrowsAsync( - iterator.next.bind(iterator), - Error, - message, - ); -}); - -Deno.test("Async iterator finishes the iterator when Readable destroyed", async () => { - const readable = new Readable({ - read() {}, - }); - - readable.destroy(); - - const { done } = await readable[Symbol.asyncIterator]().next(); - assertEquals(done, true); -}); - -Deno.test("Async iterator finishes all item promises when Readable destroyed", async () => { - const r = new Readable({ - objectMode: true, - read() { - }, - }); - - const b = r[Symbol.asyncIterator](); - const c = b.next(); - const d = b.next(); - r.destroy(); - assertEquals(await c, { done: true, value: undefined }); - assertEquals(await d, { done: true, value: undefined }); -}); - -Deno.test("Async iterator: 'next' is triggered by Readable push", async () => { - const max = 42; - let readed = 0; - let received = 0; - const readable = new Readable({ - objectMode: true, - read() { - this.push("hello"); - if (++readed === max) { - this.push(null); - } - }, - }); - - for await (const k of readable) { - received++; - assertEquals(k, "hello"); - } - - assertEquals(readed, received); -}); - -Deno.test("Async iterator: 'close' called on forced iteration end", async () => { - let closeExecuted = 0; - const closeExecutedExpected = 1; - const closeExpectedExecutions = deferred(); - - class IndestructibleReadable extends Readable { - constructor() { - super({ - autoDestroy: false, - read() {}, - }); - } - - close() { - closeExecuted++; - if (closeExecuted == closeExecutedExpected) { - closeExpectedExecutions.resolve(); - } - readable.emit("close"); - } - - // deno-lint-ignore ban-ts-comment - //@ts-ignore - destroy = null; - } - - const readable = new IndestructibleReadable(); - readable.push("asd"); - readable.push("asd"); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const d of readable) { - break; - } - - const closeTimeout = setTimeout( - () => closeExpectedExecutions.reject(), - 1000, - ); - await closeExpectedExecutions; - clearTimeout(closeTimeout); - assertEquals(closeExecuted, closeExecutedExpected); -}); diff --git a/std/node/_stream/buffer_list.ts b/std/node/_stream/buffer_list.ts deleted file mode 100644 index fe1a693c0..000000000 --- a/std/node/_stream/buffer_list.ts +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; - -type BufferListItem = { - data: Buffer | string | Uint8Array; - next: BufferListItem | null; -}; - -export default class BufferList { - head: BufferListItem | null = null; - tail: BufferListItem | null = null; - length: number; - - constructor() { - this.head = null; - this.tail = null; - this.length = 0; - } - - push(v: Buffer | string | Uint8Array) { - const entry = { data: v, next: null }; - if (this.length > 0) { - (this.tail as BufferListItem).next = entry; - } else { - this.head = entry; - } - this.tail = entry; - ++this.length; - } - - unshift(v: Buffer | string | Uint8Array) { - const entry = { data: v, next: this.head }; - if (this.length === 0) { - this.tail = entry; - } - this.head = entry; - ++this.length; - } - - shift() { - if (this.length === 0) { - return; - } - const ret = (this.head as BufferListItem).data; - if (this.length === 1) { - this.head = this.tail = null; - } else { - this.head = (this.head as BufferListItem).next; - } - --this.length; - return ret; - } - - clear() { - this.head = this.tail = null; - this.length = 0; - } - - join(s: string) { - if (this.length === 0) { - return ""; - } - let p: BufferListItem | null = (this.head as BufferListItem); - let ret = "" + p.data; - p = p.next; - while (p) { - ret += s + p.data; - p = p.next; - } - return ret; - } - - concat(n: number) { - if (this.length === 0) { - return Buffer.alloc(0); - } - const ret = Buffer.allocUnsafe(n >>> 0); - let p = this.head; - let i = 0; - while (p) { - ret.set(p.data as Buffer, i); - i += p.data.length; - p = p.next; - } - return ret; - } - - // Consumes a specified amount of bytes or characters from the buffered data. - consume(n: number, hasStrings: boolean) { - const data = (this.head as BufferListItem).data; - if (n < data.length) { - // `slice` is the same for buffers and strings. - const slice = data.slice(0, n); - (this.head as BufferListItem).data = data.slice(n); - return slice; - } - if (n === data.length) { - // First chunk is a perfect match. - return this.shift(); - } - // Result spans more than one buffer. - return hasStrings ? this._getString(n) : this._getBuffer(n); - } - - first() { - return (this.head as BufferListItem).data; - } - - *[Symbol.iterator]() { - for (let p = this.head; p; p = p.next) { - yield p.data; - } - } - - // Consumes a specified amount of characters from the buffered data. - _getString(n: number) { - let ret = ""; - let p: BufferListItem | null = (this.head as BufferListItem); - let c = 0; - p = p.next as BufferListItem; - do { - const str = p.data; - if (n > str.length) { - ret += str; - n -= str.length; - } else { - if (n === str.length) { - ret += str; - ++c; - if (p.next) { - this.head = p.next; - } else { - this.head = this.tail = null; - } - } else { - ret += str.slice(0, n); - this.head = p; - p.data = str.slice(n); - } - break; - } - ++c; - p = p.next; - } while (p); - this.length -= c; - return ret; - } - - // Consumes a specified amount of bytes from the buffered data. - _getBuffer(n: number) { - const ret = Buffer.allocUnsafe(n); - const retLen = n; - let p: BufferListItem | null = (this.head as BufferListItem); - let c = 0; - p = p.next as BufferListItem; - do { - const buf = p.data as Buffer; - if (n > buf.length) { - ret.set(buf, retLen - n); - n -= buf.length; - } else { - if (n === buf.length) { - ret.set(buf, retLen - n); - ++c; - if (p.next) { - this.head = p.next; - } else { - this.head = this.tail = null; - } - } else { - ret.set(new Uint8Array(buf.buffer, buf.byteOffset, n), retLen - n); - this.head = p; - p.data = buf.slice(n); - } - break; - } - ++c; - p = p.next; - } while (p); - this.length -= c; - return ret; - } -} diff --git a/std/node/_stream/destroy.ts b/std/node/_stream/destroy.ts deleted file mode 100644 index d13e12de2..000000000 --- a/std/node/_stream/destroy.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import type Duplex from "./duplex.ts"; -import type Readable from "./readable.ts"; -import type Stream from "./stream.ts"; -import type Writable from "./writable.ts"; - -//This whole module acts as a 'normalizer' -//Idea behind it is you can pass any kind of streams and functions will execute anyways - -//TODO(Soremwar) -//Should be any implementation of stream -//This is a guard to check executed methods exist inside the implementation -type StreamImplementations = Duplex | Readable | Writable; - -// TODO(Soremwar) -// Bring back once requests are implemented -// function isRequest(stream: any) { -// return stream && stream.setHeader && typeof stream.abort === "function"; -// } - -export function destroyer(stream: Stream, err?: Error | null) { - // TODO(Soremwar) - // Bring back once requests are implemented - // if (isRequest(stream)) return stream.abort(); - // if (isRequest(stream.req)) return stream.req.abort(); - if ( - typeof (stream as StreamImplementations).destroy === "function" - ) { - return (stream as StreamImplementations).destroy(err); - } - // A test of async iterator mocks an upcoming implementation of stream - // his is casted to any in the meanwhile - // deno-lint-ignore no-explicit-any - if (typeof (stream as any).close === "function") { - // deno-lint-ignore no-explicit-any - return (stream as any).close(); - } -} diff --git a/std/node/_stream/duplex.ts b/std/node/_stream/duplex.ts deleted file mode 100644 index b5c429f0a..000000000 --- a/std/node/_stream/duplex.ts +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { captureRejectionSymbol } from "../events.ts"; -import Readable, { ReadableState } from "./readable.ts"; -import Stream from "./stream.ts"; -import Writable, { WritableState } from "./writable.ts"; -import { Buffer } from "../buffer.ts"; -import { - ERR_STREAM_ALREADY_FINISHED, - ERR_STREAM_DESTROYED, - ERR_UNKNOWN_ENCODING, -} from "../_errors.ts"; -import type { Encodings } from "../_utils.ts"; -import createReadableStreamAsyncIterator from "./async_iterator.ts"; -import type { ReadableStreamAsyncIterator } from "./async_iterator.ts"; -import { - _destroy, - computeNewHighWaterMark, - emitReadable, - fromList, - howMuchToRead, - nReadingNextTick, - updateReadableListening, -} from "./readable_internal.ts"; -import { kOnFinished, writeV } from "./writable_internal.ts"; -import { - endDuplex, - finishMaybe, - onwrite, - readableAddChunk, -} from "./duplex_internal.ts"; -export { errorOrDestroy } from "./duplex_internal.ts"; - -export interface DuplexOptions { - allowHalfOpen?: boolean; - autoDestroy?: boolean; - decodeStrings?: boolean; - defaultEncoding?: Encodings; - destroy?( - this: Duplex, - error: Error | null, - callback: (error: Error | null) => void, - ): void; - emitClose?: boolean; - encoding?: Encodings; - final?(this: Duplex, callback: (error?: Error | null) => void): void; - highWaterMark?: number; - objectMode?: boolean; - read?(this: Duplex, size: number): void; - readable?: boolean; - readableHighWaterMark?: number; - readableObjectMode?: boolean; - writable?: boolean; - writableCorked?: number; - writableHighWaterMark?: number; - writableObjectMode?: boolean; - write?( - this: Duplex, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: Encodings, - callback: (error?: Error | null) => void, - ): void; - writev?: writeV; -} - -interface Duplex extends Readable, Writable {} - -/** - * A duplex is an implementation of a stream that has both Readable and Writable - * attributes and capabilities - */ -class Duplex extends Stream { - allowHalfOpen = true; - _final?: ( - callback: (error?: Error | null | undefined) => void, - ) => void; - _readableState: ReadableState; - _writableState: WritableState; - _writev?: writeV | null; - - constructor(options?: DuplexOptions) { - super(); - - if (options) { - if (options.allowHalfOpen === false) { - this.allowHalfOpen = false; - } - if (typeof options.destroy === "function") { - this._destroy = options.destroy; - } - if (typeof options.final === "function") { - this._final = options.final; - } - if (typeof options.read === "function") { - this._read = options.read; - } - if (options.readable === false) { - this.readable = false; - } - if (options.writable === false) { - this.writable = false; - } - if (typeof options.write === "function") { - this._write = options.write; - } - if (typeof options.writev === "function") { - this._writev = options.writev; - } - } - - const readableOptions = { - autoDestroy: options?.autoDestroy, - defaultEncoding: options?.defaultEncoding, - destroy: options?.destroy as unknown as ( - this: Readable, - error: Error | null, - callback: (error: Error | null) => void, - ) => void, - emitClose: options?.emitClose, - encoding: options?.encoding, - highWaterMark: options?.highWaterMark ?? options?.readableHighWaterMark, - objectMode: options?.objectMode ?? options?.readableObjectMode, - read: options?.read as unknown as (this: Readable) => void, - }; - - const writableOptions = { - autoDestroy: options?.autoDestroy, - decodeStrings: options?.decodeStrings, - defaultEncoding: options?.defaultEncoding, - destroy: options?.destroy as unknown as ( - this: Writable, - error: Error | null, - callback: (error: Error | null) => void, - ) => void, - emitClose: options?.emitClose, - final: options?.final as unknown as ( - this: Writable, - callback: (error?: Error | null) => void, - ) => void, - highWaterMark: options?.highWaterMark ?? options?.writableHighWaterMark, - objectMode: options?.objectMode ?? options?.writableObjectMode, - write: options?.write as unknown as ( - this: Writable, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: string, - callback: (error?: Error | null) => void, - ) => void, - writev: options?.writev as unknown as ( - this: Writable, - // deno-lint-ignore no-explicit-any - chunks: Array<{ chunk: any; encoding: Encodings }>, - callback: (error?: Error | null) => void, - ) => void, - }; - - this._readableState = new ReadableState(readableOptions); - this._writableState = new WritableState( - writableOptions, - this as unknown as Writable, - ); - //Very important to override onwrite here, duplex implementation adds a check - //on the readable side - this._writableState.onwrite = onwrite.bind(undefined, this); - } - - [captureRejectionSymbol](err?: Error) { - this.destroy(err); - } - - [Symbol.asyncIterator](): ReadableStreamAsyncIterator { - return createReadableStreamAsyncIterator(this); - } - - _destroy( - error: Error | null, - callback: (error?: Error | null) => void, - ): void { - callback(error); - } - - _read = Readable.prototype._read; - - _undestroy = Readable.prototype._undestroy; - - destroy(err?: Error | null, cb?: (error?: Error | null) => void) { - const r = this._readableState; - const w = this._writableState; - - if (w.destroyed || r.destroyed) { - if (typeof cb === "function") { - cb(); - } - - return this; - } - - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!w.errored) { - w.errored = err; - } - if (!r.errored) { - r.errored = err; - } - } - - w.destroyed = true; - r.destroyed = true; - - this._destroy(err || null, (err) => { - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!w.errored) { - w.errored = err; - } - if (!r.errored) { - r.errored = err; - } - } - - w.closed = true; - r.closed = true; - - if (typeof cb === "function") { - cb(err); - } - - if (err) { - queueMicrotask(() => { - const r = this._readableState; - const w = this._writableState; - - if (!w.errorEmitted && !r.errorEmitted) { - w.errorEmitted = true; - r.errorEmitted = true; - - this.emit("error", err); - } - - r.closeEmitted = true; - - if (w.emitClose || r.emitClose) { - this.emit("close"); - } - }); - } else { - queueMicrotask(() => { - const r = this._readableState; - const w = this._writableState; - - r.closeEmitted = true; - - if (w.emitClose || r.emitClose) { - this.emit("close"); - } - }); - } - }); - - return this; - } - - isPaused = Readable.prototype.isPaused; - - off = this.removeListener; - - on( - event: "close" | "end" | "pause" | "readable" | "resume", - listener: () => void, - ): this; - // deno-lint-ignore no-explicit-any - on(event: "data", listener: (chunk: any) => void): this; - on(event: "error", listener: (err: Error) => void): this; - // deno-lint-ignore no-explicit-any - on(event: string | symbol, listener: (...args: any[]) => void): this; - on( - ev: string | symbol, - fn: - | (() => void) - // deno-lint-ignore no-explicit-any - | ((chunk: any) => void) - | ((err: Error) => void) - // deno-lint-ignore no-explicit-any - | ((...args: any[]) => void), - ) { - const res = super.on.call(this, ev, fn); - const state = this._readableState; - - if (ev === "data") { - state.readableListening = this.listenerCount("readable") > 0; - - if (state.flowing !== false) { - this.resume(); - } - } else if (ev === "readable") { - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.flowing = false; - state.emittedReadable = false; - if (state.length) { - emitReadable(this); - } else if (!state.reading) { - queueMicrotask(() => nReadingNextTick(this)); - } - } - } - - return res; - } - - pause = Readable.prototype.pause as () => this; - - pipe = Readable.prototype.pipe; - - // deno-lint-ignore no-explicit-any - push(chunk: any, encoding?: Encodings): boolean { - return readableAddChunk(this, chunk, encoding, false); - } - - /** You can override either this method, or the async `_read` method */ - read(n?: number) { - // Same as parseInt(undefined, 10), however V8 7.3 performance regressed - // in this scenario, so we are doing it manually. - if (n === undefined) { - n = NaN; - } - const state = this._readableState; - const nOrig = n; - - if (n > state.highWaterMark) { - state.highWaterMark = computeNewHighWaterMark(n); - } - - if (n !== 0) { - state.emittedReadable = false; - } - - if ( - n === 0 && - state.needReadable && - ((state.highWaterMark !== 0 - ? state.length >= state.highWaterMark - : state.length > 0) || - state.ended) - ) { - if (state.length === 0 && state.ended) { - endDuplex(this); - } else { - emitReadable(this); - } - return null; - } - - n = howMuchToRead(n, state); - - if (n === 0 && state.ended) { - if (state.length === 0) { - endDuplex(this); - } - return null; - } - - let doRead = state.needReadable; - if ( - state.length === 0 || state.length - (n as number) < state.highWaterMark - ) { - doRead = true; - } - - if ( - state.ended || state.reading || state.destroyed || state.errored || - !state.constructed - ) { - doRead = false; - } else if (doRead) { - state.reading = true; - state.sync = true; - if (state.length === 0) { - state.needReadable = true; - } - this._read(); - state.sync = false; - if (!state.reading) { - n = howMuchToRead(nOrig, state); - } - } - - let ret; - if ((n as number) > 0) { - ret = fromList((n as number), state); - } else { - ret = null; - } - - if (ret === null) { - state.needReadable = state.length <= state.highWaterMark; - n = 0; - } else { - state.length -= n as number; - if (state.multiAwaitDrain) { - (state.awaitDrainWriters as Set<Writable>).clear(); - } else { - state.awaitDrainWriters = null; - } - } - - if (state.length === 0) { - if (!state.ended) { - state.needReadable = true; - } - - if (nOrig !== n && state.ended) { - endDuplex(this); - } - } - - if (ret !== null) { - this.emit("data", ret); - } - - return ret; - } - - removeAllListeners( - ev: - | "close" - | "data" - | "end" - | "error" - | "pause" - | "readable" - | "resume" - | symbol - | undefined, - ) { - const res = super.removeAllListeners(ev); - - if (ev === "readable" || ev === undefined) { - queueMicrotask(() => updateReadableListening(this)); - } - - return res; - } - - removeListener( - event: "close" | "end" | "pause" | "readable" | "resume", - listener: () => void, - ): this; - // deno-lint-ignore no-explicit-any - removeListener(event: "data", listener: (chunk: any) => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - removeListener( - event: string | symbol, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, - ): this; - removeListener( - ev: string | symbol, - fn: - | (() => void) - // deno-lint-ignore no-explicit-any - | ((chunk: any) => void) - | ((err: Error) => void) - // deno-lint-ignore no-explicit-any - | ((...args: any[]) => void), - ) { - const res = super.removeListener.call(this, ev, fn); - - if (ev === "readable") { - queueMicrotask(() => updateReadableListening(this)); - } - - return res; - } - - resume = Readable.prototype.resume as () => this; - - setEncoding = Readable.prototype.setEncoding as (enc: string) => this; - - // deno-lint-ignore no-explicit-any - unshift(chunk: any, encoding?: Encodings): boolean { - return readableAddChunk(this, chunk, encoding, true); - } - - unpipe = Readable.prototype.unpipe as (dest?: Writable | undefined) => this; - - wrap = Readable.prototype.wrap as (stream: Stream) => this; - - get readable(): boolean { - return this._readableState?.readable && - !this._readableState?.destroyed && - !this._readableState?.errorEmitted && - !this._readableState?.endEmitted; - } - set readable(val: boolean) { - if (this._readableState) { - this._readableState.readable = val; - } - } - - get readableHighWaterMark(): number { - return this._readableState.highWaterMark; - } - - get readableBuffer() { - return this._readableState && this._readableState.buffer; - } - - get readableFlowing(): boolean | null { - return this._readableState.flowing; - } - - set readableFlowing(state: boolean | null) { - if (this._readableState) { - this._readableState.flowing = state; - } - } - - get readableLength() { - return this._readableState.length; - } - - get readableObjectMode() { - return this._readableState ? this._readableState.objectMode : false; - } - - get readableEncoding() { - return this._readableState ? this._readableState.encoding : null; - } - - get readableEnded() { - return this._readableState ? this._readableState.endEmitted : false; - } - - _write = Writable.prototype._write; - - write = Writable.prototype.write; - - cork = Writable.prototype.cork; - - uncork = Writable.prototype.uncork; - - setDefaultEncoding(encoding: string) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === "string") { - encoding = encoding.toLowerCase(); - } - if (!Buffer.isEncoding(encoding)) { - throw new ERR_UNKNOWN_ENCODING(encoding); - } - this._writableState.defaultEncoding = encoding as Encodings; - return this; - } - - end(cb?: () => void): void; - // deno-lint-ignore no-explicit-any - end(chunk: any, cb?: () => void): void; - // deno-lint-ignore no-explicit-any - end(chunk: any, encoding: Encodings, cb?: () => void): void; - - end( - // deno-lint-ignore no-explicit-any - x?: any | (() => void), - y?: Encodings | (() => void), - z?: () => void, - ) { - const state = this._writableState; - // deno-lint-ignore no-explicit-any - let chunk: any | null; - let encoding: Encodings | null; - let cb: undefined | ((error?: Error) => void); - - if (typeof x === "function") { - chunk = null; - encoding = null; - cb = x; - } else if (typeof y === "function") { - chunk = x; - encoding = null; - cb = y; - } else { - chunk = x; - encoding = y as Encodings; - cb = z; - } - - if (chunk !== null && chunk !== undefined) { - this.write(chunk, encoding); - } - - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - let err: Error | undefined; - if (!state.errored && !state.ending) { - state.ending = true; - finishMaybe(this, state, true); - state.ended = true; - } else if (state.finished) { - err = new ERR_STREAM_ALREADY_FINISHED("end"); - } else if (state.destroyed) { - err = new ERR_STREAM_DESTROYED("end"); - } - - if (typeof cb === "function") { - if (err || state.finished) { - queueMicrotask(() => { - (cb as (error?: Error | undefined) => void)(err); - }); - } else { - state[kOnFinished].push(cb); - } - } - - return this; - } - - get destroyed() { - if ( - this._readableState === undefined || - this._writableState === undefined - ) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - } - - set destroyed(value: boolean) { - if (this._readableState && this._writableState) { - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } - } - - get writable() { - const w = this._writableState; - return !w.destroyed && !w.errored && !w.ending && !w.ended; - } - - set writable(val) { - if (this._writableState) { - this._writableState.writable = !!val; - } - } - - get writableFinished() { - return this._writableState ? this._writableState.finished : false; - } - - get writableObjectMode() { - return this._writableState ? this._writableState.objectMode : false; - } - - get writableBuffer() { - return this._writableState && this._writableState.getBuffer(); - } - - get writableEnded() { - return this._writableState ? this._writableState.ending : false; - } - - get writableHighWaterMark() { - return this._writableState && this._writableState.highWaterMark; - } - - get writableCorked() { - return this._writableState ? this._writableState.corked : 0; - } - - get writableLength() { - return this._writableState && this._writableState.length; - } -} - -export default Duplex; diff --git a/std/node/_stream/duplex_internal.ts b/std/node/_stream/duplex_internal.ts deleted file mode 100644 index bfd9749f8..000000000 --- a/std/node/_stream/duplex_internal.ts +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import type { ReadableState } from "./readable.ts"; -import { addChunk, maybeReadMore, onEofChunk } from "./readable_internal.ts"; -import type Writable from "./writable.ts"; -import type { WritableState } from "./writable.ts"; -import { - afterWrite, - AfterWriteTick, - afterWriteTick, - clearBuffer, - errorBuffer, - kOnFinished, - needFinish, - prefinish, -} from "./writable_internal.ts"; -import { Buffer } from "../buffer.ts"; -import type Duplex from "./duplex.ts"; -import { - ERR_MULTIPLE_CALLBACK, - ERR_STREAM_PUSH_AFTER_EOF, - ERR_STREAM_UNSHIFT_AFTER_END_EVENT, -} from "../_errors.ts"; - -export function endDuplex(stream: Duplex) { - const state = stream._readableState; - - if (!state.endEmitted) { - state.ended = true; - queueMicrotask(() => endReadableNT(state, stream)); - } -} - -function endReadableNT(state: ReadableState, stream: Duplex) { - // Check that we didn't get one last unshift. - if ( - !state.errorEmitted && !state.closeEmitted && - !state.endEmitted && state.length === 0 - ) { - state.endEmitted = true; - stream.emit("end"); - - if (stream.writable && stream.allowHalfOpen === false) { - queueMicrotask(() => endWritableNT(state, 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 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) - ); - - if (autoDestroy) { - stream.destroy(); - } - } - } -} - -function endWritableNT(state: ReadableState, stream: Duplex) { - const writable = stream.writable && - !stream.writableEnded && - !stream.destroyed; - if (writable) { - stream.end(); - } -} - -export function errorOrDestroy( - // deno-lint-ignore no-explicit-any - this: any, - stream: Duplex, - err: Error, - sync = false, -) { - const r = stream._readableState; - const w = stream._writableState; - - if (w.destroyed || r.destroyed) { - return this; - } - - if (r.autoDestroy || w.autoDestroy) { - stream.destroy(err); - } else if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (w && !w.errored) { - w.errored = err; - } - if (r && !r.errored) { - r.errored = err; - } - - if (sync) { - queueMicrotask(() => { - if (w.errorEmitted || r.errorEmitted) { - return; - } - - w.errorEmitted = true; - r.errorEmitted = true; - - stream.emit("error", err); - }); - } else { - if (w.errorEmitted || r.errorEmitted) { - return; - } - - w.errorEmitted = true; - r.errorEmitted = true; - - stream.emit("error", err); - } - } -} - -function finish(stream: Duplex, state: WritableState) { - state.pendingcb--; - if (state.errorEmitted || state.closeEmitted) { - return; - } - - state.finished = true; - - for (const callback of state[kOnFinished].splice(0)) { - callback(); - } - - stream.emit("finish"); - - if (state.autoDestroy) { - stream.destroy(); - } -} - -export function finishMaybe( - stream: Duplex, - state: WritableState, - sync?: boolean, -) { - if (needFinish(state)) { - prefinish(stream as Writable, state); - if (state.pendingcb === 0 && needFinish(state)) { - state.pendingcb++; - if (sync) { - queueMicrotask(() => finish(stream, state)); - } else { - finish(stream, state); - } - } - } -} - -export function onwrite(stream: Duplex, er?: Error | null) { - const state = stream._writableState; - const sync = state.sync; - const cb = state.writecb; - - if (typeof cb !== "function") { - errorOrDestroy(stream, new ERR_MULTIPLE_CALLBACK()); - return; - } - - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; - - if (er) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - er.stack; - - if (!state.errored) { - state.errored = er; - } - - if (stream._readableState && !stream._readableState.errored) { - stream._readableState.errored = er; - } - - if (sync) { - queueMicrotask(() => onwriteError(stream, state, er, cb)); - } else { - onwriteError(stream, state, er, cb); - } - } else { - if (state.buffered.length > state.bufferedIndex) { - clearBuffer(stream, state); - } - - if (sync) { - if ( - state.afterWriteTickInfo !== null && - state.afterWriteTickInfo.cb === cb - ) { - state.afterWriteTickInfo.count++; - } else { - state.afterWriteTickInfo = { - count: 1, - cb: (cb as (error?: Error) => void), - stream: stream as Writable, - state, - }; - queueMicrotask(() => - afterWriteTick(state.afterWriteTickInfo as AfterWriteTick) - ); - } - } else { - afterWrite(stream as Writable, state, 1, cb as (error?: Error) => void); - } - } -} - -function onwriteError( - stream: Duplex, - state: WritableState, - er: Error, - cb: (error: Error) => void, -) { - --state.pendingcb; - - cb(er); - errorBuffer(state); - errorOrDestroy(stream, er); -} - -export function readableAddChunk( - stream: Duplex, - chunk: string | Buffer | Uint8Array | null, - encoding: undefined | string = undefined, - addToFront: boolean, -) { - const state = stream._readableState; - let usedEncoding = encoding; - - let err; - if (!state.objectMode) { - if (typeof chunk === "string") { - usedEncoding = encoding || state.defaultEncoding; - if (state.encoding !== usedEncoding) { - if (addToFront && state.encoding) { - chunk = Buffer.from(chunk, usedEncoding).toString(state.encoding); - } else { - chunk = Buffer.from(chunk, usedEncoding); - usedEncoding = ""; - } - } - } else if (chunk instanceof Uint8Array) { - chunk = Buffer.from(chunk); - } - } - - if (err) { - errorOrDestroy(stream, err); - } else if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else if (state.objectMode || (chunk.length > 0)) { - if (addToFront) { - if (state.endEmitted) { - errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); - } else { - addChunk(stream, state, chunk, true); - } - } else if (state.ended) { - errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); - } else if (state.destroyed || state.errored) { - return false; - } else { - state.reading = false; - if (state.decoder && !usedEncoding) { - //TODO(Soremwar) - //I don't think this cast is right - chunk = state.decoder.write(Buffer.from(chunk as Uint8Array)); - if (state.objectMode || chunk.length !== 0) { - addChunk(stream, state, chunk, false); - } else { - maybeReadMore(stream, state); - } - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - maybeReadMore(stream, state); - } - - return !state.ended && - (state.length < state.highWaterMark || state.length === 0); -} diff --git a/std/node/_stream/duplex_test.ts b/std/node/_stream/duplex_test.ts deleted file mode 100644 index 1596ec218..000000000 --- a/std/node/_stream/duplex_test.ts +++ /dev/null @@ -1,698 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Duplex from "./duplex.ts"; -import finished from "./end_of_stream.ts"; -import { - assert, - assertEquals, - assertStrictEquals, - assertThrows, -} from "../../testing/asserts.ts"; -import { deferred, delay } from "../../async/mod.ts"; - -Deno.test("Duplex stream works normally", () => { - const stream = new Duplex({ objectMode: true }); - - assert(stream._readableState.objectMode); - assert(stream._writableState.objectMode); - assert(stream.allowHalfOpen); - assertEquals(stream.listenerCount("end"), 0); - - let written: { val: number }; - let read: { val: number }; - - stream._write = (obj, _, cb) => { - written = obj; - cb(); - }; - - stream._read = () => {}; - - stream.on("data", (obj) => { - read = obj; - }); - - stream.push({ val: 1 }); - stream.end({ val: 2 }); - - stream.on("finish", () => { - assertEquals(read.val, 1); - assertEquals(written.val, 2); - }); -}); - -Deno.test("Duplex stream gets constructed correctly", () => { - const d1 = new Duplex({ - objectMode: true, - highWaterMark: 100, - }); - - assertEquals(d1.readableObjectMode, true); - assertEquals(d1.readableHighWaterMark, 100); - assertEquals(d1.writableObjectMode, true); - assertEquals(d1.writableHighWaterMark, 100); - - const d2 = new Duplex({ - readableObjectMode: false, - readableHighWaterMark: 10, - writableObjectMode: true, - writableHighWaterMark: 100, - }); - - assertEquals(d2.writableObjectMode, true); - assertEquals(d2.writableHighWaterMark, 100); - assertEquals(d2.readableObjectMode, false); - assertEquals(d2.readableHighWaterMark, 10); -}); - -Deno.test("Duplex stream can be paused", () => { - const readable = new Duplex(); - - // _read is a noop, here. - readable._read = () => {}; - - // Default state of a stream is not "paused" - assert(!readable.isPaused()); - - // Make the stream start flowing... - readable.on("data", () => {}); - - // still not paused. - assert(!readable.isPaused()); - - readable.pause(); - assert(readable.isPaused()); - readable.resume(); - assert(!readable.isPaused()); -}); - -Deno.test("Duplex stream sets enconding correctly", () => { - const readable = new Duplex({ - read() {}, - }); - - readable.setEncoding("utf8"); - - readable.push(new TextEncoder().encode("DEF")); - readable.unshift(new TextEncoder().encode("ABC")); - - assertStrictEquals(readable.read(), "ABCDEF"); -}); - -Deno.test("Duplex stream sets encoding correctly", () => { - const readable = new Duplex({ - read() {}, - }); - - readable.setEncoding("utf8"); - - readable.push(new TextEncoder().encode("DEF")); - readable.unshift(new TextEncoder().encode("ABC")); - - assertStrictEquals(readable.read(), "ABCDEF"); -}); - -Deno.test("Duplex stream holds up a big push", async () => { - let readExecuted = 0; - const readExecutedExpected = 3; - const readExpectedExecutions = deferred(); - - let endExecuted = 0; - const endExecutedExpected = 1; - const endExpectedExecutions = deferred(); - - const str = "asdfasdfasdfasdfasdf"; - - const r = new Duplex({ - highWaterMark: 5, - encoding: "utf8", - }); - - let reads = 0; - - function _read() { - if (reads === 0) { - setTimeout(() => { - r.push(str); - }, 1); - reads++; - } else if (reads === 1) { - const ret = r.push(str); - assertEquals(ret, false); - reads++; - } else { - r.push(null); - } - } - - r._read = () => { - readExecuted++; - if (readExecuted == readExecutedExpected) { - readExpectedExecutions.resolve(); - } - _read(); - }; - - r.on("end", () => { - endExecuted++; - if (endExecuted == endExecutedExpected) { - endExpectedExecutions.resolve(); - } - }); - - // Push some data in to start. - // We've never gotten any read event at this point. - const ret = r.push(str); - assert(!ret); - let chunk = r.read(); - assertEquals(chunk, str); - chunk = r.read(); - assertEquals(chunk, null); - - r.once("readable", () => { - // This time, we'll get *all* the remaining data, because - // it's been added synchronously, as the read WOULD take - // us below the hwm, and so it triggered a _read() again, - // which synchronously added more, which we then return. - chunk = r.read(); - assertEquals(chunk, str + str); - - chunk = r.read(); - assertEquals(chunk, null); - }); - - const readTimeout = setTimeout( - () => readExpectedExecutions.reject(), - 1000, - ); - const endTimeout = setTimeout( - () => endExpectedExecutions.reject(), - 1000, - ); - await readExpectedExecutions; - await endExpectedExecutions; - clearTimeout(readTimeout); - clearTimeout(endTimeout); - assertEquals(readExecuted, readExecutedExpected); - assertEquals(endExecuted, endExecutedExpected); -}); - -Deno.test("Duplex stream: 'readable' event is emitted but 'read' is not on highWaterMark length exceeded", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - const r = new Duplex({ - highWaterMark: 3, - }); - - r._read = () => { - throw new Error("_read must not be called"); - }; - r.push(Buffer.from("blerg")); - - setTimeout(function () { - assert(!r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - clearTimeout(readableTimeout); - assertEquals(readableExecuted, readableExecutedExpected); -}); - -Deno.test("Duplex stream: 'readable' and 'read' events are emitted on highWaterMark length not reached", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - let readExecuted = 0; - const readExecutedExpected = 1; - const readExpectedExecutions = deferred(); - - const r = new Duplex({ - highWaterMark: 3, - }); - - r._read = () => { - readExecuted++; - if (readExecuted == readExecutedExpected) { - readExpectedExecutions.resolve(); - } - }; - - r.push(Buffer.from("bl")); - - setTimeout(function () { - assert(r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - const readTimeout = setTimeout( - () => readExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - await readExpectedExecutions; - clearTimeout(readableTimeout); - clearTimeout(readTimeout); - assertEquals(readableExecuted, readableExecutedExpected); - assertEquals(readExecuted, readExecutedExpected); -}); - -Deno.test("Duplex stream: 'readable' event is emitted but 'read' is not on highWaterMark length not reached and stream ended", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - const r = new Duplex({ - highWaterMark: 30, - }); - - r._read = () => { - throw new Error("Must not be executed"); - }; - - r.push(Buffer.from("blerg")); - //This ends the stream and triggers end - r.push(null); - - setTimeout(function () { - // Assert we're testing what we think we are - assert(!r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - clearTimeout(readableTimeout); - assertEquals(readableExecuted, readableExecutedExpected); -}); - -Deno.test("Duplex stream: 'read' is emitted on empty string pushed in non-object mode", async () => { - let endExecuted = 0; - const endExecutedExpected = 1; - const endExpectedExecutions = deferred(); - - const underlyingData = ["", "x", "y", "", "z"]; - const expected = underlyingData.filter((data) => data); - const result: unknown[] = []; - - const r = new Duplex({ - encoding: "utf8", - }); - r._read = function () { - queueMicrotask(() => { - if (!underlyingData.length) { - this.push(null); - } else { - this.push(underlyingData.shift()); - } - }); - }; - - r.on("readable", () => { - const data = r.read(); - if (data !== null) result.push(data); - }); - - r.on("end", () => { - endExecuted++; - if (endExecuted == endExecutedExpected) { - endExpectedExecutions.resolve(); - } - assertEquals(result, expected); - }); - - const endTimeout = setTimeout( - () => endExpectedExecutions.reject(), - 1000, - ); - await endExpectedExecutions; - clearTimeout(endTimeout); - assertEquals(endExecuted, endExecutedExpected); -}); - -Deno.test("Duplex stream: listeners can be removed", () => { - const r = new Duplex(); - r._read = () => {}; - r.on("data", () => {}); - - r.removeAllListeners("data"); - - assertEquals(r.eventNames().length, 0); -}); - -Deno.test("Duplex stream writes correctly", async () => { - let callback: undefined | ((error?: Error | null | undefined) => void); - - let writeExecuted = 0; - const writeExecutedExpected = 1; - const writeExpectedExecutions = deferred(); - - let writevExecuted = 0; - const writevExecutedExpected = 1; - const writevExpectedExecutions = deferred(); - - const writable = new Duplex({ - write: (chunk, encoding, cb) => { - writeExecuted++; - if (writeExecuted == writeExecutedExpected) { - writeExpectedExecutions.resolve(); - } - assert(chunk instanceof Buffer); - assertStrictEquals(encoding, "buffer"); - assertStrictEquals(String(chunk), "ABC"); - callback = cb; - }, - writev: (chunks) => { - writevExecuted++; - if (writevExecuted == writevExecutedExpected) { - writevExpectedExecutions.resolve(); - } - assertStrictEquals(chunks.length, 2); - assertStrictEquals(chunks[0].encoding, "buffer"); - assertStrictEquals(chunks[1].encoding, "buffer"); - assertStrictEquals(chunks[0].chunk + chunks[1].chunk, "DEFGHI"); - }, - }); - - writable.write(new TextEncoder().encode("ABC")); - writable.write(new TextEncoder().encode("DEF")); - writable.end(new TextEncoder().encode("GHI")); - callback?.(); - - const writeTimeout = setTimeout( - () => writeExpectedExecutions.reject(), - 1000, - ); - const writevTimeout = setTimeout( - () => writevExpectedExecutions.reject(), - 1000, - ); - await writeExpectedExecutions; - await writevExpectedExecutions; - clearTimeout(writeTimeout); - clearTimeout(writevTimeout); - assertEquals(writeExecuted, writeExecutedExpected); - assertEquals(writevExecuted, writevExecutedExpected); -}); - -Deno.test("Duplex stream writes Uint8Array in object mode", async () => { - let writeExecuted = 0; - const writeExecutedExpected = 1; - const writeExpectedExecutions = deferred(); - - const ABC = new TextEncoder().encode("ABC"); - - const writable = new Duplex({ - objectMode: true, - write: (chunk, encoding, cb) => { - writeExecuted++; - if (writeExecuted == writeExecutedExpected) { - writeExpectedExecutions.resolve(); - } - assert(!(chunk instanceof Buffer)); - assert(chunk instanceof Uint8Array); - assertEquals(chunk, ABC); - assertEquals(encoding, "utf8"); - cb(); - }, - }); - - writable.end(ABC); - - const writeTimeout = setTimeout( - () => writeExpectedExecutions.reject(), - 1000, - ); - await writeExpectedExecutions; - clearTimeout(writeTimeout); - assertEquals(writeExecuted, writeExecutedExpected); -}); - -Deno.test("Duplex stream throws on unexpected close", async () => { - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExpectedExecutions = deferred(); - - const writable = new Duplex({ - write: () => {}, - }); - writable.writable = false; - writable.destroy(); - - finished(writable, (err) => { - finishedExecuted++; - if (finishedExecuted == finishedExecutedExpected) { - finishedExpectedExecutions.resolve(); - } - assertEquals(err?.code, "ERR_STREAM_PREMATURE_CLOSE"); - }); - - const finishedTimeout = setTimeout( - () => finishedExpectedExecutions.reject(), - 1000, - ); - await finishedExpectedExecutions; - clearTimeout(finishedTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); -}); - -Deno.test("Duplex stream finishes correctly after error", async () => { - let errorExecuted = 0; - const errorExecutedExpected = 1; - const errorExpectedExecutions = deferred(); - - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExpectedExecutions = deferred(); - - const w = new Duplex({ - write(_chunk, _encoding, cb) { - cb(new Error()); - }, - autoDestroy: false, - }); - w.write("asd"); - w.on("error", () => { - errorExecuted++; - if (errorExecuted == errorExecutedExpected) { - errorExpectedExecutions.resolve(); - } - finished(w, () => { - finishedExecuted++; - if (finishedExecuted == finishedExecutedExpected) { - finishedExpectedExecutions.resolve(); - } - }); - }); - - const errorTimeout = setTimeout( - () => errorExpectedExecutions.reject(), - 1000, - ); - const finishedTimeout = setTimeout( - () => finishedExpectedExecutions.reject(), - 1000, - ); - await finishedExpectedExecutions; - await errorExpectedExecutions; - clearTimeout(finishedTimeout); - clearTimeout(errorTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); - assertEquals(errorExecuted, errorExecutedExpected); -}); - -Deno.test("Duplex stream fails on 'write' null value", () => { - const writable = new Duplex(); - assertThrows(() => writable.write(null)); -}); - -Deno.test("Duplex stream is destroyed correctly", async () => { - let closeExecuted = 0; - const closeExecutedExpected = 1; - const closeExpectedExecutions = deferred(); - - const unexpectedExecution = deferred(); - - const duplex = new Duplex({ - write(_chunk, _enc, cb) { - cb(); - }, - read() {}, - }); - - duplex.resume(); - - function never() { - unexpectedExecution.reject(); - } - - duplex.on("end", never); - duplex.on("finish", never); - duplex.on("close", () => { - closeExecuted++; - if (closeExecuted == closeExecutedExpected) { - closeExpectedExecutions.resolve(); - } - }); - - duplex.destroy(); - assertEquals(duplex.destroyed, true); - - const closeTimeout = setTimeout( - () => closeExpectedExecutions.reject(), - 1000, - ); - await Promise.race([ - unexpectedExecution, - delay(100), - ]); - await closeExpectedExecutions; - clearTimeout(closeTimeout); - assertEquals(closeExecuted, closeExecutedExpected); -}); - -Deno.test("Duplex stream errors correctly on destroy", async () => { - let errorExecuted = 0; - const errorExecutedExpected = 1; - const errorExpectedExecutions = deferred(); - - const unexpectedExecution = deferred(); - - const duplex = new Duplex({ - write(_chunk, _enc, cb) { - cb(); - }, - read() {}, - }); - duplex.resume(); - - const expected = new Error("kaboom"); - - function never() { - unexpectedExecution.reject(); - } - - duplex.on("end", never); - duplex.on("finish", never); - duplex.on("error", (err) => { - errorExecuted++; - if (errorExecuted == errorExecutedExpected) { - errorExpectedExecutions.resolve(); - } - assertStrictEquals(err, expected); - }); - - duplex.destroy(expected); - assertEquals(duplex.destroyed, true); - - const errorTimeout = setTimeout( - () => errorExpectedExecutions.reject(), - 1000, - ); - await Promise.race([ - unexpectedExecution, - delay(100), - ]); - await errorExpectedExecutions; - clearTimeout(errorTimeout); - assertEquals(errorExecuted, errorExecutedExpected); -}); - -Deno.test("Duplex stream doesn't finish on allowHalfOpen", async () => { - const unexpectedExecution = deferred(); - - const duplex = new Duplex({ - read() {}, - }); - - assertEquals(duplex.allowHalfOpen, true); - duplex.on("finish", () => unexpectedExecution.reject()); - assertEquals(duplex.listenerCount("end"), 0); - duplex.resume(); - duplex.push(null); - - await Promise.race([ - unexpectedExecution, - delay(100), - ]); -}); - -Deno.test("Duplex stream finishes when allowHalfOpen is disabled", async () => { - let finishExecuted = 0; - const finishExecutedExpected = 1; - const finishExpectedExecutions = deferred(); - - const duplex = new Duplex({ - read() {}, - allowHalfOpen: false, - }); - - assertEquals(duplex.allowHalfOpen, false); - duplex.on("finish", () => { - finishExecuted++; - if (finishExecuted == finishExecutedExpected) { - finishExpectedExecutions.resolve(); - } - }); - assertEquals(duplex.listenerCount("end"), 0); - duplex.resume(); - duplex.push(null); - - const finishTimeout = setTimeout( - () => finishExpectedExecutions.reject(), - 1000, - ); - await finishExpectedExecutions; - clearTimeout(finishTimeout); - assertEquals(finishExecuted, finishExecutedExpected); -}); - -Deno.test("Duplex stream doesn't finish when allowHalfOpen is disabled but stream ended", async () => { - const unexpectedExecution = deferred(); - - const duplex = new Duplex({ - read() {}, - allowHalfOpen: false, - }); - - assertEquals(duplex.allowHalfOpen, false); - duplex._writableState.ended = true; - duplex.on("finish", () => unexpectedExecution.reject()); - assertEquals(duplex.listenerCount("end"), 0); - duplex.resume(); - duplex.push(null); - - await Promise.race([ - unexpectedExecution, - delay(100), - ]); -}); diff --git a/std/node/_stream/end_of_stream.ts b/std/node/_stream/end_of_stream.ts deleted file mode 100644 index 6179e7fc4..000000000 --- a/std/node/_stream/end_of_stream.ts +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { once } from "../_utils.ts"; -import type Duplex from "./duplex.ts"; -import type Readable from "./readable.ts"; -import type Stream from "./stream.ts"; -import type { ReadableState } from "./readable.ts"; -import type Writable from "./writable.ts"; -import type { WritableState } from "./writable.ts"; -import { - ERR_INVALID_ARG_TYPE, - ERR_STREAM_PREMATURE_CLOSE, - NodeErrorAbstraction, -} from "../_errors.ts"; - -export type StreamImplementations = Duplex | Readable | Stream | Writable; - -// TODO(Soremwar) -// Bring back once requests are implemented -// function isRequest(stream: Stream) { -// return stream.setHeader && typeof stream.abort === "function"; -// } - -// deno-lint-ignore no-explicit-any -function isReadable(stream: any) { - return typeof stream.readable === "boolean" || - typeof stream.readableEnded === "boolean" || - !!stream._readableState; -} - -// deno-lint-ignore no-explicit-any -function isWritable(stream: any) { - return typeof stream.writable === "boolean" || - typeof stream.writableEnded === "boolean" || - !!stream._writableState; -} - -function isWritableFinished(stream: Writable) { - if (stream.writableFinished) return true; - const wState = stream._writableState; - if (!wState || wState.errored) return false; - return wState.finished || (wState.ended && wState.length === 0); -} - -function nop() {} - -function isReadableEnded(stream: Readable) { - if (stream.readableEnded) return true; - const rState = stream._readableState; - if (!rState || rState.errored) return false; - return rState.endEmitted || (rState.ended && rState.length === 0); -} - -export interface FinishedOptions { - error?: boolean; - readable?: boolean; - writable?: boolean; -} - -/** - * Appends an ending callback triggered when a stream is no longer readable, - * writable or has experienced an error or a premature close event -*/ -export default function eos( - stream: StreamImplementations, - options: FinishedOptions | null, - callback: (err?: NodeErrorAbstraction | null) => void, -): () => void; -export default function eos( - stream: StreamImplementations, - callback: (err?: NodeErrorAbstraction | null) => void, -): () => void; -export default function eos( - stream: StreamImplementations, - x: FinishedOptions | ((err?: NodeErrorAbstraction | null) => void) | null, - y?: (err?: NodeErrorAbstraction | null) => void, -) { - let opts: FinishedOptions; - let callback: (err?: NodeErrorAbstraction | null) => void; - - if (!y) { - if (typeof x !== "function") { - throw new ERR_INVALID_ARG_TYPE("callback", "function", x); - } - opts = {}; - callback = x; - } else { - if (!x || Array.isArray(x) || typeof x !== "object") { - throw new ERR_INVALID_ARG_TYPE("opts", "object", x); - } - opts = x; - - if (typeof y !== "function") { - throw new ERR_INVALID_ARG_TYPE("callback", "function", y); - } - callback = y; - } - - callback = once(callback); - - const readable = opts.readable ?? isReadable(stream); - const writable = opts.writable ?? isWritable(stream); - - // deno-lint-ignore no-explicit-any - const wState: WritableState | undefined = (stream as any)._writableState; - // deno-lint-ignore no-explicit-any - const rState: ReadableState | undefined = (stream as any)._readableState; - const validState = wState || rState; - - const onlegacyfinish = () => { - if (!(stream as Writable).writable) { - onfinish(); - } - }; - - let willEmitClose = ( - validState?.autoDestroy && - validState?.emitClose && - validState?.closed === false && - isReadable(stream) === readable && - isWritable(stream) === writable - ); - - let writableFinished = (stream as Writable).writableFinished || - wState?.finished; - const onfinish = () => { - writableFinished = true; - // deno-lint-ignore no-explicit-any - if ((stream as any).destroyed) { - willEmitClose = false; - } - - if (willEmitClose && (!(stream as Readable).readable || readable)) { - return; - } - if (!readable || readableEnded) { - callback.call(stream); - } - }; - - let readableEnded = (stream as Readable).readableEnded || rState?.endEmitted; - const onend = () => { - readableEnded = true; - // deno-lint-ignore no-explicit-any - if ((stream as any).destroyed) { - willEmitClose = false; - } - - if (willEmitClose && (!(stream as Writable).writable || writable)) { - return; - } - if (!writable || writableFinished) { - callback.call(stream); - } - }; - - const onerror = (err: NodeErrorAbstraction) => { - callback.call(stream, err); - }; - - const onclose = () => { - if (readable && !readableEnded) { - if (!isReadableEnded(stream as Readable)) { - return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); - } - } - if (writable && !writableFinished) { - if (!isWritableFinished(stream as Writable)) { - return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); - } - } - callback.call(stream); - }; - - // TODO(Soremwar) - // Bring back once requests are implemented - // const onrequest = () => { - // stream.req.on("finish", onfinish); - // }; - - // TODO(Soremwar) - // Bring back once requests are implemented - // if (isRequest(stream)) { - // stream.on("complete", onfinish); - // stream.on("abort", onclose); - // if (stream.req) { - // onrequest(); - // } else { - // stream.on("request", onrequest); - // } - // } else - if (writable && !wState) { - stream.on("end", onlegacyfinish); - stream.on("close", onlegacyfinish); - } - - // TODO(Soremwar) - // Bring back once requests are implemented - // if (typeof stream.aborted === "boolean") { - // stream.on("aborted", onclose); - // } - - stream.on("end", onend); - stream.on("finish", onfinish); - if (opts.error !== false) stream.on("error", onerror); - stream.on("close", onclose); - - const closed = ( - wState?.closed || - rState?.closed || - wState?.errorEmitted || - rState?.errorEmitted || - // TODO(Soremwar) - // Bring back once requests are implemented - // (rState && stream.req && stream.aborted) || - ( - (!writable || wState?.finished) && - (!readable || rState?.endEmitted) - ) - ); - - if (closed) { - queueMicrotask(callback); - } - - return function () { - callback = nop; - stream.removeListener("aborted", onclose); - stream.removeListener("complete", onfinish); - stream.removeListener("abort", onclose); - // TODO(Soremwar) - // Bring back once requests are implemented - // stream.removeListener("request", onrequest); - // 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); - }; -} diff --git a/std/node/_stream/end_of_stream_test.ts b/std/node/_stream/end_of_stream_test.ts deleted file mode 100644 index 571e75b99..000000000 --- a/std/node/_stream/end_of_stream_test.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import finished from "./end_of_stream.ts"; -import Readable from "./readable.ts"; -import Transform from "./transform.ts"; -import Writable from "./writable.ts"; -import { mustCall } from "../_utils.ts"; -import { assert, fail } from "../../testing/asserts.ts"; -import { deferred, delay } from "../../async/mod.ts"; - -Deno.test("Finished appends to Readable correctly", async () => { - const rs = new Readable({ - read() {}, - }); - - const [finishedExecution, finishedCb] = mustCall((err) => { - assert(!err); - }); - - finished(rs, finishedCb); - - rs.push(null); - rs.resume(); - - await finishedExecution; -}); - -Deno.test("Finished appends to Writable correctly", async () => { - const ws = new Writable({ - write(_data, _enc, cb) { - cb(); - }, - }); - - const [finishedExecution, finishedCb] = mustCall((err) => { - assert(!err); - }); - - finished(ws, finishedCb); - - ws.end(); - - await finishedExecution; -}); - -Deno.test("Finished appends to Transform correctly", async () => { - const tr = new Transform({ - transform(_data, _enc, cb) { - cb(); - }, - }); - - let finish = false; - let ended = false; - - tr.on("end", () => { - ended = true; - }); - - tr.on("finish", () => { - finish = true; - }); - - const [finishedExecution, finishedCb] = mustCall((err) => { - assert(!err); - assert(finish); - assert(ended); - }); - - finished(tr, finishedCb); - - tr.end(); - tr.resume(); - - await finishedExecution; -}); - -Deno.test("The function returned by Finished clears the listeners", async () => { - const finishedExecution = deferred(); - - const ws = new Writable({ - write(_data, _env, cb) { - cb(); - }, - }); - - const removeListener = finished(ws, () => { - finishedExecution.reject(); - }); - removeListener(); - ws.end(); - - await Promise.race([ - delay(100), - finishedExecution, - ]) - .catch(() => fail("Finished was executed")); -}); diff --git a/std/node/_stream/from.ts b/std/node/_stream/from.ts deleted file mode 100644 index 652c17715..000000000 --- a/std/node/_stream/from.ts +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Readable from "./readable.ts"; -import type { ReadableOptions } from "./readable.ts"; -import { ERR_INVALID_ARG_TYPE, ERR_STREAM_NULL_VALUES } from "../_errors.ts"; - -export default function from( - // deno-lint-ignore no-explicit-any - iterable: Iterable<any> | AsyncIterable<any>, - opts?: ReadableOptions, -) { - let iterator: - // deno-lint-ignore no-explicit-any - | Iterator<any, any, undefined> - // deno-lint-ignore no-explicit-any - | AsyncIterator<any, any, undefined>; - if (typeof iterable === "string" || iterable instanceof Buffer) { - return new Readable({ - objectMode: true, - ...opts, - read() { - this.push(iterable); - this.push(null); - }, - }); - } - - if (Symbol.asyncIterator in iterable) { - // deno-lint-ignore no-explicit-any - iterator = (iterable as AsyncIterable<any>)[Symbol.asyncIterator](); - } else if (Symbol.iterator in iterable) { - // deno-lint-ignore no-explicit-any - iterator = (iterable as Iterable<any>)[Symbol.iterator](); - } else { - throw new ERR_INVALID_ARG_TYPE("iterable", ["Iterable"], iterable); - } - - const readable = new Readable({ - objectMode: true, - highWaterMark: 1, - ...opts, - }); - - // Reading boolean to protect against _read - // being called before last iteration completion. - let reading = false; - - // needToClose boolean if iterator needs to be explicitly closed - let needToClose = false; - - readable._read = function () { - if (!reading) { - reading = true; - next(); - } - }; - - readable._destroy = function (error, cb) { - if (needToClose) { - needToClose = false; - close().then( - () => queueMicrotask(() => cb(error)), - (e) => queueMicrotask(() => cb(error || e)), - ); - } else { - cb(error); - } - }; - - async function close() { - if (typeof iterator.return === "function") { - const { value } = await iterator.return(); - await value; - } - } - - async function next() { - try { - needToClose = false; - const { value, done } = await iterator.next(); - needToClose = !done; - if (done) { - readable.push(null); - } else if (readable.destroyed) { - await close(); - } else { - const res = await value; - if (res === null) { - reading = false; - throw new ERR_STREAM_NULL_VALUES(); - } else if (readable.push(res)) { - next(); - } else { - reading = false; - } - } - } catch (err) { - readable.destroy(err); - } - } - return readable; -} diff --git a/std/node/_stream/passthrough.ts b/std/node/_stream/passthrough.ts deleted file mode 100644 index 9126420e5..000000000 --- a/std/node/_stream/passthrough.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import Transform from "./transform.ts"; -import type { TransformOptions } from "./transform.ts"; -import type { Encodings } from "../_utils.ts"; - -export default class PassThrough extends Transform { - constructor(options?: TransformOptions) { - super(options); - } - - _transform( - // deno-lint-ignore no-explicit-any - chunk: any, - _encoding: Encodings, - // deno-lint-ignore no-explicit-any - cb: (error?: Error | null, data?: any) => void, - ) { - cb(null, chunk); - } -} diff --git a/std/node/_stream/pipeline.ts b/std/node/_stream/pipeline.ts deleted file mode 100644 index d02a92870..000000000 --- a/std/node/_stream/pipeline.ts +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { once } from "../_utils.ts"; -import { destroyer as implDestroyer } from "./destroy.ts"; -import eos from "./end_of_stream.ts"; -import createReadableStreamAsyncIterator from "./async_iterator.ts"; -import * as events from "../events.ts"; -import PassThrough from "./passthrough.ts"; -import { - ERR_INVALID_ARG_TYPE, - ERR_INVALID_CALLBACK, - ERR_INVALID_RETURN_VALUE, - ERR_MISSING_ARGS, - ERR_STREAM_DESTROYED, - NodeErrorAbstraction, -} from "../_errors.ts"; -import type Duplex from "./duplex.ts"; -import type Readable from "./readable.ts"; -import type Stream from "./stream.ts"; -import type Transform from "./transform.ts"; -import type Writable from "./writable.ts"; - -type Streams = Duplex | Readable | Writable; -// deno-lint-ignore no-explicit-any -type EndCallback = (err?: NodeErrorAbstraction | null, val?: any) => void; -type TransformCallback = - // deno-lint-ignore no-explicit-any - | ((value?: any) => AsyncGenerator<any>) - // deno-lint-ignore no-explicit-any - | ((value?: any) => Promise<any>); -/** - * This type represents an array that contains a data source, - * many Transform Streams, a writable stream destination - * and end in an optional callback - * */ -type DataSource = - // deno-lint-ignore no-explicit-any - | (() => AsyncGenerator<any>) - | // deno-lint-ignore no-explicit-any - AsyncIterable<any> - | Duplex - | // deno-lint-ignore no-explicit-any - Iterable<any> - | // deno-lint-ignore no-explicit-any - (() => Generator<any>) - | Readable; -type Transformers = Duplex | Transform | TransformCallback | Writable; -export type PipelineArguments = [ - DataSource, - ...Array<Transformers | EndCallback>, -]; - -function destroyer( - stream: Streams, - reading: boolean, - writing: boolean, - callback: EndCallback, -) { - callback = once(callback); - - let finished = false; - stream.on("close", () => { - finished = true; - }); - - eos(stream, { readable: reading, writable: writing }, (err) => { - finished = !err; - - // deno-lint-ignore no-explicit-any - const rState = (stream as any)?._readableState; - if ( - err && - err.code === "ERR_STREAM_PREMATURE_CLOSE" && - reading && - (rState?.ended && !rState?.errored && !rState?.errorEmitted) - ) { - stream - .once("end", callback) - .once("error", callback); - } else { - callback(err); - } - }); - - return (err: NodeErrorAbstraction) => { - if (finished) return; - finished = true; - implDestroyer(stream, err); - callback(err || new ERR_STREAM_DESTROYED("pipe")); - }; -} - -function popCallback(streams: PipelineArguments): EndCallback { - if (typeof streams[streams.length - 1] !== "function") { - throw new ERR_INVALID_CALLBACK(streams[streams.length - 1]); - } - return streams.pop() as EndCallback; -} - -// function isPromise(obj) { -// return !!(obj && typeof obj.then === "function"); -// } - -// deno-lint-ignore no-explicit-any -function isReadable(obj: any): obj is Stream { - return !!(obj && typeof obj.pipe === "function"); -} - -// deno-lint-ignore no-explicit-any -function isWritable(obj: any) { - return !!(obj && typeof obj.write === "function"); -} - -// deno-lint-ignore no-explicit-any -function isStream(obj: any) { - return isReadable(obj) || isWritable(obj); -} - -// deno-lint-ignore no-explicit-any -function isIterable(obj: any, isAsync?: boolean) { - if (!obj) 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"; -} - -// deno-lint-ignore no-explicit-any -function makeAsyncIterable(val: Readable | Iterable<any> | AsyncIterable<any>) { - if (isIterable(val)) { - return val; - } else if (isReadable(val)) { - return fromReadable(val as Readable); - } - throw new ERR_INVALID_ARG_TYPE( - "val", - ["Readable", "Iterable", "AsyncIterable"], - val, - ); -} - -async function* fromReadable(val: Readable) { - yield* createReadableStreamAsyncIterator(val); -} - -async function pump( - // deno-lint-ignore no-explicit-any - iterable: Iterable<any>, - writable: Duplex | Writable, - finish: (err?: NodeErrorAbstraction | null) => void, -) { - let error; - try { - for await (const chunk of iterable) { - if (!writable.write(chunk)) { - if (writable.destroyed) return; - await events.once(writable, "drain"); - } - } - writable.end(); - } catch (err) { - error = err; - } finally { - finish(error); - } -} - -export default function pipeline(...args: PipelineArguments) { - const callback: EndCallback = once(popCallback(args)); - - let streams: [DataSource, ...Transformers[]]; - if (args.length > 1) { - streams = args as [DataSource, ...Transformers[]]; - } else { - throw new ERR_MISSING_ARGS("streams"); - } - - let error: NodeErrorAbstraction; - // deno-lint-ignore no-explicit-any - let value: any; - const destroys: Array<(err: NodeErrorAbstraction) => void> = []; - - let finishCount = 0; - - function finish(err?: NodeErrorAbstraction | null) { - const final = --finishCount === 0; - - if (err && (!error || error.code === "ERR_STREAM_PREMATURE_CLOSE")) { - error = err; - } - - if (!error && !final) { - return; - } - - while (destroys.length) { - (destroys.shift() as (err: NodeErrorAbstraction) => void)(error); - } - - if (final) { - callback(error, value); - } - } - - // TODO(Soremwar) - // Simplify the hell out of this - // deno-lint-ignore no-explicit-any - let ret: any; - for (let i = 0; i < streams.length; i++) { - const stream = streams[i]; - const reading = i < streams.length - 1; - const writing = i > 0; - - if (isStream(stream)) { - finishCount++; - destroys.push(destroyer(stream as Streams, reading, writing, finish)); - } - - if (i === 0) { - if (typeof stream === "function") { - ret = stream(); - if (!isIterable(ret)) { - throw new ERR_INVALID_RETURN_VALUE( - "Iterable, AsyncIterable or Stream", - "source", - ret, - ); - } - } else if (isIterable(stream) || isReadable(stream)) { - ret = stream; - } else { - throw new ERR_INVALID_ARG_TYPE( - "source", - ["Stream", "Iterable", "AsyncIterable", "Function"], - stream, - ); - } - } else if (typeof stream === "function") { - ret = makeAsyncIterable(ret); - ret = stream(ret); - - if (reading) { - if (!isIterable(ret, true)) { - throw new ERR_INVALID_RETURN_VALUE( - "AsyncIterable", - `transform[${i - 1}]`, - ret, - ); - } - } else { - // If the last argument to pipeline is not a stream - // we must create a proxy stream so that pipeline(...) - // always returns a stream which can be further - // composed through `.pipe(stream)`. - const pt = new PassThrough({ - objectMode: true, - }); - if (ret instanceof Promise) { - ret - .then((val) => { - value = val; - pt.end(val); - }, (err) => { - pt.destroy(err); - }); - } else if (isIterable(ret, true)) { - finishCount++; - pump(ret, pt, finish); - } else { - throw new ERR_INVALID_RETURN_VALUE( - "AsyncIterable or Promise", - "destination", - ret, - ); - } - - ret = pt; - - finishCount++; - destroys.push(destroyer(ret, false, true, finish)); - } - } else if (isStream(stream)) { - if (isReadable(ret)) { - ret.pipe(stream as Readable); - - // TODO(Soremwar) - // Reimplement after stdout and stderr are implemented - // if (stream === process.stdout || stream === process.stderr) { - // ret.on("end", () => stream.end()); - // } - } else { - ret = makeAsyncIterable(ret); - - finishCount++; - pump(ret, stream as Writable, finish); - } - ret = stream; - } else { - const name = reading ? `transform[${i - 1}]` : "destination"; - throw new ERR_INVALID_ARG_TYPE( - name, - ["Stream", "Function"], - ret, - ); - } - } - - return ret as unknown as Readable; -} diff --git a/std/node/_stream/pipeline_test.ts b/std/node/_stream/pipeline_test.ts deleted file mode 100644 index aa1869416..000000000 --- a/std/node/_stream/pipeline_test.ts +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import PassThrough from "./passthrough.ts"; -import pipeline from "./pipeline.ts"; -import Readable from "./readable.ts"; -import Transform from "./transform.ts"; -import Writable from "./writable.ts"; -import { mustCall } from "../_utils.ts"; -import { - assert, - assertEquals, - assertStrictEquals, -} from "../../testing/asserts.ts"; -import type { NodeErrorAbstraction } from "../_errors.ts"; - -Deno.test("Pipeline ends on stream finished", async () => { - let finished = false; - - // deno-lint-ignore no-explicit-any - const processed: any[] = []; - const expected = [ - Buffer.from("a"), - Buffer.from("b"), - Buffer.from("c"), - ]; - - const read = new Readable({ - read() {}, - }); - - const write = new Writable({ - write(data, _enc, cb) { - processed.push(data); - cb(); - }, - }); - - write.on("finish", () => { - finished = true; - }); - - for (let i = 0; i < expected.length; i++) { - read.push(expected[i]); - } - read.push(null); - - const [finishedCompleted, finishedCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assert(finished); - assertEquals(processed, expected); - }, - 1, - ); - - pipeline(read, write, finishedCb); - - await finishedCompleted; -}); - -Deno.test("Pipeline fails on stream destroyed", async () => { - const read = new Readable({ - read() {}, - }); - - const write = new Writable({ - write(_data, _enc, cb) { - cb(); - }, - }); - - read.push("data"); - queueMicrotask(() => read.destroy()); - - const [pipelineExecuted, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(err); - }, - 1, - ); - pipeline(read, write, pipelineCb); - - await pipelineExecuted; -}); - -Deno.test("Pipeline exits on stream error", async () => { - const read = new Readable({ - read() {}, - }); - - const transform = new Transform({ - transform(_data, _enc, cb) { - cb(new Error("kaboom")); - }, - }); - - const write = new Writable({ - write(_data, _enc, cb) { - cb(); - }, - }); - - const [readExecution, readCb] = mustCall(); - read.on("close", readCb); - const [closeExecution, closeCb] = mustCall(); - transform.on("close", closeCb); - const [writeExecution, writeCb] = mustCall(); - write.on("close", writeCb); - - const errorExecutions = [read, transform, write] - .map((stream) => { - const [execution, cb] = mustCall((err?: NodeErrorAbstraction | null) => { - assertEquals(err, new Error("kaboom")); - }); - - stream.on("error", cb); - return execution; - }); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assertEquals(err, new Error("kaboom")); - }, - ); - const dst = pipeline(read, transform, write, pipelineCb); - - assertStrictEquals(dst, write); - - read.push("hello"); - - await readExecution; - await closeExecution; - await writeExecution; - await Promise.all(errorExecutions); - await pipelineExecution; -}); - -Deno.test("Pipeline processes iterators correctly", async () => { - let res = ""; - const w = new Writable({ - write(chunk, _encoding, callback) { - res += chunk; - callback(); - }, - }); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assertEquals(res, "helloworld"); - }, - ); - pipeline( - function* () { - yield "hello"; - yield "world"; - }(), - w, - pipelineCb, - ); - - await pipelineExecution; -}); - -Deno.test("Pipeline processes async iterators correctly", async () => { - let res = ""; - const w = new Writable({ - write(chunk, _encoding, callback) { - res += chunk; - callback(); - }, - }); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assertEquals(res, "helloworld"); - }, - ); - pipeline( - async function* () { - await Promise.resolve(); - yield "hello"; - yield "world"; - }(), - w, - pipelineCb, - ); - - await pipelineExecution; -}); - -Deno.test("Pipeline processes generators correctly", async () => { - let res = ""; - const w = new Writable({ - write(chunk, _encoding, callback) { - res += chunk; - callback(); - }, - }); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assertEquals(res, "helloworld"); - }, - ); - pipeline( - function* () { - yield "hello"; - yield "world"; - }, - w, - pipelineCb, - ); - - await pipelineExecution; -}); - -Deno.test("Pipeline processes async generators correctly", async () => { - let res = ""; - const w = new Writable({ - write(chunk, _encoding, callback) { - res += chunk; - callback(); - }, - }); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assertEquals(res, "helloworld"); - }, - ); - pipeline( - async function* () { - await Promise.resolve(); - yield "hello"; - yield "world"; - }, - w, - pipelineCb, - ); - - await pipelineExecution; -}); - -Deno.test("Pipeline handles generator transforms", async () => { - let res = ""; - - const [pipelineExecuted, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assert(!err); - assertEquals(res, "HELLOWORLD"); - }, - ); - pipeline( - async function* () { - await Promise.resolve(); - yield "hello"; - yield "world"; - }, - async function* (source: string[]) { - for await (const chunk of source) { - yield chunk.toUpperCase(); - } - }, - async function (source: string[]) { - for await (const chunk of source) { - res += chunk; - } - }, - pipelineCb, - ); - - await pipelineExecuted; -}); - -Deno.test("Pipeline passes result to final callback", async () => { - const [pipelineExecuted, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null, val?: unknown) => { - assert(!err); - assertEquals(val, "HELLOWORLD"); - }, - ); - pipeline( - async function* () { - await Promise.resolve(); - yield "hello"; - yield "world"; - }, - async function* (source: string[]) { - for await (const chunk of source) { - yield chunk.toUpperCase(); - } - }, - async function (source: string[]) { - let ret = ""; - for await (const chunk of source) { - ret += chunk; - } - return ret; - }, - pipelineCb, - ); - - await pipelineExecuted; -}); - -Deno.test("Pipeline returns a stream after ending", async () => { - const [pipelineExecuted, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assertEquals(err, undefined); - }, - ); - const ret = pipeline( - async function* () { - await Promise.resolve(); - yield "hello"; - }, - // deno-lint-ignore require-yield - async function* (source: string[]) { - for await (const chunk of source) { - chunk; - } - }, - pipelineCb, - ); - - ret.resume(); - - assertEquals(typeof ret.pipe, "function"); - - await pipelineExecuted; -}); - -Deno.test("Pipeline returns a stream after erroring", async () => { - const errorText = "kaboom"; - - const [pipelineExecuted, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assertEquals(err?.message, errorText); - }, - ); - const ret = pipeline( - // deno-lint-ignore require-yield - async function* () { - await Promise.resolve(); - throw new Error(errorText); - }, - // deno-lint-ignore require-yield - async function* (source: string[]) { - for await (const chunk of source) { - chunk; - } - }, - pipelineCb, - ); - - ret.resume(); - - assertEquals(typeof ret.pipe, "function"); - - await pipelineExecuted; -}); - -Deno.test("Pipeline destination gets destroyed on error", async () => { - const errorText = "kaboom"; - const s = new PassThrough(); - - const [pipelineExecution, pipelineCb] = mustCall( - (err?: NodeErrorAbstraction | null) => { - assertEquals(err?.message, errorText); - assertEquals(s.destroyed, true); - }, - ); - pipeline( - // deno-lint-ignore require-yield - async function* () { - throw new Error(errorText); - }, - s, - pipelineCb, - ); - - await pipelineExecution; -}); diff --git a/std/node/_stream/promises.ts b/std/node/_stream/promises.ts deleted file mode 100644 index 1adf4ea3f..000000000 --- a/std/node/_stream/promises.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import pl from "./pipeline.ts"; -import type { PipelineArguments } from "./pipeline.ts"; -import eos from "./end_of_stream.ts"; -import type { - FinishedOptions, - StreamImplementations as FinishedStreams, -} from "./end_of_stream.ts"; - -export function pipeline(...streams: PipelineArguments) { - return new Promise((resolve, reject) => { - pl( - ...streams, - (err, value) => { - if (err) { - reject(err); - } else { - resolve(value); - } - }, - ); - }); -} - -export function finished( - stream: FinishedStreams, - opts?: FinishedOptions, -) { - return new Promise<void>((resolve, reject) => { - eos( - stream, - opts || null, - (err) => { - if (err) { - reject(err); - } else { - resolve(); - } - }, - ); - }); -} diff --git a/std/node/_stream/promises_test.ts b/std/node/_stream/promises_test.ts deleted file mode 100644 index 90803b4af..000000000 --- a/std/node/_stream/promises_test.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Readable from "./readable.ts"; -import Writable from "./writable.ts"; -import { pipeline } from "./promises.ts"; -import { deferred } from "../../async/mod.ts"; -import { - assert, - assertEquals, - assertThrowsAsync, -} from "../../testing/asserts.ts"; - -Deno.test("Promise pipeline works correctly", async () => { - let pipelineExecuted = 0; - const pipelineExecutedExpected = 1; - const pipelineExpectedExecutions = deferred(); - - let finished = false; - // deno-lint-ignore no-explicit-any - const processed: any[] = []; - const expected = [ - Buffer.from("a"), - Buffer.from("b"), - Buffer.from("c"), - ]; - - const read = new Readable({ - read() {}, - }); - - const write = new Writable({ - write(data, _enc, cb) { - processed.push(data); - cb(); - }, - }); - - write.on("finish", () => { - finished = true; - }); - - for (let i = 0; i < expected.length; i++) { - read.push(expected[i]); - } - read.push(null); - - pipeline(read, write).then(() => { - pipelineExecuted++; - if (pipelineExecuted == pipelineExecutedExpected) { - pipelineExpectedExecutions.resolve(); - } - assert(finished); - assertEquals(processed, expected); - }); - - const pipelineTimeout = setTimeout( - () => pipelineExpectedExecutions.reject(), - 1000, - ); - await pipelineExpectedExecutions; - clearTimeout(pipelineTimeout); - assertEquals(pipelineExecuted, pipelineExecutedExpected); -}); - -Deno.test("Promise pipeline throws on readable destroyed", async () => { - const read = new Readable({ - read() {}, - }); - - const write = new Writable({ - write(_data, _enc, cb) { - cb(); - }, - }); - - read.push("data"); - read.destroy(); - - await assertThrowsAsync( - () => pipeline(read, write), - Error, - "Premature close", - ); -}); diff --git a/std/node/_stream/readable.ts b/std/node/_stream/readable.ts deleted file mode 100644 index 54e0d8ecd..000000000 --- a/std/node/_stream/readable.ts +++ /dev/null @@ -1,788 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { captureRejectionSymbol } from "../events.ts"; -import Stream from "./stream.ts"; -import type { Buffer } from "../buffer.ts"; -import BufferList from "./buffer_list.ts"; -import { - ERR_INVALID_OPT_VALUE, - ERR_METHOD_NOT_IMPLEMENTED, -} from "../_errors.ts"; -import type { Encodings } from "../_utils.ts"; -import { StringDecoder } from "../string_decoder.ts"; -import createReadableStreamAsyncIterator from "./async_iterator.ts"; -import streamFrom from "./from.ts"; -import { kDestroy, kPaused } from "./symbols.ts"; -import { - _destroy, - computeNewHighWaterMark, - emitReadable, - endReadable, - errorOrDestroy, - fromList, - howMuchToRead, - nReadingNextTick, - pipeOnDrain, - prependListener, - readableAddChunk, - resume, - updateReadableListening, -} from "./readable_internal.ts"; -import Writable from "./writable.ts"; -import { errorOrDestroy as errorOrDestroyWritable } from "./writable_internal.ts"; -import Duplex, { errorOrDestroy as errorOrDestroyDuplex } from "./duplex.ts"; - -export interface ReadableOptions { - autoDestroy?: boolean; - defaultEncoding?: Encodings; - destroy?( - this: Readable, - error: Error | null, - callback: (error: Error | null) => void, - ): void; - emitClose?: boolean; - encoding?: Encodings; - highWaterMark?: number; - objectMode?: boolean; - read?(this: Readable): void; -} - -export class ReadableState { - [kPaused]: boolean | null = null; - awaitDrainWriters: Duplex | Writable | Set<Duplex | Writable> | null = null; - buffer = new BufferList(); - closed = false; - closeEmitted = false; - constructed: boolean; - decoder: StringDecoder | null = null; - destroyed = false; - emittedReadable = false; - encoding: Encodings | null = null; - ended = false; - endEmitted = false; - errored: Error | null = null; - errorEmitted = false; - flowing: boolean | null = null; - highWaterMark: number; - length = 0; - multiAwaitDrain = false; - needReadable = false; - objectMode: boolean; - pipes: Array<Duplex | Writable> = []; - readable = true; - readableListening = false; - reading = false; - readingMore = false; - resumeScheduled = false; - sync = true; - emitClose: boolean; - autoDestroy: boolean; - defaultEncoding: string; - - constructor(options?: ReadableOptions) { - this.objectMode = !!options?.objectMode; - - this.highWaterMark = options?.highWaterMark ?? - (this.objectMode ? 16 : 16 * 1024); - if (Number.isInteger(this.highWaterMark) && this.highWaterMark >= 0) { - this.highWaterMark = Math.floor(this.highWaterMark); - } else { - throw new ERR_INVALID_OPT_VALUE("highWaterMark", this.highWaterMark); - } - - this.emitClose = options?.emitClose ?? true; - this.autoDestroy = options?.autoDestroy ?? true; - this.defaultEncoding = options?.defaultEncoding || "utf8"; - - if (options?.encoding) { - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } - - this.constructed = true; - } -} - -class Readable extends Stream { - _readableState: ReadableState; - - constructor(options?: ReadableOptions) { - super(); - if (options) { - if (typeof options.read === "function") { - this._read = options.read; - } - if (typeof options.destroy === "function") { - this._destroy = options.destroy; - } - } - this._readableState = new ReadableState(options); - } - - static from( - // deno-lint-ignore no-explicit-any - iterable: Iterable<any> | AsyncIterable<any>, - opts?: ReadableOptions, - ): Readable { - return streamFrom(iterable, opts); - } - - static ReadableState = ReadableState; - - static _fromList = fromList; - - // You can override either this method, or the async _read(n) below. - read(n?: number) { - // Same as parseInt(undefined, 10), however V8 7.3 performance regressed - // in this scenario, so we are doing it manually. - if (n === undefined) { - n = NaN; - } - const state = this._readableState; - const nOrig = n; - - if (n > state.highWaterMark) { - state.highWaterMark = computeNewHighWaterMark(n); - } - - if (n !== 0) { - state.emittedReadable = false; - } - - if ( - n === 0 && - state.needReadable && - ((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; - } - - n = howMuchToRead(n, state); - - if (n === 0 && state.ended) { - if (state.length === 0) { - endReadable(this); - } - return null; - } - - let doRead = state.needReadable; - if ( - state.length === 0 || state.length - (n as number) < state.highWaterMark - ) { - doRead = true; - } - - if ( - state.ended || state.reading || state.destroyed || state.errored || - !state.constructed - ) { - doRead = false; - } else if (doRead) { - state.reading = true; - state.sync = true; - if (state.length === 0) { - state.needReadable = true; - } - this._read(); - state.sync = false; - if (!state.reading) { - n = howMuchToRead(nOrig, state); - } - } - - let ret; - if ((n as number) > 0) { - ret = fromList((n as number), state); - } else { - ret = null; - } - - if (ret === null) { - state.needReadable = state.length <= state.highWaterMark; - n = 0; - } else { - state.length -= n as number; - if (state.multiAwaitDrain) { - (state.awaitDrainWriters as Set<Writable>).clear(); - } else { - state.awaitDrainWriters = null; - } - } - - if (state.length === 0) { - if (!state.ended) { - state.needReadable = true; - } - - if (nOrig !== n && state.ended) { - endReadable(this); - } - } - - if (ret !== null) { - this.emit("data", ret); - } - - return ret; - } - - _read(_size?: number) { - throw new ERR_METHOD_NOT_IMPLEMENTED("_read()"); - } - - pipe<T extends Duplex | Writable>(dest: T, pipeOpts?: { end?: boolean }): T { - // deno-lint-ignore no-this-alias - const src = this; - const state = this._readableState; - - if (state.pipes.length === 1) { - if (!state.multiAwaitDrain) { - state.multiAwaitDrain = true; - state.awaitDrainWriters = new Set( - state.awaitDrainWriters ? [state.awaitDrainWriters as Writable] : [], - ); - } - } - - state.pipes.push(dest); - - const doEnd = (!pipeOpts || pipeOpts.end !== false); - - //TODO(Soremwar) - //Part of doEnd condition - //In node, output/input are a duplex Stream - // && - // dest !== stdout && - // dest !== stderr - - const endFn = doEnd ? onend : unpipe; - if (state.endEmitted) { - queueMicrotask(endFn); - } else { - this.once("end", endFn); - } - - dest.on("unpipe", onunpipe); - function onunpipe(readable: Readable, unpipeInfo: { hasUnpiped: boolean }) { - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } - } - } - - function onend() { - dest.end(); - } - - let ondrain: () => void; - - let cleanedUp = false; - function cleanup() { - dest.removeListener("close", onclose); - dest.removeListener("finish", onfinish); - if (ondrain) { - dest.removeListener("drain", ondrain); - } - dest.removeListener("error", onerror); - dest.removeListener("unpipe", onunpipe); - src.removeListener("end", onend); - src.removeListener("end", unpipe); - src.removeListener("data", ondata); - - cleanedUp = true; - if ( - ondrain && state.awaitDrainWriters && - (!dest._writableState || dest._writableState.needDrain) - ) { - ondrain(); - } - } - - this.on("data", ondata); - // deno-lint-ignore no-explicit-any - function ondata(chunk: any) { - const ret = dest.write(chunk); - if (ret === false) { - if (!cleanedUp) { - if (state.pipes.length === 1 && state.pipes[0] === dest) { - state.awaitDrainWriters = dest; - state.multiAwaitDrain = false; - } else if (state.pipes.length > 1 && state.pipes.includes(dest)) { - (state.awaitDrainWriters as Set<Duplex | Writable>).add(dest); - } - src.pause(); - } - if (!ondrain) { - ondrain = pipeOnDrain(src, dest); - dest.on("drain", ondrain); - } - } - } - - function onerror(er: Error) { - unpipe(); - dest.removeListener("error", onerror); - if (dest.listenerCount("error") === 0) { - const s = dest._writableState || (dest as Duplex)._readableState; - if (s && !s.errorEmitted) { - if (dest instanceof Duplex) { - errorOrDestroyDuplex(dest as unknown as Duplex, er); - } else { - errorOrDestroyWritable(dest as Writable, er); - } - } else { - dest.emit("error", er); - } - } - } - - prependListener(dest, "error", onerror); - - function onclose() { - dest.removeListener("finish", onfinish); - unpipe(); - } - dest.once("close", onclose); - function onfinish() { - dest.removeListener("close", onclose); - unpipe(); - } - dest.once("finish", onfinish); - - function unpipe() { - src.unpipe(dest as Writable); - } - - dest.emit("pipe", this); - - if (!state.flowing) { - this.resume(); - } - - return dest; - } - - isPaused() { - return this._readableState[kPaused] === true || - this._readableState.flowing === false; - } - - setEncoding(enc: Encodings) { - const decoder = new StringDecoder(enc); - this._readableState.decoder = decoder; - this._readableState.encoding = this._readableState.decoder - .encoding as Encodings; - - const buffer = this._readableState.buffer; - let content = ""; - for (const data of buffer) { - content += decoder.write(data as Buffer); - } - buffer.clear(); - if (content !== "") { - buffer.push(content); - } - this._readableState.length = content.length; - return this; - } - - on( - event: "close" | "end" | "pause" | "readable" | "resume", - listener: () => void, - ): this; - // deno-lint-ignore no-explicit-any - on(event: "data", listener: (chunk: any) => void): this; - on(event: "error", listener: (err: Error) => void): this; - // deno-lint-ignore no-explicit-any - on(event: string | symbol, listener: (...args: any[]) => void): this; - on( - ev: string | symbol, - fn: - | (() => void) - // deno-lint-ignore no-explicit-any - | ((chunk: any) => void) - | ((err: Error) => void) - // deno-lint-ignore no-explicit-any - | ((...args: any[]) => void), - ) { - const res = super.on.call(this, ev, fn); - const state = this._readableState; - - if (ev === "data") { - state.readableListening = this.listenerCount("readable") > 0; - - if (state.flowing !== false) { - this.resume(); - } - } else if (ev === "readable") { - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.flowing = false; - state.emittedReadable = false; - if (state.length) { - emitReadable(this); - } else if (!state.reading) { - queueMicrotask(() => nReadingNextTick(this)); - } - } - } - - return res; - } - - removeListener( - event: "close" | "end" | "pause" | "readable" | "resume", - listener: () => void, - ): this; - // deno-lint-ignore no-explicit-any - removeListener(event: "data", listener: (chunk: any) => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - removeListener( - event: string | symbol, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, - ): this; - removeListener( - ev: string | symbol, - fn: - | (() => void) - // deno-lint-ignore no-explicit-any - | ((chunk: any) => void) - | ((err: Error) => void) - // deno-lint-ignore no-explicit-any - | ((...args: any[]) => void), - ) { - const res = super.removeListener.call(this, ev, fn); - - if (ev === "readable") { - queueMicrotask(() => updateReadableListening(this)); - } - - return res; - } - - off = this.removeListener; - - destroy(err?: Error | null, cb?: () => void) { - const r = this._readableState; - - if (r.destroyed) { - if (typeof cb === "function") { - cb(); - } - - return this; - } - - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!r.errored) { - r.errored = err; - } - } - - r.destroyed = true; - - // If still constructing then defer calling _destroy. - if (!r.constructed) { - this.once(kDestroy, (er: Error) => { - _destroy(this, err || er, cb); - }); - } else { - _destroy(this, err, cb); - } - - return this; - } - - _undestroy() { - const r = this._readableState; - r.constructed = true; - r.closed = false; - r.closeEmitted = false; - r.destroyed = false; - r.errored = null; - r.errorEmitted = false; - r.reading = false; - r.ended = false; - r.endEmitted = false; - } - - _destroy( - error: Error | null, - callback: (error?: Error | null) => void, - ): void { - callback(error); - } - - [captureRejectionSymbol](err: Error) { - this.destroy(err); - } - - // deno-lint-ignore no-explicit-any - push(chunk: any, encoding?: Encodings): boolean { - return readableAddChunk(this, chunk, encoding, false); - } - - // deno-lint-ignore no-explicit-any - unshift(chunk: any, encoding?: string): boolean { - return readableAddChunk(this, chunk, encoding, true); - } - - unpipe(dest?: Writable): this { - const state = this._readableState; - const unpipeInfo = { hasUnpiped: false }; - - if (state.pipes.length === 0) { - return this; - } - - if (!dest) { - // remove all. - const dests = state.pipes; - state.pipes = []; - this.pause(); - - for (const dest of dests) { - dest.emit("unpipe", this, { hasUnpiped: false }); - } - return this; - } - - const index = state.pipes.indexOf(dest); - if (index === -1) { - return this; - } - - state.pipes.splice(index, 1); - if (state.pipes.length === 0) { - this.pause(); - } - - dest.emit("unpipe", this, unpipeInfo); - - return this; - } - - removeAllListeners( - ev: - | "close" - | "data" - | "end" - | "error" - | "pause" - | "readable" - | "resume" - | symbol - | undefined, - ) { - const res = super.removeAllListeners(ev); - - if (ev === "readable" || ev === undefined) { - queueMicrotask(() => updateReadableListening(this)); - } - - return res; - } - - resume() { - const state = this._readableState; - if (!state.flowing) { - // We flow only if there is no one listening - // for readable, but we still have to call - // resume(). - state.flowing = !state.readableListening; - resume(this, state); - } - state[kPaused] = false; - return this; - } - - pause() { - if (this._readableState.flowing !== false) { - this._readableState.flowing = false; - this.emit("pause"); - } - this._readableState[kPaused] = true; - return this; - } - - /** Wrap an old-style stream as the async data source. */ - wrap(stream: Stream): this { - const state = this._readableState; - let paused = false; - - stream.on("end", () => { - if (state.decoder && !state.ended) { - const chunk = state.decoder.end(); - if (chunk && chunk.length) { - this.push(chunk); - } - } - - this.push(null); - }); - - stream.on("data", (chunk) => { - if (state.decoder) { - chunk = state.decoder.write(chunk); - } - - if (state.objectMode && (chunk === null || chunk === undefined)) { - return; - } else if (!state.objectMode && (!chunk || !chunk.length)) { - return; - } - - const ret = this.push(chunk); - if (!ret) { - paused = true; - // By the time this is triggered, stream will be a readable stream - // deno-lint-ignore ban-ts-comment - // @ts-ignore - stream.pause(); - } - }); - - // TODO(Soremwar) - // There must be a clean way to implement this on TypeScript - // Proxy all the other methods. Important when wrapping filters and duplexes. - for (const i in stream) { - // deno-lint-ignore ban-ts-comment - //@ts-ignore - if (this[i] === undefined && typeof stream[i] === "function") { - // deno-lint-ignore ban-ts-comment - //@ts-ignore - this[i] = function methodWrap(method) { - return function methodWrapReturnFunction() { - // deno-lint-ignore ban-ts-comment - //@ts-ignore - return stream[method].apply(stream); - }; - }(i); - } - } - - stream.on("error", (err) => { - errorOrDestroy(this, err); - }); - - stream.on("close", () => { - this.emit("close"); - }); - - stream.on("destroy", () => { - this.emit("destroy"); - }); - - stream.on("pause", () => { - this.emit("pause"); - }); - - stream.on("resume", () => { - this.emit("resume"); - }); - - this._read = () => { - if (paused) { - paused = false; - // By the time this is triggered, stream will be a readable stream - // deno-lint-ignore ban-ts-comment - //@ts-ignore - stream.resume(); - } - }; - - return this; - } - - [Symbol.asyncIterator]() { - return createReadableStreamAsyncIterator(this); - } - - get readable(): boolean { - return this._readableState?.readable && - !this._readableState?.destroyed && - !this._readableState?.errorEmitted && - !this._readableState?.endEmitted; - } - set readable(val: boolean) { - if (this._readableState) { - this._readableState.readable = val; - } - } - - get readableHighWaterMark(): number { - return this._readableState.highWaterMark; - } - - get readableBuffer() { - return this._readableState && this._readableState.buffer; - } - - get readableFlowing(): boolean | null { - return this._readableState.flowing; - } - - set readableFlowing(state: boolean | null) { - if (this._readableState) { - this._readableState.flowing = state; - } - } - - get readableLength() { - return this._readableState.length; - } - - get readableObjectMode() { - return this._readableState ? this._readableState.objectMode : false; - } - - get readableEncoding() { - return this._readableState ? this._readableState.encoding : null; - } - - get destroyed() { - if (this._readableState === undefined) { - return false; - } - return this._readableState.destroyed; - } - - set destroyed(value: boolean) { - if (!this._readableState) { - return; - } - this._readableState.destroyed = value; - } - - get readableEnded() { - return this._readableState ? this._readableState.endEmitted : false; - } -} - -Object.defineProperties(Readable, { - _readableState: { enumerable: false }, - destroyed: { enumerable: false }, - readableBuffer: { enumerable: false }, - readableEncoding: { enumerable: false }, - readableEnded: { enumerable: false }, - readableFlowing: { enumerable: false }, - readableHighWaterMark: { enumerable: false }, - readableLength: { enumerable: false }, - readableObjectMode: { enumerable: false }, -}); - -export default Readable; diff --git a/std/node/_stream/readable_internal.ts b/std/node/_stream/readable_internal.ts deleted file mode 100644 index 0ef261d4d..000000000 --- a/std/node/_stream/readable_internal.ts +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import type Duplex from "./duplex.ts"; -import type EventEmitter from "../events.ts"; -import type Readable from "./readable.ts"; -import type Writable from "./writable.ts"; -import type { ReadableState } from "./readable.ts"; -import { kPaused } from "./symbols.ts"; -import { - ERR_STREAM_PUSH_AFTER_EOF, - ERR_STREAM_UNSHIFT_AFTER_END_EVENT, -} from "../_errors.ts"; - -export function _destroy( - self: Readable, - err?: Error | null, - cb?: (error?: Error | null) => void, -) { - self._destroy(err || null, (err) => { - const r = (self as Readable)._readableState; - - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!r.errored) { - r.errored = err; - } - } - - r.closed = true; - - if (typeof cb === "function") { - cb(err); - } - - if (err) { - queueMicrotask(() => { - if (!r.errorEmitted) { - r.errorEmitted = true; - self.emit("error", err); - } - r.closeEmitted = true; - if (r.emitClose) { - self.emit("close"); - } - }); - } else { - queueMicrotask(() => { - r.closeEmitted = true; - if (r.emitClose) { - self.emit("close"); - } - }); - } - }); -} - -export function addChunk( - stream: Duplex | Readable, - state: ReadableState, - chunk: string | Buffer | Uint8Array, - addToFront: boolean, -) { - if (state.flowing && state.length === 0 && !state.sync) { - if (state.multiAwaitDrain) { - (state.awaitDrainWriters as Set<Writable>).clear(); - } else { - state.awaitDrainWriters = null; - } - stream.emit("data", chunk); - } else { - // Update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) { - state.buffer.unshift(chunk); - } else { - state.buffer.push(chunk); - } - - if (state.needReadable) { - emitReadable(stream); - } - } - maybeReadMore(stream, state); -} - -// Don't raise the hwm > 1GB. -const MAX_HWM = 0x40000000; -export function computeNewHighWaterMark(n: number) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -export function emitReadable(stream: Duplex | Readable) { - const state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - state.emittedReadable = true; - queueMicrotask(() => emitReadable_(stream)); - } -} - -function emitReadable_(stream: Duplex | Readable) { - const state = stream._readableState; - if (!state.destroyed && !state.errored && (state.length || state.ended)) { - stream.emit("readable"); - state.emittedReadable = false; - } - - state.needReadable = !state.flowing && - !state.ended && - state.length <= state.highWaterMark; - flow(stream); -} - -export function endReadable(stream: Readable) { - const state = stream._readableState; - - if (!state.endEmitted) { - state.ended = true; - queueMicrotask(() => endReadableNT(state, stream)); - } -} - -function endReadableNT(state: ReadableState, stream: Readable) { - if ( - !state.errorEmitted && !state.closeEmitted && - !state.endEmitted && state.length === 0 - ) { - state.endEmitted = true; - stream.emit("end"); - - if (state.autoDestroy) { - stream.destroy(); - } - } -} - -export function errorOrDestroy( - stream: Duplex | Readable, - err: Error, - sync = false, -) { - const r = stream._readableState; - - if (r.destroyed) { - return stream; - } - - if (r.autoDestroy) { - stream.destroy(err); - } else if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!r.errored) { - r.errored = err; - } - if (sync) { - queueMicrotask(() => { - if (!r.errorEmitted) { - r.errorEmitted = true; - stream.emit("error", err); - } - }); - } else if (!r.errorEmitted) { - r.errorEmitted = true; - stream.emit("error", err); - } - } -} - -function flow(stream: Duplex | Readable) { - const state = stream._readableState; - while (state.flowing && stream.read() !== null); -} - -/** Pluck off n bytes from an array of buffers. -* Length is the combined lengths of all the buffers in the list. -* This function is designed to be inlinable, so please take care when making -* changes to the function body. -*/ -export function fromList(n: number, state: ReadableState) { - // nothing buffered. - if (state.length === 0) { - return null; - } - - let ret; - if (state.objectMode) { - ret = state.buffer.shift(); - } else if (!n || n >= state.length) { - 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(); - } else { - ret = state.buffer.consume(n, !!state.decoder); - } - - return ret; -} - -export function howMuchToRead(n: number, state: ReadableState) { - if (n <= 0 || (state.length === 0 && state.ended)) { - return 0; - } - if (state.objectMode) { - return 1; - } - if (Number.isNaN(n)) { - // Only flow one buffer at a time. - if (state.flowing && state.length) { - return state.buffer.first().length; - } - return state.length; - } - if (n <= state.length) { - return n; - } - return state.ended ? state.length : 0; -} - -export function maybeReadMore(stream: Readable, state: ReadableState) { - if (!state.readingMore && state.constructed) { - state.readingMore = true; - queueMicrotask(() => maybeReadMore_(stream, state)); - } -} - -function maybeReadMore_(stream: Readable, state: ReadableState) { - while ( - !state.reading && !state.ended && - (state.length < state.highWaterMark || - (state.flowing && state.length === 0)) - ) { - const len = state.length; - stream.read(0); - if (len === state.length) { - // Didn't get any data, stop spinning. - break; - } - } - state.readingMore = false; -} - -export function nReadingNextTick(self: Duplex | Readable) { - self.read(0); -} - -export function onEofChunk(stream: Duplex | Readable, state: ReadableState) { - if (state.ended) return; - if (state.decoder) { - const chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - if (state.sync) { - emitReadable(stream); - } else { - state.needReadable = false; - state.emittedReadable = true; - emitReadable_(stream); - } -} - -export function pipeOnDrain(src: Duplex | Readable, dest: Duplex | Writable) { - return function pipeOnDrainFunctionResult() { - const state = src._readableState; - - if (state.awaitDrainWriters === dest) { - state.awaitDrainWriters = null; - } else if (state.multiAwaitDrain) { - (state.awaitDrainWriters as Set<Duplex | Writable>).delete(dest); - } - - if ( - (!state.awaitDrainWriters || - (state.awaitDrainWriters as Set<Writable>).size === 0) && - src.listenerCount("data") - ) { - state.flowing = true; - flow(src); - } - }; -} - -export function prependListener( - emitter: EventEmitter, - event: string, - // deno-lint-ignore no-explicit-any - fn: (...args: any[]) => any, -) { - if (typeof emitter.prependListener === "function") { - return emitter.prependListener(event, fn); - } - - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - //the prependListener() method. The goal is to eventually remove this hack. - // TODO(Soremwar) - // Burn it with fire - // deno-lint-ignore ban-ts-comment - //@ts-ignore - if (emitter._events.get(event)?.length) { - // deno-lint-ignore ban-ts-comment - //@ts-ignore - const listeners = [fn, ...emitter._events.get(event)]; - // deno-lint-ignore ban-ts-comment - //@ts-ignore - emitter._events.set(event, listeners); - } else { - emitter.on(event, fn); - } -} - -export function readableAddChunk( - stream: Duplex | Readable, - chunk: string | Buffer | Uint8Array | null, - encoding: undefined | string = undefined, - addToFront: boolean, -) { - const state = stream._readableState; - let usedEncoding = encoding; - - let err; - if (!state.objectMode) { - if (typeof chunk === "string") { - usedEncoding = encoding || state.defaultEncoding; - if (state.encoding !== usedEncoding) { - if (addToFront && state.encoding) { - chunk = Buffer.from(chunk, usedEncoding).toString(state.encoding); - } else { - chunk = Buffer.from(chunk, usedEncoding); - usedEncoding = ""; - } - } - } else if (chunk instanceof Uint8Array) { - chunk = Buffer.from(chunk); - } - } - - if (err) { - errorOrDestroy(stream, err); - } else if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else if (state.objectMode || (chunk.length > 0)) { - if (addToFront) { - if (state.endEmitted) { - errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); - } else { - addChunk(stream, state, chunk, true); - } - } else if (state.ended) { - errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); - } else if (state.destroyed || state.errored) { - return false; - } else { - state.reading = false; - if (state.decoder && !usedEncoding) { - //TODO(Soremwar) - //I don't think this cast is right - chunk = state.decoder.write(Buffer.from(chunk as Uint8Array)); - if (state.objectMode || chunk.length !== 0) { - addChunk(stream, state, chunk, false); - } else { - maybeReadMore(stream, state); - } - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - maybeReadMore(stream, state); - } - - return !state.ended && - (state.length < state.highWaterMark || state.length === 0); -} - -export function resume(stream: Duplex | Readable, state: ReadableState) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - queueMicrotask(() => resume_(stream, state)); - } -} - -function resume_(stream: Duplex | Readable, state: ReadableState) { - if (!state.reading) { - stream.read(0); - } - - state.resumeScheduled = false; - stream.emit("resume"); - flow(stream); - if (state.flowing && !state.reading) { - stream.read(0); - } -} - -export function updateReadableListening(self: Duplex | Readable) { - const state = self._readableState; - state.readableListening = self.listenerCount("readable") > 0; - - if (state.resumeScheduled && state[kPaused] === false) { - // Flowing needs to be set to true now, otherwise - // the upcoming resume will not flow. - state.flowing = true; - - // Crude way to check if we should resume. - } else if (self.listenerCount("data") > 0) { - self.resume(); - } else if (!state.readableListening) { - state.flowing = null; - } -} diff --git a/std/node/_stream/readable_test.ts b/std/node/_stream/readable_test.ts deleted file mode 100644 index 72767e28f..000000000 --- a/std/node/_stream/readable_test.ts +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Readable from "../_stream/readable.ts"; -import { once } from "../events.ts"; -import { deferred } from "../../async/mod.ts"; -import { - assert, - assertEquals, - assertStrictEquals, -} from "../../testing/asserts.ts"; - -Deno.test("Readable stream from iterator", async () => { - function* generate() { - yield "a"; - yield "b"; - yield "c"; - } - - const stream = Readable.from(generate()); - - const expected = ["a", "b", "c"]; - - for await (const chunk of stream) { - assertStrictEquals(chunk, expected.shift()); - } -}); - -Deno.test("Readable stream from async iterator", async () => { - async function* generate() { - yield "a"; - yield "b"; - yield "c"; - } - - const stream = Readable.from(generate()); - - const expected = ["a", "b", "c"]; - - for await (const chunk of stream) { - assertStrictEquals(chunk, expected.shift()); - } -}); - -Deno.test("Readable stream from promise", async () => { - const promises = [ - Promise.resolve("a"), - Promise.resolve("b"), - Promise.resolve("c"), - ]; - - const stream = Readable.from(promises); - - const expected = ["a", "b", "c"]; - - for await (const chunk of stream) { - assertStrictEquals(chunk, expected.shift()); - } -}); - -Deno.test("Readable stream from string", async () => { - const string = "abc"; - const stream = Readable.from(string); - - for await (const chunk of stream) { - assertStrictEquals(chunk, string); - } -}); - -Deno.test("Readable stream from Buffer", async () => { - const string = "abc"; - const stream = Readable.from(Buffer.from(string)); - - for await (const chunk of stream) { - assertStrictEquals((chunk as Buffer).toString(), string); - } -}); - -Deno.test("Readable stream gets destroyed on error", async () => { - // deno-lint-ignore require-yield - async function* generate() { - throw new Error("kaboom"); - } - - const stream = Readable.from(generate()); - - stream.read(); - - const [err] = await once(stream, "error"); - assertStrictEquals(err.message, "kaboom"); - assertStrictEquals(stream.destroyed, true); -}); - -Deno.test("Readable stream works as Transform stream", async () => { - async function* generate(stream: Readable) { - for await (const chunk of stream) { - yield (chunk as string).toUpperCase(); - } - } - - const source = new Readable({ - objectMode: true, - read() { - this.push("a"); - this.push("b"); - this.push("c"); - this.push(null); - }, - }); - - const stream = Readable.from(generate(source)); - - const expected = ["A", "B", "C"]; - - for await (const chunk of stream) { - assertStrictEquals(chunk, expected.shift()); - } -}); - -Deno.test("Readable stream can be paused", () => { - const readable = new Readable(); - - // _read is a noop, here. - readable._read = () => {}; - - // Default state of a stream is not "paused" - assert(!readable.isPaused()); - - // Make the stream start flowing... - readable.on("data", () => {}); - - // still not paused. - assert(!readable.isPaused()); - - readable.pause(); - assert(readable.isPaused()); - readable.resume(); - assert(!readable.isPaused()); -}); - -Deno.test("Readable stream sets enconding correctly", () => { - const readable = new Readable({ - read() {}, - }); - - readable.setEncoding("utf8"); - - readable.push(new TextEncoder().encode("DEF")); - readable.unshift(new TextEncoder().encode("ABC")); - - assertStrictEquals(readable.read(), "ABCDEF"); -}); - -Deno.test("Readable stream sets encoding correctly", () => { - const readable = new Readable({ - read() {}, - }); - - readable.setEncoding("utf8"); - - readable.push(new TextEncoder().encode("DEF")); - readable.unshift(new TextEncoder().encode("ABC")); - - assertStrictEquals(readable.read(), "ABCDEF"); -}); - -Deno.test("Readable stream holds up a big push", async () => { - let readExecuted = 0; - const readExecutedExpected = 3; - const readExpectedExecutions = deferred(); - - let endExecuted = 0; - const endExecutedExpected = 1; - const endExpectedExecutions = deferred(); - - const str = "asdfasdfasdfasdfasdf"; - - const r = new Readable({ - highWaterMark: 5, - encoding: "utf8", - }); - - let reads = 0; - - function _read() { - if (reads === 0) { - setTimeout(() => { - r.push(str); - }, 1); - reads++; - } else if (reads === 1) { - const ret = r.push(str); - assertEquals(ret, false); - reads++; - } else { - r.push(null); - } - } - - r._read = () => { - readExecuted++; - if (readExecuted == readExecutedExpected) { - readExpectedExecutions.resolve(); - } - _read(); - }; - - r.on("end", () => { - endExecuted++; - if (endExecuted == endExecutedExpected) { - endExpectedExecutions.resolve(); - } - }); - - // Push some data in to start. - // We've never gotten any read event at this point. - const ret = r.push(str); - assert(!ret); - let chunk = r.read(); - assertEquals(chunk, str); - chunk = r.read(); - assertEquals(chunk, null); - - r.once("readable", () => { - // This time, we'll get *all* the remaining data, because - // it's been added synchronously, as the read WOULD take - // us below the hwm, and so it triggered a _read() again, - // which synchronously added more, which we then return. - chunk = r.read(); - assertEquals(chunk, str + str); - - chunk = r.read(); - assertEquals(chunk, null); - }); - - const readTimeout = setTimeout( - () => readExpectedExecutions.reject(), - 1000, - ); - const endTimeout = setTimeout( - () => endExpectedExecutions.reject(), - 1000, - ); - await readExpectedExecutions; - await endExpectedExecutions; - clearTimeout(readTimeout); - clearTimeout(endTimeout); - assertEquals(readExecuted, readExecutedExpected); - assertEquals(endExecuted, endExecutedExpected); -}); - -Deno.test("Readable stream: 'on' event", async () => { - async function* generate() { - yield "a"; - yield "b"; - yield "c"; - } - - const stream = Readable.from(generate()); - - let iterations = 0; - const expected = ["a", "b", "c"]; - - stream.on("data", (chunk) => { - iterations++; - assertStrictEquals(chunk, expected.shift()); - }); - - await once(stream, "end"); - - assertStrictEquals(iterations, 3); -}); - -Deno.test("Readable stream: 'data' event", async () => { - async function* generate() { - yield "a"; - yield "b"; - yield "c"; - } - - const stream = Readable.from(generate(), { objectMode: false }); - - let iterations = 0; - const expected = ["a", "b", "c"]; - - stream.on("data", (chunk) => { - iterations++; - assertStrictEquals(chunk instanceof Buffer, true); - assertStrictEquals(chunk.toString(), expected.shift()); - }); - - await once(stream, "end"); - - assertStrictEquals(iterations, 3); -}); - -Deno.test("Readable stream: 'data' event on non-object", async () => { - async function* generate() { - yield "a"; - yield "b"; - yield "c"; - } - - const stream = Readable.from(generate(), { objectMode: false }); - - let iterations = 0; - const expected = ["a", "b", "c"]; - - stream.on("data", (chunk) => { - iterations++; - assertStrictEquals(chunk instanceof Buffer, true); - assertStrictEquals(chunk.toString(), expected.shift()); - }); - - await once(stream, "end"); - - assertStrictEquals(iterations, 3); -}); - -Deno.test("Readable stream: 'readable' event is emitted but 'read' is not on highWaterMark length exceeded", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - const r = new Readable({ - highWaterMark: 3, - }); - - r._read = () => { - throw new Error("_read must not be called"); - }; - r.push(Buffer.from("blerg")); - - setTimeout(function () { - assert(!r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - clearTimeout(readableTimeout); - assertEquals(readableExecuted, readableExecutedExpected); -}); - -Deno.test("Readable stream: 'readable' and 'read' events are emitted on highWaterMark length not reached", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - let readExecuted = 0; - const readExecutedExpected = 1; - const readExpectedExecutions = deferred(); - - const r = new Readable({ - highWaterMark: 3, - }); - - r._read = () => { - readExecuted++; - if (readExecuted == readExecutedExpected) { - readExpectedExecutions.resolve(); - } - }; - - r.push(Buffer.from("bl")); - - setTimeout(function () { - assert(r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - const readTimeout = setTimeout( - () => readExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - await readExpectedExecutions; - clearTimeout(readableTimeout); - clearTimeout(readTimeout); - assertEquals(readableExecuted, readableExecutedExpected); - assertEquals(readExecuted, readExecutedExpected); -}); - -Deno.test("Readable stream: 'readable' event is emitted but 'read' is not on highWaterMark length not reached and stream ended", async () => { - let readableExecuted = 0; - const readableExecutedExpected = 1; - const readableExpectedExecutions = deferred(); - - const r = new Readable({ - highWaterMark: 30, - }); - - r._read = () => { - throw new Error("Must not be executed"); - }; - - r.push(Buffer.from("blerg")); - //This ends the stream and triggers end - r.push(null); - - setTimeout(function () { - // Assert we're testing what we think we are - assert(!r._readableState.reading); - r.on("readable", () => { - readableExecuted++; - if (readableExecuted == readableExecutedExpected) { - readableExpectedExecutions.resolve(); - } - }); - }, 1); - - const readableTimeout = setTimeout( - () => readableExpectedExecutions.reject(), - 1000, - ); - await readableExpectedExecutions; - clearTimeout(readableTimeout); - assertEquals(readableExecuted, readableExecutedExpected); -}); - -Deno.test("Readable stream: 'read' is emitted on empty string pushed in non-object mode", async () => { - let endExecuted = 0; - const endExecutedExpected = 1; - const endExpectedExecutions = deferred(); - - const underlyingData = ["", "x", "y", "", "z"]; - const expected = underlyingData.filter((data) => data); - const result: unknown[] = []; - - const r = new Readable({ - encoding: "utf8", - }); - r._read = function () { - queueMicrotask(() => { - if (!underlyingData.length) { - this.push(null); - } else { - this.push(underlyingData.shift()); - } - }); - }; - - r.on("readable", () => { - const data = r.read(); - if (data !== null) result.push(data); - }); - - r.on("end", () => { - endExecuted++; - if (endExecuted == endExecutedExpected) { - endExpectedExecutions.resolve(); - } - assertEquals(result, expected); - }); - - const endTimeout = setTimeout( - () => endExpectedExecutions.reject(), - 1000, - ); - await endExpectedExecutions; - clearTimeout(endTimeout); - assertEquals(endExecuted, endExecutedExpected); -}); - -Deno.test("Readable stream: listeners can be removed", () => { - const r = new Readable(); - r._read = () => {}; - r.on("data", () => {}); - - r.removeAllListeners("data"); - - assertEquals(r.eventNames().length, 0); -}); diff --git a/std/node/_stream/stream.ts b/std/node/_stream/stream.ts deleted file mode 100644 index 4daafc77b..000000000 --- a/std/node/_stream/stream.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import EventEmitter from "../events.ts"; -import type Readable from "./readable.ts"; -import type Writable from "./writable.ts"; -import { types } from "../util.ts"; - -class Stream extends EventEmitter { - constructor() { - super(); - } - - static _isUint8Array = types.isUint8Array; - static _uint8ArrayToBuffer = (chunk: Uint8Array) => Buffer.from(chunk); - - pipe(dest: Readable | Writable, options?: { end?: boolean }) { - // deno-lint-ignore no-this-alias - const source = this; - - //TODO(Soremwar) - //isStdio exist on stdin || stdout only, which extend from Duplex - //if (!dest._isStdio && (options?.end ?? true)) { - //Find an alternative to be able to pipe streams to stdin & stdout - //Port them as well? - if (options?.end ?? true) { - source.on("end", onend); - source.on("close", onclose); - } - - let didOnEnd = false; - function onend() { - if (didOnEnd) return; - didOnEnd = true; - - // 'end' is only called on Writable streams - (dest as Writable).end(); - } - - function onclose() { - if (didOnEnd) return; - didOnEnd = true; - - if (typeof dest.destroy === "function") dest.destroy(); - } - - // Don't leave dangling pipes when there are errors. - function onerror(this: Stream, er: Error) { - cleanup(); - if (this.listenerCount("error") === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on("error", onerror); - dest.on("error", onerror); - - // Remove all the event listeners that were added. - function cleanup() { - source.removeListener("end", onend); - source.removeListener("close", onclose); - - source.removeListener("error", onerror); - dest.removeListener("error", onerror); - - source.removeListener("end", cleanup); - source.removeListener("close", cleanup); - - dest.removeListener("close", cleanup); - } - - source.on("end", cleanup); - source.on("close", cleanup); - - dest.on("close", cleanup); - dest.emit("pipe", source); - - return dest; - } -} - -export default Stream; diff --git a/std/node/_stream/symbols.ts b/std/node/_stream/symbols.ts deleted file mode 100644 index addb969d3..000000000 --- a/std/node/_stream/symbols.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -export const kConstruct = Symbol("kConstruct"); -export const kDestroy = Symbol("kDestroy"); -export const kPaused = Symbol("kPaused"); diff --git a/std/node/_stream/transform.ts b/std/node/_stream/transform.ts deleted file mode 100644 index a4246e81a..000000000 --- a/std/node/_stream/transform.ts +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Encodings } from "../_utils.ts"; -import Duplex from "./duplex.ts"; -import type { DuplexOptions } from "./duplex.ts"; -import type { writeV } from "./writable_internal.ts"; -import { ERR_METHOD_NOT_IMPLEMENTED } from "../_errors.ts"; - -const kCallback = Symbol("kCallback"); - -type TransformFlush = ( - this: Transform, - // deno-lint-ignore no-explicit-any - callback: (error?: Error | null, data?: any) => void, -) => void; - -export interface TransformOptions extends DuplexOptions { - read?(this: Transform, size: number): void; - write?( - this: Transform, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: Encodings, - callback: (error?: Error | null) => void, - ): void; - writev?: writeV; - final?(this: Transform, callback: (error?: Error | null) => void): void; - destroy?( - this: Transform, - error: Error | null, - callback: (error: Error | null) => void, - ): void; - transform?( - this: Transform, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: Encodings, - // deno-lint-ignore no-explicit-any - callback: (error?: Error | null, data?: any) => void, - ): void; - flush?: TransformFlush; -} - -export default class Transform extends Duplex { - [kCallback]: null | ((error?: Error | null) => void); - _flush?: TransformFlush; - - constructor(options?: TransformOptions) { - super(options); - this._readableState.sync = false; - - this[kCallback] = null; - - if (options) { - if (typeof options.transform === "function") { - this._transform = options.transform; - } - - if (typeof options.flush === "function") { - this._flush = options.flush; - } - } - - this.on("prefinish", function (this: Transform) { - if (typeof this._flush === "function" && !this.destroyed) { - this._flush((er, data) => { - if (er) { - this.destroy(er); - return; - } - - if (data != null) { - this.push(data); - } - this.push(null); - }); - } else { - this.push(null); - } - }); - } - - _read = () => { - if (this[kCallback]) { - const callback = this[kCallback] as (error?: Error | null) => void; - this[kCallback] = null; - callback(); - } - }; - - _transform( - // deno-lint-ignore no-explicit-any - _chunk: any, - _encoding: string, - // deno-lint-ignore no-explicit-any - _callback: (error?: Error | null, data?: any) => void, - ) { - throw new ERR_METHOD_NOT_IMPLEMENTED("_transform()"); - } - - _write = ( - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: string, - callback: (error?: Error | null) => void, - ) => { - const rState = this._readableState; - const wState = this._writableState; - const length = rState.length; - - this._transform(chunk, encoding, (err, val) => { - if (err) { - callback(err); - return; - } - - if (val != null) { - this.push(val); - } - - if ( - wState.ended || // Backwards compat. - length === rState.length || // Backwards compat. - rState.length < rState.highWaterMark || - rState.length === 0 - ) { - callback(); - } else { - this[kCallback] = callback; - } - }); - }; -} diff --git a/std/node/_stream/transform_test.ts b/std/node/_stream/transform_test.ts deleted file mode 100644 index d3b90ff01..000000000 --- a/std/node/_stream/transform_test.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Transform from "./transform.ts"; -import finished from "./end_of_stream.ts"; -import { deferred } from "../../async/mod.ts"; -import { assert, assertEquals } from "../../testing/asserts.ts"; - -Deno.test("Transform stream finishes correctly", async () => { - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExecution = deferred(); - - const tr = new Transform({ - transform(_data, _enc, cb) { - cb(); - }, - }); - - let finish = false; - let ended = false; - - tr.on("end", () => { - ended = true; - }); - - tr.on("finish", () => { - finish = true; - }); - - finished(tr, (err) => { - finishedExecuted++; - if (finishedExecuted === finishedExecutedExpected) { - finishedExecution.resolve(); - } - assert(!err, "no error"); - assert(finish); - assert(ended); - }); - - tr.end(); - tr.resume(); - - const finishedTimeout = setTimeout( - () => finishedExecution.reject(), - 1000, - ); - await finishedExecution; - clearTimeout(finishedTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); -}); - -Deno.test("Transform stream flushes data correctly", () => { - const expected = "asdf"; - - const t = new Transform({ - transform: (_d, _e, n) => { - n(); - }, - flush: (n) => { - n(null, expected); - }, - }); - - t.end(Buffer.from("blerg")); - t.on("data", (data) => { - assertEquals(data.toString(), expected); - }); -}); diff --git a/std/node/_stream/writable.ts b/std/node/_stream/writable.ts deleted file mode 100644 index 534fc22fb..000000000 --- a/std/node/_stream/writable.ts +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import Stream from "./stream.ts"; -import { captureRejectionSymbol } from "../events.ts"; -import { - ERR_INVALID_ARG_TYPE, - ERR_INVALID_OPT_VALUE, - ERR_METHOD_NOT_IMPLEMENTED, - ERR_STREAM_ALREADY_FINISHED, - ERR_STREAM_CANNOT_PIPE, - ERR_STREAM_DESTROYED, - ERR_STREAM_NULL_VALUES, - ERR_STREAM_WRITE_AFTER_END, - ERR_UNKNOWN_ENCODING, -} from "../_errors.ts"; -import type { AfterWriteTick, writeV } from "./writable_internal.ts"; -import { - clearBuffer, - destroy, - errorBuffer, - errorOrDestroy, - finishMaybe, - kOnFinished, - nop, - onwrite, - resetBuffer, - writeOrBuffer, -} from "./writable_internal.ts"; -import type { Encodings } from "../_utils.ts"; - -type WritableEncodings = Encodings | "buffer"; - -export interface WritableOptions { - autoDestroy?: boolean; - decodeStrings?: boolean; - defaultEncoding?: WritableEncodings; - destroy?( - this: Writable, - error: Error | null, - callback: (error: Error | null) => void, - ): void; - emitClose?: boolean; - final?(this: Writable, callback: (error?: Error | null) => void): void; - highWaterMark?: number; - objectMode?: boolean; - write?( - this: Writable, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: WritableEncodings, - callback: (error?: Error | null) => void, - ): void; - writev?( - this: Writable, - // deno-lint-ignore no-explicit-any - chunks: Array<{ chunk: any; encoding: string }>, - callback: (error?: Error | null) => void, - ): void; -} - -export class WritableState { - [kOnFinished]: Array<(error?: Error) => void> = []; - afterWriteTickInfo: null | AfterWriteTick = null; - allBuffers = true; - allNoop = true; - autoDestroy: boolean; - buffered: Array<{ - allBuffers?: boolean; - // deno-lint-ignore no-explicit-any - chunk: any; - encoding: string; - callback: (error: Error) => void; - }> = []; - bufferedIndex = 0; - bufferProcessing = false; - closed = false; - closeEmitted = false; - constructed: boolean; - corked = 0; - decodeStrings: boolean; - defaultEncoding: WritableEncodings; - destroyed = false; - emitClose: boolean; - ended = false; - ending = false; - errored: Error | null = null; - errorEmitted = false; - finalCalled = false; - finished = false; - highWaterMark: number; - length = 0; - needDrain = false; - objectMode: boolean; - onwrite: (error?: Error | null) => void; - pendingcb = 0; - prefinished = false; - sync = true; - writecb: null | ((error: Error) => void) = null; - writable = true; - writelen = 0; - writing = false; - - constructor(options: WritableOptions | undefined, stream: Writable) { - this.objectMode = !!options?.objectMode; - - this.highWaterMark = options?.highWaterMark ?? - (this.objectMode ? 16 : 16 * 1024); - - if (Number.isInteger(this.highWaterMark) && this.highWaterMark >= 0) { - this.highWaterMark = Math.floor(this.highWaterMark); - } else { - throw new ERR_INVALID_OPT_VALUE("highWaterMark", this.highWaterMark); - } - - this.decodeStrings = !options?.decodeStrings === false; - - this.defaultEncoding = options?.defaultEncoding || "utf8"; - - this.onwrite = onwrite.bind(undefined, stream); - - resetBuffer(this); - - this.emitClose = options?.emitClose ?? true; - this.autoDestroy = options?.autoDestroy ?? true; - this.constructed = true; - } - - getBuffer() { - return this.buffered.slice(this.bufferedIndex); - } - - get bufferedRequestCount() { - return this.buffered.length - this.bufferedIndex; - } -} - -/** A bit simpler than readable streams. -* Implement an async `._write(chunk, encoding, cb)`, and it'll handle all -* the drain event emission and buffering. -*/ -class Writable extends Stream { - _final?: ( - this: Writable, - callback: (error?: Error | null | undefined) => void, - ) => void; - _writableState: WritableState; - _writev?: writeV | null = null; - - constructor(options?: WritableOptions) { - super(); - this._writableState = new WritableState(options, this); - - 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; - } - } - } - - [captureRejectionSymbol](err?: Error) { - this.destroy(err); - } - - static WritableState = WritableState; - - get destroyed() { - return this._writableState ? this._writableState.destroyed : false; - } - - set destroyed(value) { - if (this._writableState) { - this._writableState.destroyed = value; - } - } - - get writable() { - const w = this._writableState; - return !w.destroyed && !w.errored && !w.ending && !w.ended; - } - - set writable(val) { - if (this._writableState) { - this._writableState.writable = !!val; - } - } - - get writableFinished() { - return this._writableState ? this._writableState.finished : false; - } - - get writableObjectMode() { - return this._writableState ? this._writableState.objectMode : false; - } - - get writableBuffer() { - return this._writableState && this._writableState.getBuffer(); - } - - get writableEnded() { - return this._writableState ? this._writableState.ending : false; - } - - get writableHighWaterMark() { - return this._writableState && this._writableState.highWaterMark; - } - - get writableCorked() { - return this._writableState ? this._writableState.corked : 0; - } - - get writableLength() { - return this._writableState && this._writableState.length; - } - - _undestroy() { - const w = this._writableState; - w.constructed = true; - w.destroyed = false; - w.closed = false; - w.closeEmitted = false; - w.errored = null; - w.errorEmitted = false; - w.ended = false; - w.ending = false; - w.finalCalled = false; - w.prefinished = false; - w.finished = false; - } - - _destroy(err: Error | null, cb: (error?: Error | null) => void) { - cb(err); - } - - destroy(err?: Error | null, cb?: () => void) { - const state = this._writableState; - if (!state.destroyed) { - queueMicrotask(() => errorBuffer(state)); - } - destroy.call(this, err, cb); - return this; - } - - end(cb?: () => void): void; - // deno-lint-ignore no-explicit-any - end(chunk: any, cb?: () => void): void; - // deno-lint-ignore no-explicit-any - end(chunk: any, encoding: WritableEncodings, cb?: () => void): void; - - end( - // deno-lint-ignore no-explicit-any - x?: any | (() => void), - y?: WritableEncodings | (() => void), - z?: () => void, - ) { - const state = this._writableState; - // deno-lint-ignore no-explicit-any - let chunk: any | null; - let encoding: WritableEncodings | null; - let cb: undefined | ((error?: Error) => void); - - if (typeof x === "function") { - chunk = null; - encoding = null; - cb = x; - } else if (typeof y === "function") { - chunk = x; - encoding = null; - cb = y; - } else { - chunk = x; - encoding = y as WritableEncodings; - cb = z; - } - - if (chunk !== null && chunk !== undefined) { - this.write(chunk, encoding); - } - - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - let err: Error | undefined; - if (!state.errored && !state.ending) { - state.ending = true; - finishMaybe(this, state, true); - state.ended = true; - } else if (state.finished) { - err = new ERR_STREAM_ALREADY_FINISHED("end"); - } else if (state.destroyed) { - err = new ERR_STREAM_DESTROYED("end"); - } - - if (typeof cb === "function") { - if (err || state.finished) { - queueMicrotask(() => { - (cb as (error?: Error | undefined) => void)(err); - }); - } else { - state[kOnFinished].push(cb); - } - } - - return this; - } - - _write( - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: string, - cb: (error?: Error | null) => void, - ): void { - if (this._writev) { - this._writev([{ chunk, encoding }], cb); - } else { - throw new ERR_METHOD_NOT_IMPLEMENTED("_write()"); - } - } - - //This signature was changed to keep inheritance coherent - pipe(dest: Writable): Writable { - errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); - return dest; - } - - // deno-lint-ignore no-explicit-any - write(chunk: any, cb?: (error: Error | null | undefined) => void): boolean; - write( - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: WritableEncodings | null, - cb?: (error: Error | null | undefined) => void, - ): boolean; - - write( - // deno-lint-ignore no-explicit-any - chunk: any, - x?: WritableEncodings | null | ((error: Error | null | undefined) => void), - y?: ((error: Error | null | undefined) => void), - ) { - const state = this._writableState; - let encoding: WritableEncodings; - let cb: (error?: Error | null) => void; - - if (typeof x === "function") { - cb = x; - encoding = state.defaultEncoding; - } else { - if (!x) { - encoding = state.defaultEncoding; - } else if (x !== "buffer" && !Buffer.isEncoding(x)) { - throw new ERR_UNKNOWN_ENCODING(x); - } else { - encoding = x; - } - if (typeof y !== "function") { - cb = nop; - } else { - cb = y; - } - } - - if (chunk === null) { - throw new ERR_STREAM_NULL_VALUES(); - } else if (!state.objectMode) { - if (typeof chunk === "string") { - if (state.decodeStrings !== false) { - chunk = Buffer.from(chunk, encoding); - encoding = "buffer"; - } - } else if (chunk instanceof Buffer) { - encoding = "buffer"; - } else if (Stream._isUint8Array(chunk)) { - chunk = Stream._uint8ArrayToBuffer(chunk); - encoding = "buffer"; - } else { - throw new ERR_INVALID_ARG_TYPE( - "chunk", - ["string", "Buffer", "Uint8Array"], - chunk, - ); - } - } - - let err: Error | undefined; - if (state.ending) { - err = new ERR_STREAM_WRITE_AFTER_END(); - } else if (state.destroyed) { - err = new ERR_STREAM_DESTROYED("write"); - } - - if (err) { - queueMicrotask(() => cb(err)); - errorOrDestroy(this, err, true); - return false; - } - state.pendingcb++; - return writeOrBuffer(this, state, chunk, encoding, cb); - } - - cork() { - this._writableState.corked++; - } - - uncork() { - const state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing) { - clearBuffer(this, state); - } - } - } - - setDefaultEncoding(encoding: string) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === "string") { - encoding = encoding.toLowerCase(); - } - if (!Buffer.isEncoding(encoding)) { - throw new ERR_UNKNOWN_ENCODING(encoding); - } - this._writableState.defaultEncoding = encoding as WritableEncodings; - return this; - } -} - -export default Writable; diff --git a/std/node/_stream/writable_internal.ts b/std/node/_stream/writable_internal.ts deleted file mode 100644 index e8c001af0..000000000 --- a/std/node/_stream/writable_internal.ts +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import type Duplex from "./duplex.ts"; -import type Writable from "./writable.ts"; -import type { WritableState } from "./writable.ts"; -import { kDestroy } from "./symbols.ts"; -import { ERR_MULTIPLE_CALLBACK, ERR_STREAM_DESTROYED } from "../_errors.ts"; - -export type writeV = ( - // deno-lint-ignore no-explicit-any - chunks: Array<{ chunk: any; encoding: string }>, - callback: (error?: Error | null) => void, -) => void; - -export type AfterWriteTick = { - cb: (error?: Error) => void; - count: number; - state: WritableState; - stream: Writable; -}; - -export const kOnFinished = Symbol("kOnFinished"); - -function _destroy( - self: Writable, - err?: Error | null, - cb?: (error?: Error | null) => void, -) { - self._destroy(err || null, (err) => { - const w = self._writableState; - - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!w.errored) { - w.errored = err; - } - } - - w.closed = true; - - if (typeof cb === "function") { - cb(err); - } - - if (err) { - queueMicrotask(() => { - if (!w.errorEmitted) { - w.errorEmitted = true; - self.emit("error", err); - } - w.closeEmitted = true; - if (w.emitClose) { - self.emit("close"); - } - }); - } else { - queueMicrotask(() => { - w.closeEmitted = true; - if (w.emitClose) { - self.emit("close"); - } - }); - } - }); -} - -export function afterWrite( - stream: Writable, - state: WritableState, - count: number, - cb: (error?: Error) => void, -) { - const needDrain = !state.ending && !stream.destroyed && state.length === 0 && - state.needDrain; - if (needDrain) { - state.needDrain = false; - stream.emit("drain"); - } - - while (count-- > 0) { - state.pendingcb--; - cb(); - } - - if (state.destroyed) { - errorBuffer(state); - } - - finishMaybe(stream, state); -} - -export function afterWriteTick({ - cb, - count, - state, - stream, -}: AfterWriteTick) { - state.afterWriteTickInfo = null; - return afterWrite(stream, state, count, cb); -} - -/** If there's something in the buffer waiting, then process it.*/ -export function clearBuffer(stream: Duplex | Writable, state: WritableState) { - if ( - state.corked || - state.bufferProcessing || - state.destroyed || - !state.constructed - ) { - return; - } - - const { buffered, bufferedIndex, objectMode } = state; - const bufferedLength = buffered.length - bufferedIndex; - - if (!bufferedLength) { - return; - } - - const i = bufferedIndex; - - state.bufferProcessing = true; - if (bufferedLength > 1 && stream._writev) { - state.pendingcb -= bufferedLength - 1; - - const callback = state.allNoop ? nop : (err: Error) => { - for (let n = i; n < buffered.length; ++n) { - buffered[n].callback(err); - } - }; - const chunks = state.allNoop && i === 0 ? buffered : buffered.slice(i); - - doWrite(stream, state, true, state.length, chunks, "", callback); - - resetBuffer(state); - } else { - do { - const { chunk, encoding, callback } = buffered[i]; - const len = objectMode ? 1 : chunk.length; - doWrite(stream, state, false, len, chunk, encoding, callback); - } while (i < buffered.length && !state.writing); - - if (i === buffered.length) { - resetBuffer(state); - } else if (i > 256) { - buffered.splice(0, i); - state.bufferedIndex = 0; - } else { - state.bufferedIndex = i; - } - } - state.bufferProcessing = false; -} - -export function destroy(this: Writable, err?: Error | null, cb?: () => void) { - const w = this._writableState; - - if (w.destroyed) { - if (typeof cb === "function") { - cb(); - } - - return this; - } - - if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!w.errored) { - w.errored = err; - } - } - - w.destroyed = true; - - if (!w.constructed) { - this.once(kDestroy, (er) => { - _destroy(this, err || er, cb); - }); - } else { - _destroy(this, err, cb); - } - - return this; -} - -function doWrite( - stream: Duplex | Writable, - state: WritableState, - writev: boolean, - len: number, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: string, - cb: (error: Error) => void, -) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (state.destroyed) { - state.onwrite(new ERR_STREAM_DESTROYED("write")); - } else if (writev) { - (stream._writev as unknown as writeV)(chunk, state.onwrite); - } else { - stream._write(chunk, encoding, state.onwrite); - } - state.sync = false; -} - -/** If there's something in the buffer waiting, then invoke callbacks.*/ -export function errorBuffer(state: WritableState) { - if (state.writing) { - return; - } - - for (let n = state.bufferedIndex; n < state.buffered.length; ++n) { - const { chunk, callback } = state.buffered[n]; - const len = state.objectMode ? 1 : chunk.length; - state.length -= len; - callback(new ERR_STREAM_DESTROYED("write")); - } - - for (const callback of state[kOnFinished].splice(0)) { - callback(new ERR_STREAM_DESTROYED("end")); - } - - resetBuffer(state); -} - -export function errorOrDestroy(stream: Writable, err: Error, sync = false) { - const w = stream._writableState; - - if (w.destroyed) { - return stream; - } - - if (w.autoDestroy) { - stream.destroy(err); - } else if (err) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - err.stack; - - if (!w.errored) { - w.errored = err; - } - if (sync) { - queueMicrotask(() => { - if (w.errorEmitted) { - return; - } - w.errorEmitted = true; - stream.emit("error", err); - }); - } else { - if (w.errorEmitted) { - return; - } - w.errorEmitted = true; - stream.emit("error", err); - } - } -} - -function finish(stream: Writable, state: WritableState) { - state.pendingcb--; - if (state.errorEmitted || state.closeEmitted) { - return; - } - - state.finished = true; - - for (const callback of state[kOnFinished].splice(0)) { - callback(); - } - - stream.emit("finish"); - - if (state.autoDestroy) { - stream.destroy(); - } -} - -export function finishMaybe( - stream: Writable, - state: WritableState, - sync?: boolean, -) { - if (needFinish(state)) { - prefinish(stream, state); - if (state.pendingcb === 0 && needFinish(state)) { - state.pendingcb++; - if (sync) { - queueMicrotask(() => finish(stream, state)); - } else { - finish(stream, state); - } - } - } -} - -export function needFinish(state: WritableState) { - return (state.ending && - state.constructed && - state.length === 0 && - !state.errored && - state.buffered.length === 0 && - !state.finished && - !state.writing); -} - -export function nop() {} - -export function resetBuffer(state: WritableState) { - state.buffered = []; - state.bufferedIndex = 0; - state.allBuffers = true; - state.allNoop = true; -} - -function onwriteError( - stream: Writable, - state: WritableState, - er: Error, - cb: (error: Error) => void, -) { - --state.pendingcb; - - cb(er); - errorBuffer(state); - errorOrDestroy(stream, er); -} - -export function onwrite(stream: Writable, er?: Error | null) { - const state = stream._writableState; - const sync = state.sync; - const cb = state.writecb; - - if (typeof cb !== "function") { - errorOrDestroy(stream, new ERR_MULTIPLE_CALLBACK()); - return; - } - - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; - - if (er) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - er.stack; - - if (!state.errored) { - state.errored = er; - } - - if (sync) { - queueMicrotask(() => onwriteError(stream, state, er, cb)); - } else { - onwriteError(stream, state, er, cb); - } - } else { - if (state.buffered.length > state.bufferedIndex) { - clearBuffer(stream, state); - } - - if (sync) { - if ( - state.afterWriteTickInfo !== null && - state.afterWriteTickInfo.cb === cb - ) { - state.afterWriteTickInfo.count++; - } else { - state.afterWriteTickInfo = { - count: 1, - cb: (cb as (error?: Error) => void), - stream, - state, - }; - queueMicrotask(() => - afterWriteTick(state.afterWriteTickInfo as AfterWriteTick) - ); - } - } else { - afterWrite(stream, state, 1, cb as (error?: Error) => void); - } - } -} - -export function prefinish(stream: Writable, state: WritableState) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === "function" && !state.destroyed) { - state.finalCalled = true; - - state.sync = true; - state.pendingcb++; - stream._final((err) => { - state.pendingcb--; - if (err) { - for (const callback of state[kOnFinished].splice(0)) { - callback(err); - } - errorOrDestroy(stream, err, state.sync); - } else if (needFinish(state)) { - state.prefinished = true; - stream.emit("prefinish"); - state.pendingcb++; - queueMicrotask(() => finish(stream, state)); - } - }); - state.sync = false; - } else { - state.prefinished = true; - stream.emit("prefinish"); - } - } -} - -export function writeOrBuffer( - stream: Duplex | Writable, - state: WritableState, - // deno-lint-ignore no-explicit-any - chunk: any, - encoding: string, - callback: (error: Error) => void, -) { - const len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - if (state.writing || state.corked || state.errored || !state.constructed) { - state.buffered.push({ chunk, encoding, callback }); - if (state.allBuffers && encoding !== "buffer") { - state.allBuffers = false; - } - if (state.allNoop && callback !== nop) { - state.allNoop = false; - } - } else { - state.writelen = len; - state.writecb = callback; - state.writing = true; - state.sync = true; - stream._write(chunk, encoding, state.onwrite); - state.sync = false; - } - - const ret = state.length < state.highWaterMark; - - if (!ret) { - state.needDrain = true; - } - - return ret && !state.errored && !state.destroyed; -} diff --git a/std/node/_stream/writable_test.ts b/std/node/_stream/writable_test.ts deleted file mode 100644 index d6133b65f..000000000 --- a/std/node/_stream/writable_test.ts +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. MIT License. -import { Buffer } from "../buffer.ts"; -import finished from "./end_of_stream.ts"; -import Writable from "../_stream/writable.ts"; -import { deferred } from "../../async/mod.ts"; -import { - assert, - assertEquals, - assertStrictEquals, - assertThrows, -} from "../../testing/asserts.ts"; - -Deno.test("Writable stream writes correctly", async () => { - let callback: undefined | ((error?: Error | null | undefined) => void); - - let writeExecuted = 0; - const writeExecutedExpected = 1; - const writeExpectedExecutions = deferred(); - - let writevExecuted = 0; - const writevExecutedExpected = 1; - const writevExpectedExecutions = deferred(); - - const writable = new Writable({ - write: (chunk, encoding, cb) => { - writeExecuted++; - if (writeExecuted == writeExecutedExpected) { - writeExpectedExecutions.resolve(); - } - assert(chunk instanceof Buffer); - assertStrictEquals(encoding, "buffer"); - assertStrictEquals(String(chunk), "ABC"); - callback = cb; - }, - writev: (chunks) => { - writevExecuted++; - if (writevExecuted == writevExecutedExpected) { - writevExpectedExecutions.resolve(); - } - assertStrictEquals(chunks.length, 2); - assertStrictEquals(chunks[0].encoding, "buffer"); - assertStrictEquals(chunks[1].encoding, "buffer"); - assertStrictEquals(chunks[0].chunk + chunks[1].chunk, "DEFGHI"); - }, - }); - - writable.write(new TextEncoder().encode("ABC")); - writable.write(new TextEncoder().encode("DEF")); - writable.end(new TextEncoder().encode("GHI")); - callback?.(); - - const writeTimeout = setTimeout( - () => writeExpectedExecutions.reject(), - 1000, - ); - const writevTimeout = setTimeout( - () => writevExpectedExecutions.reject(), - 1000, - ); - await writeExpectedExecutions; - await writevExpectedExecutions; - clearTimeout(writeTimeout); - clearTimeout(writevTimeout); - assertEquals(writeExecuted, writeExecutedExpected); - assertEquals(writevExecuted, writevExecutedExpected); -}); - -Deno.test("Writable stream writes Uint8Array in object mode", async () => { - let writeExecuted = 0; - const writeExecutedExpected = 1; - const writeExpectedExecutions = deferred(); - - const ABC = new TextEncoder().encode("ABC"); - - const writable = new Writable({ - objectMode: true, - write: (chunk, encoding, cb) => { - writeExecuted++; - if (writeExecuted == writeExecutedExpected) { - writeExpectedExecutions.resolve(); - } - assert(!(chunk instanceof Buffer)); - assert(chunk instanceof Uint8Array); - assertEquals(chunk, ABC); - assertEquals(encoding, "utf8"); - cb(); - }, - }); - - writable.end(ABC); - - const writeTimeout = setTimeout( - () => writeExpectedExecutions.reject(), - 1000, - ); - await writeExpectedExecutions; - clearTimeout(writeTimeout); - assertEquals(writeExecuted, writeExecutedExpected); -}); - -Deno.test("Writable stream throws on unexpected close", async () => { - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExpectedExecutions = deferred(); - - const writable = new Writable({ - write: () => {}, - }); - writable.writable = false; - writable.destroy(); - - finished(writable, (err) => { - finishedExecuted++; - if (finishedExecuted == finishedExecutedExpected) { - finishedExpectedExecutions.resolve(); - } - assertEquals(err?.code, "ERR_STREAM_PREMATURE_CLOSE"); - }); - - const finishedTimeout = setTimeout( - () => finishedExpectedExecutions.reject(), - 1000, - ); - await finishedExpectedExecutions; - clearTimeout(finishedTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); -}); - -Deno.test("Writable stream finishes correctly", async () => { - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExpectedExecutions = deferred(); - - const w = new Writable({ - write(_chunk, _encoding, cb) { - cb(); - }, - autoDestroy: false, - }); - - w.end("asd"); - - queueMicrotask(() => { - finished(w, () => { - finishedExecuted++; - if (finishedExecuted == finishedExecutedExpected) { - finishedExpectedExecutions.resolve(); - } - }); - }); - - const finishedTimeout = setTimeout( - () => finishedExpectedExecutions.reject(), - 1000, - ); - await finishedExpectedExecutions; - clearTimeout(finishedTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); -}); - -Deno.test("Writable stream finishes correctly after error", async () => { - let errorExecuted = 0; - const errorExecutedExpected = 1; - const errorExpectedExecutions = deferred(); - - let finishedExecuted = 0; - const finishedExecutedExpected = 1; - const finishedExpectedExecutions = deferred(); - - const w = new Writable({ - write(_chunk, _encoding, cb) { - cb(new Error()); - }, - autoDestroy: false, - }); - w.write("asd"); - w.on("error", () => { - errorExecuted++; - if (errorExecuted == errorExecutedExpected) { - errorExpectedExecutions.resolve(); - } - finished(w, () => { - finishedExecuted++; - if (finishedExecuted == finishedExecutedExpected) { - finishedExpectedExecutions.resolve(); - } - }); - }); - - const errorTimeout = setTimeout( - () => errorExpectedExecutions.reject(), - 1000, - ); - const finishedTimeout = setTimeout( - () => finishedExpectedExecutions.reject(), - 1000, - ); - await finishedExpectedExecutions; - await errorExpectedExecutions; - clearTimeout(finishedTimeout); - clearTimeout(errorTimeout); - assertEquals(finishedExecuted, finishedExecutedExpected); - assertEquals(errorExecuted, errorExecutedExpected); -}); - -Deno.test("Writable stream fails on 'write' null value", () => { - const writable = new Writable(); - assertThrows(() => writable.write(null)); -}); diff --git a/std/node/_util/_util_callbackify.ts b/std/node/_util/_util_callbackify.ts deleted file mode 100644 index e0b862b0e..000000000 --- a/std/node/_util/_util_callbackify.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// These are simplified versions of the "real" errors in Node. -class NodeFalsyValueRejectionError extends Error { - public reason: unknown; - public code = "ERR_FALSY_VALUE_REJECTION"; - constructor(reason: unknown) { - super("Promise was rejected with falsy value"); - this.reason = reason; - } -} -class NodeInvalidArgTypeError extends TypeError { - public code = "ERR_INVALID_ARG_TYPE"; - constructor(argumentName: string) { - super(`The ${argumentName} argument must be of type function.`); - } -} - -type Callback<ResultT> = - | ((err: Error) => void) - | ((err: null, result: ResultT) => void); - -function callbackify<ResultT>( - fn: () => PromiseLike<ResultT>, -): (callback: Callback<ResultT>) => void; -function callbackify<ArgT, ResultT>( - fn: (arg: ArgT) => PromiseLike<ResultT>, -): (arg: ArgT, callback: Callback<ResultT>) => void; -function callbackify<Arg1T, Arg2T, ResultT>( - fn: (arg1: Arg1T, arg2: Arg2T) => PromiseLike<ResultT>, -): (arg1: Arg1T, arg2: Arg2T, callback: Callback<ResultT>) => void; -function callbackify<Arg1T, Arg2T, Arg3T, ResultT>( - fn: (arg1: Arg1T, arg2: Arg2T, arg3: Arg3T) => PromiseLike<ResultT>, -): (arg1: Arg1T, arg2: Arg2T, arg3: Arg3T, callback: Callback<ResultT>) => void; -function callbackify<Arg1T, Arg2T, Arg3T, Arg4T, ResultT>( - fn: ( - arg1: Arg1T, - arg2: Arg2T, - arg3: Arg3T, - arg4: Arg4T, - ) => PromiseLike<ResultT>, -): ( - arg1: Arg1T, - arg2: Arg2T, - arg3: Arg3T, - arg4: Arg4T, - callback: Callback<ResultT>, -) => void; -function callbackify<Arg1T, Arg2T, Arg3T, Arg4T, Arg5T, ResultT>( - fn: ( - arg1: Arg1T, - arg2: Arg2T, - arg3: Arg3T, - arg4: Arg4T, - arg5: Arg5T, - ) => PromiseLike<ResultT>, -): ( - arg1: Arg1T, - arg2: Arg2T, - arg3: Arg3T, - arg4: Arg4T, - arg5: Arg5T, - callback: Callback<ResultT>, -) => void; - -// deno-lint-ignore no-explicit-any -function callbackify(original: any): any { - if (typeof original !== "function") { - throw new NodeInvalidArgTypeError('"original"'); - } - - const callbackified = function (this: unknown, ...args: unknown[]): void { - const maybeCb = args.pop(); - if (typeof maybeCb !== "function") { - throw new NodeInvalidArgTypeError("last"); - } - const cb = (...args: unknown[]): void => { - maybeCb.apply(this, args); - }; - original.apply(this, args).then( - (ret: unknown) => { - queueMicrotask(cb.bind(this, null, ret)); - }, - (rej: unknown) => { - rej = rej || new NodeFalsyValueRejectionError(rej); - queueMicrotask(cb.bind(this, rej)); - }, - ); - }; - - const descriptors = Object.getOwnPropertyDescriptors(original); - // It is possible to manipulate a functions `length` or `name` property. This - // guards against the manipulation. - if (typeof descriptors.length.value === "number") { - descriptors.length.value++; - } - if (typeof descriptors.name.value === "string") { - descriptors.name.value += "Callbackified"; - } - Object.defineProperties(callbackified, descriptors); - return callbackified; -} - -export { callbackify }; diff --git a/std/node/_util/_util_callbackify_test.ts b/std/node/_util/_util_callbackify_test.ts deleted file mode 100644 index 9e5281409..000000000 --- a/std/node/_util/_util_callbackify_test.ts +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -import { assert, assertStrictEquals } from "../../testing/asserts.ts"; -import { callbackify } from "./_util_callbackify.ts"; - -const values = [ - "hello world", - null, - undefined, - false, - 0, - {}, - { key: "value" }, - Symbol("I am a symbol"), - function ok(): void {}, - ["array", "with", 4, "values"], - new Error("boo"), -]; - -class TestQueue { - #waitingPromise: Promise<void>; - #resolve?: () => void; - #reject?: (err: unknown) => void; - #queueSize = 0; - - constructor() { - this.#waitingPromise = new Promise((resolve, reject) => { - this.#resolve = resolve; - this.#reject = reject; - }); - } - - enqueue(fn: (done: () => void) => void): void { - this.#queueSize++; - try { - fn(() => { - this.#queueSize--; - if (this.#queueSize === 0) { - assert( - this.#resolve, - "Test setup error; async queue is missing #resolve", - ); - this.#resolve(); - } - }); - } catch (err) { - assert(this.#reject, "Test setup error; async queue is missing #reject"); - this.#reject(err); - } - } - - waitForCompletion(): Promise<void> { - return this.#waitingPromise; - } -} - -Deno.test( - "callbackify passes the resolution value as the second argument to the callback", - async () => { - const testQueue = new TestQueue(); - - for (const value of values) { - // deno-lint-ignore require-await - const asyncFn = async (): Promise<typeof value> => { - return value; - }; - const cbAsyncFn = callbackify(asyncFn); - testQueue.enqueue((done) => { - cbAsyncFn((err: unknown, ret: unknown) => { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - done(); - }); - }); - - const promiseFn = (): Promise<typeof value> => { - return Promise.resolve(value); - }; - const cbPromiseFn = callbackify(promiseFn); - testQueue.enqueue((done) => { - cbPromiseFn((err: unknown, ret: unknown) => { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - done(); - }); - }); - - // deno-lint-ignore no-explicit-any - const thenableFn = (): PromiseLike<any> => { - return { - // deno-lint-ignore no-explicit-any - then(onfulfilled): PromiseLike<any> { - assert(onfulfilled); - onfulfilled(value); - return this; - }, - }; - }; - const cbThenableFn = callbackify(thenableFn); - testQueue.enqueue((done) => { - cbThenableFn((err: unknown, ret: unknown) => { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - done(); - }); - }); - } - - await testQueue.waitForCompletion(); - }, -); - -Deno.test( - "callbackify passes the rejection value as the first argument to the callback", - async () => { - const testQueue = new TestQueue(); - - for (const value of values) { - // deno-lint-ignore require-await - const asyncFn = async (): Promise<never> => { - return Promise.reject(value); - }; - const cbAsyncFn = callbackify(asyncFn); - assertStrictEquals(cbAsyncFn.length, 1); - assertStrictEquals(cbAsyncFn.name, "asyncFnCallbackified"); - testQueue.enqueue((done) => { - cbAsyncFn((err: unknown, ret: unknown) => { - assertStrictEquals(ret, undefined); - if (err instanceof Error) { - if ("reason" in err) { - assert(!value); - assertStrictEquals( - // deno-lint-ignore no-explicit-any - (err as any).code, - "ERR_FALSY_VALUE_REJECTION", - ); - // deno-lint-ignore no-explicit-any - assertStrictEquals((err as any).reason, value); - } else { - assertStrictEquals(String(value).endsWith(err.message), true); - } - } else { - assertStrictEquals(err, value); - } - done(); - }); - }); - - const promiseFn = (): Promise<never> => { - return Promise.reject(value); - }; - const obj = {}; - Object.defineProperty(promiseFn, "name", { - value: obj, - writable: false, - enumerable: false, - configurable: true, - }); - - const cbPromiseFn = callbackify(promiseFn); - assertStrictEquals(promiseFn.name, obj); - testQueue.enqueue((done) => { - cbPromiseFn((err: unknown, ret: unknown) => { - assertStrictEquals(ret, undefined); - if (err instanceof Error) { - if ("reason" in err) { - assert(!value); - assertStrictEquals( - // deno-lint-ignore no-explicit-any - (err as any).code, - "ERR_FALSY_VALUE_REJECTION", - ); - // deno-lint-ignore no-explicit-any - assertStrictEquals((err as any).reason, value); - } else { - assertStrictEquals(String(value).endsWith(err.message), true); - } - } else { - assertStrictEquals(err, value); - } - done(); - }); - }); - - const thenableFn = (): PromiseLike<never> => { - return { - then(onfulfilled, onrejected): PromiseLike<never> { - assert(onrejected); - onrejected(value); - return this; - }, - }; - }; - - const cbThenableFn = callbackify(thenableFn); - testQueue.enqueue((done) => { - cbThenableFn((err: unknown, ret: unknown) => { - assertStrictEquals(ret, undefined); - if (err instanceof Error) { - if ("reason" in err) { - assert(!value); - assertStrictEquals( - // deno-lint-ignore no-explicit-any - (err as any).code, - "ERR_FALSY_VALUE_REJECTION", - ); - // deno-lint-ignore no-explicit-any - assertStrictEquals((err as any).reason, value); - } else { - assertStrictEquals(String(value).endsWith(err.message), true); - } - } else { - assertStrictEquals(err, value); - } - done(); - }); - }); - } - - await testQueue.waitForCompletion(); - }, -); - -Deno.test("callbackify passes arguments to the original", async () => { - const testQueue = new TestQueue(); - - for (const value of values) { - // deno-lint-ignore require-await - const asyncFn = async (arg: typeof value): Promise<typeof value> => { - assertStrictEquals(arg, value); - return arg; - }; - - const cbAsyncFn = callbackify(asyncFn); - assertStrictEquals(cbAsyncFn.length, 2); - assert(Object.getPrototypeOf(cbAsyncFn) !== Object.getPrototypeOf(asyncFn)); - assertStrictEquals(Object.getPrototypeOf(cbAsyncFn), Function.prototype); - testQueue.enqueue((done) => { - cbAsyncFn(value, (err: unknown, ret: unknown) => { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - done(); - }); - }); - - const promiseFn = <T>(arg: typeof value): Promise<typeof value> => { - assertStrictEquals(arg, value); - return Promise.resolve(arg); - }; - const obj = {}; - Object.defineProperty(promiseFn, "length", { - value: obj, - writable: false, - enumerable: false, - configurable: true, - }); - - const cbPromiseFn = callbackify(promiseFn); - assertStrictEquals(promiseFn.length, obj); - testQueue.enqueue((done) => { - cbPromiseFn(value, (err: unknown, ret: unknown) => { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - done(); - }); - }); - } - - await testQueue.waitForCompletion(); -}); - -Deno.test("callbackify preserves the `this` binding", async () => { - const testQueue = new TestQueue(); - - for (const value of values) { - const objectWithSyncFunction = { - fn(this: unknown, arg: typeof value): Promise<typeof value> { - assertStrictEquals(this, objectWithSyncFunction); - return Promise.resolve(arg); - }, - }; - const cbSyncFunction = callbackify(objectWithSyncFunction.fn); - testQueue.enqueue((done) => { - cbSyncFunction.call(objectWithSyncFunction, value, function ( - this: unknown, - err: unknown, - ret: unknown, - ) { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - assertStrictEquals(this, objectWithSyncFunction); - done(); - }); - }); - - const objectWithAsyncFunction = { - // deno-lint-ignore require-await - async fn(this: unknown, arg: typeof value): Promise<typeof value> { - assertStrictEquals(this, objectWithAsyncFunction); - return arg; - }, - }; - const cbAsyncFunction = callbackify(objectWithAsyncFunction.fn); - testQueue.enqueue((done) => { - cbAsyncFunction.call(objectWithAsyncFunction, value, function ( - this: unknown, - err: unknown, - ret: unknown, - ) { - assertStrictEquals(err, null); - assertStrictEquals(ret, value); - assertStrictEquals(this, objectWithAsyncFunction); - done(); - }); - }); - } - - await testQueue.waitForCompletion(); -}); - -Deno.test("callbackify throws with non-function inputs", () => { - ["foo", null, undefined, false, 0, {}, Symbol(), []].forEach((value) => { - try { - // deno-lint-ignore no-explicit-any - callbackify(value as any); - throw Error("We should never reach this error"); - } catch (err) { - assert(err instanceof TypeError); - // deno-lint-ignore no-explicit-any - assertStrictEquals((err as any).code, "ERR_INVALID_ARG_TYPE"); - assertStrictEquals(err.name, "TypeError"); - assertStrictEquals( - err.message, - 'The "original" argument must be of type function.', - ); - } - }); -}); - -Deno.test( - "callbackify returns a function that throws if the last argument is not a function", - () => { - // deno-lint-ignore require-await - async function asyncFn(): Promise<number> { - return 42; - } - - // deno-lint-ignore no-explicit-any - const cb = callbackify(asyncFn) as any; - const args: unknown[] = []; - - ["foo", null, undefined, false, 0, {}, Symbol(), []].forEach((value) => { - args.push(value); - - try { - cb(...args); - throw Error("We should never reach this error"); - } catch (err) { - assert(err instanceof TypeError); - // deno-lint-ignore no-explicit-any - assertStrictEquals((err as any).code, "ERR_INVALID_ARG_TYPE"); - assertStrictEquals(err.name, "TypeError"); - assertStrictEquals( - err.message, - "The last argument must be of type function.", - ); - } - }); - }, -); diff --git a/std/node/_util/_util_promisify.ts b/std/node/_util/_util_promisify.ts deleted file mode 100644 index 6692677ec..000000000 --- a/std/node/_util/_util_promisify.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Hack: work around the following TypeScript error: -// error: TS2345 [ERROR]: Argument of type 'typeof kCustomPromisifiedSymbol' -// is not assignable to parameter of type 'typeof kCustomPromisifiedSymbol'. -// assertStrictEquals(kCustomPromisifiedSymbol, promisify.custom); -// ~~~~~~~~~~~~~~~~ -declare const _CustomPromisifiedSymbol: unique symbol; -declare const _CustomPromisifyArgsSymbol: unique symbol; -declare let Symbol: SymbolConstructor; -interface SymbolConstructor { - for(key: "nodejs.util.promisify.custom"): typeof _CustomPromisifiedSymbol; - for( - key: "nodejs.util.promisify.customArgs", - ): typeof _CustomPromisifyArgsSymbol; -} -// End hack. - -// In addition to being accessible through util.promisify.custom, -// this symbol is registered globally and can be accessed in any environment as -// Symbol.for('nodejs.util.promisify.custom'). -const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom"); -// This is an internal Node symbol used by functions returning multiple -// arguments, e.g. ['bytesRead', 'buffer'] for fs.read(). -const kCustomPromisifyArgsSymbol = Symbol.for( - "nodejs.util.promisify.customArgs", -); - -class NodeInvalidArgTypeError extends TypeError { - public code = "ERR_INVALID_ARG_TYPE"; - constructor(argumentName: string, type: string, received: unknown) { - super( - `The "${argumentName}" argument must be of type ${type}. Received ${typeof received}`, - ); - } -} - -export function promisify( - // deno-lint-ignore no-explicit-any - original: (...args: any[]) => void, - // deno-lint-ignore no-explicit-any -): (...args: any[]) => Promise<any> { - if (typeof original !== "function") { - throw new NodeInvalidArgTypeError("original", "Function", original); - } - // deno-lint-ignore no-explicit-any - if ((original as any)[kCustomPromisifiedSymbol]) { - // deno-lint-ignore no-explicit-any - const fn = (original as any)[kCustomPromisifiedSymbol]; - if (typeof fn !== "function") { - throw new NodeInvalidArgTypeError( - "util.promisify.custom", - "Function", - fn, - ); - } - return Object.defineProperty(fn, kCustomPromisifiedSymbol, { - value: fn, - enumerable: false, - writable: false, - configurable: true, - }); - } - - // Names to create an object from in case the callback receives multiple - // arguments, e.g. ['bytesRead', 'buffer'] for fs.read. - // deno-lint-ignore no-explicit-any - const argumentNames = (original as any)[kCustomPromisifyArgsSymbol]; - // deno-lint-ignore no-explicit-any - function fn(this: any, ...args: unknown[]): Promise<unknown> { - return new Promise((resolve, reject) => { - original.call(this, ...args, (err: Error, ...values: unknown[]) => { - if (err) { - return reject(err); - } - if (argumentNames !== undefined && values.length > 1) { - const obj = {}; - for (let i = 0; i < argumentNames.length; i++) { - // deno-lint-ignore no-explicit-any - (obj as any)[argumentNames[i]] = values[i]; - } - resolve(obj); - } else { - resolve(values[0]); - } - }); - }); - } - - Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); - - Object.defineProperty(fn, kCustomPromisifiedSymbol, { - value: fn, - enumerable: false, - writable: false, - configurable: true, - }); - return Object.defineProperties( - fn, - Object.getOwnPropertyDescriptors(original), - ); -} - -promisify.custom = kCustomPromisifiedSymbol; diff --git a/std/node/_util/_util_promisify_test.ts b/std/node/_util/_util_promisify_test.ts deleted file mode 100644 index 39f7de75c..000000000 --- a/std/node/_util/_util_promisify_test.ts +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -import { - assert, - assertEquals, - assertStrictEquals, - assertThrowsAsync, -} from "../../testing/asserts.ts"; -import { promisify } from "./_util_promisify.ts"; -import * as fs from "../fs.ts"; - -// deno-lint-ignore no-explicit-any -type VoidFunction = (...args: any[]) => void; - -const readFile = promisify(fs.readFile); -const customPromisifyArgs = Symbol.for("nodejs.util.promisify.customArgs"); - -Deno.test( - "Errors should reject the promise", - async function testPromiseRejection() { - await assertThrowsAsync(() => readFile("/dontexist"), Deno.errors.NotFound); - }, -); - -Deno.test("Promisify.custom", async function testPromisifyCustom() { - function fn(): void {} - - function promisifedFn(): void {} - // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol - fn[promisify.custom] = promisifedFn; - - const promisifiedFnA = promisify(fn); - const promisifiedFnB = promisify(promisifiedFnA); - assertStrictEquals(promisifiedFnA, promisifedFn); - assertStrictEquals(promisifiedFnB, promisifedFn); - - await promisifiedFnA; - await promisifiedFnB; -}); - -Deno.test("promiisfy.custom symbol", function testPromisifyCustomSymbol() { - function fn(): void {} - - function promisifiedFn(): void {} - - // util.promisify.custom is a shared symbol which can be accessed - // as `Symbol.for("nodejs.util.promisify.custom")`. - const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom"); - // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol - fn[kCustomPromisifiedSymbol] = promisifiedFn; - - assertStrictEquals(kCustomPromisifiedSymbol, promisify.custom); - assertStrictEquals(promisify(fn), promisifiedFn); - assertStrictEquals(promisify(promisify(fn)), promisifiedFn); -}); - -Deno.test("Invalid argument should throw", function testThrowInvalidArgument() { - function fn(): void {} - // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol - fn[promisify.custom] = 42; - try { - promisify(fn); - } catch (e) { - assertStrictEquals(e.code, "ERR_INVALID_ARG_TYPE"); - assert(e instanceof TypeError); - } -}); - -Deno.test("Custom promisify args", async function testPromisifyCustomArgs() { - const firstValue = 5; - const secondValue = 17; - - function fn(callback: VoidFunction): void { - callback(null, firstValue, secondValue); - } - - // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol - fn[customPromisifyArgs] = ["first", "second"]; - - const obj = await promisify(fn)(); - assertEquals(obj, { first: firstValue, second: secondValue }); -}); - -Deno.test( - "Multiple callback args without custom promisify args", - async function testPromisifyWithoutCustomArgs() { - function fn(callback: VoidFunction): void { - callback(null, "foo", "bar"); - } - const value = await promisify(fn)(); - assertStrictEquals(value, "foo"); - }, -); - -Deno.test( - "Undefined resolved value", - async function testPromisifyWithUndefinedResolvedValue() { - function fn(callback: VoidFunction): void { - callback(null); - } - const value = await promisify(fn)(); - assertStrictEquals(value, undefined); - }, -); - -Deno.test( - "Undefined resolved value II", - async function testPromisifyWithUndefinedResolvedValueII() { - function fn(callback: VoidFunction): void { - callback(); - } - const value = await promisify(fn)(); - assertStrictEquals(value, undefined); - }, -); - -Deno.test( - "Resolved value: number", - async function testPromisifyWithNumberResolvedValue() { - function fn(err: Error | null, val: number, callback: VoidFunction): void { - callback(err, val); - } - const value = await promisify(fn)(null, 42); - assertStrictEquals(value, 42); - }, -); - -Deno.test( - "Rejected value", - async function testPromisifyWithNumberRejectedValue() { - function fn(err: Error | null, val: null, callback: VoidFunction): void { - callback(err, val); - } - await assertThrowsAsync( - () => promisify(fn)(new Error("oops"), null), - Error, - "oops", - ); - }, -); - -Deno.test("Rejected value", async function testPromisifyWithAsObjectMethod() { - const o: { fn?: VoidFunction } = {}; - const fn = promisify(function (this: unknown, cb: VoidFunction): void { - cb(null, this === o); - }); - - o.fn = fn; - - const val = await o.fn(); - assert(val); -}); - -Deno.test( - "Multiple callback", - async function testPromisifyWithMultipleCallback() { - const err = new Error( - "Should not have called the callback with the error.", - ); - const stack = err.stack; - - const fn = promisify(function (cb: VoidFunction): void { - cb(null); - cb(err); - }); - - await fn(); - await Promise.resolve(); - return assertStrictEquals(stack, err.stack); - }, -); - -Deno.test("Promisify a promise", function testPromisifyPromise() { - function c(): void {} - const a = promisify(function (): void {}); - const b = promisify(a); - assert(c !== a); - assertStrictEquals(a, b); -}); - -Deno.test("Test error", async function testInvalidArguments() { - let errToThrow; - - const thrower = promisify(function ( - a: number, - b: number, - c: number, - cb: VoidFunction, - ): void { - errToThrow = new Error(`${a}-${b}-${c}-${cb}`); - throw errToThrow; - }); - - try { - await thrower(1, 2, 3); - throw new Error(`should've failed`); - } catch (e) { - assertStrictEquals(e, errToThrow); - } -}); - -Deno.test("Test invalid arguments", function testInvalidArguments() { - [undefined, null, true, 0, "str", {}, [], Symbol()].forEach((input) => { - try { - // @ts-expect-error TypeScript - promisify(input); - } catch (e) { - assertStrictEquals(e.code, "ERR_INVALID_ARG_TYPE"); - assert(e instanceof TypeError); - assertEquals( - e.message, - `The "original" argument must be of type Function. Received ${typeof input}`, - ); - } - }); -}); diff --git a/std/node/_util/_util_types.ts b/std/node/_util/_util_types.ts deleted file mode 100644 index f64f5377b..000000000 --- a/std/node/_util/_util_types.ts +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -const _toString = Object.prototype.toString; - -const _isObjectLike = (value: unknown): boolean => - value !== null && typeof value === "object"; - -const _isFunctionLike = (value: unknown): boolean => - value !== null && typeof value === "function"; - -export function isAnyArrayBuffer(value: unknown): boolean { - return ( - _isObjectLike(value) && - (_toString.call(value) === "[object ArrayBuffer]" || - _toString.call(value) === "[object SharedArrayBuffer]") - ); -} - -export function isArrayBufferView(value: unknown): boolean { - return ArrayBuffer.isView(value); -} - -export function isArgumentsObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Arguments]"; -} - -export function isArrayBuffer(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object ArrayBuffer]" - ); -} - -export function isAsyncFunction(value: unknown): boolean { - return ( - _isFunctionLike(value) && _toString.call(value) === "[object AsyncFunction]" - ); -} - -export function isBigInt64Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object BigInt64Array]" - ); -} - -export function isBigUint64Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object BigUint64Array]" - ); -} - -export function isBooleanObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Boolean]"; -} - -export function isBoxedPrimitive(value: unknown): boolean { - return ( - isBooleanObject(value) || - isStringObject(value) || - isNumberObject(value) || - isSymbolObject(value) || - isBigIntObject(value) - ); -} - -export function isDataView(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object DataView]"; -} - -export function isDate(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Date]"; -} - -// isExternal: Not implemented - -export function isFloat32Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Float32Array]" - ); -} - -export function isFloat64Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Float64Array]" - ); -} - -export function isGeneratorFunction(value: unknown): boolean { - return ( - _isFunctionLike(value) && - _toString.call(value) === "[object GeneratorFunction]" - ); -} - -export function isGeneratorObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Generator]"; -} - -export function isInt8Array(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Int8Array]"; -} - -export function isInt16Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Int16Array]" - ); -} - -export function isInt32Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Int32Array]" - ); -} - -export function isMap(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Map]"; -} - -export function isMapIterator(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Map Iterator]" - ); -} - -export function isModuleNamespaceObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Module]"; -} - -export function isNativeError(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Error]"; -} - -export function isNumberObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Number]"; -} - -export function isBigIntObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object BigInt]"; -} - -export function isPromise(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Promise]"; -} - -export function isRegExp(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object RegExp]"; -} - -export function isSet(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Set]"; -} - -export function isSetIterator(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Set Iterator]" - ); -} - -export function isSharedArrayBuffer(value: unknown): boolean { - return ( - _isObjectLike(value) && - _toString.call(value) === "[object SharedArrayBuffer]" - ); -} - -export function isStringObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object String]"; -} - -export function isSymbolObject(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object Symbol]"; -} - -// Adapted from Lodash -export function isTypedArray(value: unknown): boolean { - /** Used to match `toStringTag` values of typed arrays. */ - const reTypedTag = - /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/; - return _isObjectLike(value) && reTypedTag.test(_toString.call(value)); -} - -export function isUint8Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Uint8Array]" - ); -} - -export function isUint8ClampedArray(value: unknown): boolean { - return ( - _isObjectLike(value) && - _toString.call(value) === "[object Uint8ClampedArray]" - ); -} - -export function isUint16Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Uint16Array]" - ); -} - -export function isUint32Array(value: unknown): boolean { - return ( - _isObjectLike(value) && _toString.call(value) === "[object Uint32Array]" - ); -} - -export function isWeakMap(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object WeakMap]"; -} - -export function isWeakSet(value: unknown): boolean { - return _isObjectLike(value) && _toString.call(value) === "[object WeakSet]"; -} diff --git a/std/node/_util/_util_types_test.ts b/std/node/_util/_util_types_test.ts deleted file mode 100644 index 763969964..000000000 --- a/std/node/_util/_util_types_test.ts +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -import { assertStrictEquals } from "../../testing/asserts.ts"; -import { - isAnyArrayBuffer, - isArgumentsObject, - isArrayBuffer, - isArrayBufferView, - isAsyncFunction, - isBigInt64Array, - isBigIntObject, - isBigUint64Array, - isBooleanObject, - isBoxedPrimitive, - isDataView, - isDate, - isFloat32Array, - isFloat64Array, - isGeneratorFunction, - isGeneratorObject, - isInt16Array, - isInt32Array, - isInt8Array, - isMap, - isMapIterator, - isModuleNamespaceObject, - isNativeError, - isNumberObject, - isPromise, - isRegExp, - isSet, - isSetIterator, - isSharedArrayBuffer, - isStringObject, - isSymbolObject, - isTypedArray, - isUint16Array, - isUint32Array, - isUint8Array, - isUint8ClampedArray, - isWeakMap, - isWeakSet, -} from "./_util_types.ts"; - -// Used to test isModuleNamespaceObject -import * as testModuleNamespaceOpbject from "./_util_types.ts"; - -// isAnyArrayBuffer -Deno.test("Should return true for valid ArrayBuffer types", () => { - assertStrictEquals(isAnyArrayBuffer(new ArrayBuffer(0)), true); - assertStrictEquals(isAnyArrayBuffer(new SharedArrayBuffer(0)), true); -}); - -Deno.test("Should return false for invalid ArrayBuffer types", () => { - assertStrictEquals(isAnyArrayBuffer({}), false); - assertStrictEquals(isAnyArrayBuffer([]), false); - assertStrictEquals(isAnyArrayBuffer(new Error()), false); -}); - -// isArrayBufferView -Deno.test("Should return true for valid ArrayBufferView types", () => { - assertStrictEquals(isArrayBufferView(new Int8Array(0)), true); - assertStrictEquals(isArrayBufferView(new Uint8Array(0)), true); - assertStrictEquals(isArrayBufferView(new Uint8ClampedArray(0)), true); - assertStrictEquals(isArrayBufferView(new Int16Array(0)), true); - assertStrictEquals(isArrayBufferView(new Uint16Array(0)), true); - assertStrictEquals(isArrayBufferView(new Int32Array(0)), true); - assertStrictEquals(isArrayBufferView(new Uint32Array(0)), true); - assertStrictEquals(isArrayBufferView(new Float32Array(0)), true); - assertStrictEquals(isArrayBufferView(new Float64Array(0)), true); - assertStrictEquals(isArrayBufferView(new DataView(new ArrayBuffer(0))), true); -}); - -Deno.test("Should return false for invalid ArrayBufferView types", () => { - assertStrictEquals(isArrayBufferView({}), false); - assertStrictEquals(isArrayBufferView([]), false); - assertStrictEquals(isArrayBufferView(new Error()), false); - assertStrictEquals(isArrayBufferView(new ArrayBuffer(0)), false); -}); - -// isArgumentsObject -// Note: not testable in TS - -Deno.test("Should return false for invalid Argument types", () => { - assertStrictEquals(isArgumentsObject({}), false); - assertStrictEquals(isArgumentsObject([]), false); - assertStrictEquals(isArgumentsObject(new Error()), false); -}); - -// isArrayBuffer -Deno.test("Should return true for valid ArrayBuffer types", () => { - assertStrictEquals(isArrayBuffer(new ArrayBuffer(0)), true); -}); - -Deno.test("Should return false for invalid ArrayBuffer types", () => { - assertStrictEquals(isArrayBuffer(new SharedArrayBuffer(0)), false); - assertStrictEquals(isArrayBuffer({}), false); - assertStrictEquals(isArrayBuffer([]), false); - assertStrictEquals(isArrayBuffer(new Error()), false); -}); - -// isAsyncFunction -Deno.test("Should return true for valid async function types", () => { - const asyncFunction = async (): Promise<void> => {}; - assertStrictEquals(isAsyncFunction(asyncFunction), true); -}); - -Deno.test("Should return false for invalid async function types", () => { - const syncFunction = (): void => {}; - assertStrictEquals(isAsyncFunction(syncFunction), false); - assertStrictEquals(isAsyncFunction({}), false); - assertStrictEquals(isAsyncFunction([]), false); - assertStrictEquals(isAsyncFunction(new Error()), false); -}); - -// isBigInt64Array -Deno.test("Should return true for valid BigInt64Array types", () => { - assertStrictEquals(isBigInt64Array(new BigInt64Array()), true); -}); - -Deno.test("Should return false for invalid BigInt64Array types", () => { - assertStrictEquals(isBigInt64Array(new BigUint64Array()), false); - assertStrictEquals(isBigInt64Array(new Float32Array()), false); - assertStrictEquals(isBigInt64Array(new Int32Array()), false); -}); - -// isBigUint64Array -Deno.test("Should return true for valid isBigUint64Array types", () => { - assertStrictEquals(isBigUint64Array(new BigUint64Array()), true); -}); - -Deno.test("Should return false for invalid isBigUint64Array types", () => { - assertStrictEquals(isBigUint64Array(new BigInt64Array()), false); - assertStrictEquals(isBigUint64Array(new Float32Array()), false); - assertStrictEquals(isBigUint64Array(new Int32Array()), false); -}); - -// isBooleanObject -Deno.test("Should return true for valid Boolean object types", () => { - assertStrictEquals(isBooleanObject(new Boolean(false)), true); - assertStrictEquals(isBooleanObject(new Boolean(true)), true); -}); - -Deno.test("Should return false for invalid isBigUint64Array types", () => { - assertStrictEquals(isBooleanObject(false), false); - assertStrictEquals(isBooleanObject(true), false); - assertStrictEquals(isBooleanObject(Boolean(false)), false); - assertStrictEquals(isBooleanObject(Boolean(true)), false); -}); - -// isBoxedPrimitive -Deno.test("Should return true for valid boxed primitive values", () => { - assertStrictEquals(isBoxedPrimitive(new Boolean(false)), true); - assertStrictEquals(isBoxedPrimitive(Object(Symbol("foo"))), true); - assertStrictEquals(isBoxedPrimitive(Object(BigInt(5))), true); - assertStrictEquals(isBoxedPrimitive(new String("foo")), true); -}); - -Deno.test("Should return false for invalid boxed primitive values", () => { - assertStrictEquals(isBoxedPrimitive(false), false); - assertStrictEquals(isBoxedPrimitive(Symbol("foo")), false); -}); - -// isDateView -Deno.test("Should return true for valid DataView types", () => { - assertStrictEquals(isDataView(new DataView(new ArrayBuffer(0))), true); -}); - -Deno.test("Should return false for invalid DataView types", () => { - assertStrictEquals(isDataView(new Float64Array(0)), false); -}); - -// isDate -Deno.test("Should return true for valid date types", () => { - assertStrictEquals(isDate(new Date()), true); - assertStrictEquals(isDate(new Date(0)), true); - assertStrictEquals(isDate(new (eval("Date"))()), true); -}); - -Deno.test("Should return false for invalid date types", () => { - assertStrictEquals(isDate(Date()), false); - assertStrictEquals(isDate({}), false); - assertStrictEquals(isDate([]), false); - assertStrictEquals(isDate(new Error()), false); - assertStrictEquals(isDate(Object.create(Date.prototype)), false); -}); - -// isFloat32Array -Deno.test("Should return true for valid Float32Array types", () => { - assertStrictEquals(isFloat32Array(new Float32Array(0)), true); -}); - -Deno.test("Should return false for invalid Float32Array types", () => { - assertStrictEquals(isFloat32Array(new ArrayBuffer(0)), false); - assertStrictEquals(isFloat32Array(new Float64Array(0)), false); -}); - -// isFloat64Array -Deno.test("Should return true for valid Float64Array types", () => { - assertStrictEquals(isFloat64Array(new Float64Array(0)), true); -}); - -Deno.test("Should return false for invalid Float64Array types", () => { - assertStrictEquals(isFloat64Array(new ArrayBuffer(0)), false); - assertStrictEquals(isFloat64Array(new Uint8Array(0)), false); -}); - -// isGeneratorFunction -Deno.test("Should return true for valid generator functions", () => { - assertStrictEquals( - isGeneratorFunction(function* foo() {}), - true, - ); -}); - -Deno.test("Should return false for invalid generator functions", () => { - assertStrictEquals( - isGeneratorFunction(function foo() {}), - false, - ); -}); - -// isGeneratorObject -Deno.test("Should return true for valid generator object types", () => { - function* foo(): Iterator<void> {} - assertStrictEquals(isGeneratorObject(foo()), true); -}); - -Deno.test("Should return false for invalid generation object types", () => { - assertStrictEquals( - isGeneratorObject(function* foo() {}), - false, - ); -}); - -// isInt8Array -Deno.test("Should return true for valid Int8Array types", () => { - assertStrictEquals(isInt8Array(new Int8Array(0)), true); -}); - -Deno.test("Should return false for invalid Int8Array types", () => { - assertStrictEquals(isInt8Array(new ArrayBuffer(0)), false); - assertStrictEquals(isInt8Array(new Float64Array(0)), false); -}); - -// isInt16Array -Deno.test("Should return true for valid Int16Array types", () => { - assertStrictEquals(isInt16Array(new Int16Array(0)), true); -}); - -Deno.test("Should return false for invalid Int16Array type", () => { - assertStrictEquals(isInt16Array(new ArrayBuffer(0)), false); - assertStrictEquals(isInt16Array(new Float64Array(0)), false); -}); - -// isInt32Array -Deno.test("Should return true for valid isInt32Array types", () => { - assertStrictEquals(isInt32Array(new Int32Array(0)), true); -}); - -Deno.test("Should return false for invalid isInt32Array type", () => { - assertStrictEquals(isInt32Array(new ArrayBuffer(0)), false); - assertStrictEquals(isInt32Array(new Float64Array(0)), false); -}); - -// isStringObject -Deno.test("Should return true for valid String types", () => { - assertStrictEquals(isStringObject(new String("")), true); - assertStrictEquals(isStringObject(new String("Foo")), true); -}); - -Deno.test("Should return false for invalid String types", () => { - assertStrictEquals(isStringObject(""), false); - assertStrictEquals(isStringObject("Foo"), false); -}); - -// isMap -Deno.test("Should return true for valid Map types", () => { - assertStrictEquals(isMap(new Map()), true); -}); - -Deno.test("Should return false for invalid Map types", () => { - assertStrictEquals(isMap({}), false); - assertStrictEquals(isMap([]), false); - assertStrictEquals(isMap(new Date()), false); - assertStrictEquals(isMap(new Error()), false); -}); - -// isMapIterator -Deno.test("Should return true for valid Map Iterator types", () => { - const map = new Map(); - assertStrictEquals(isMapIterator(map.keys()), true); - assertStrictEquals(isMapIterator(map.values()), true); - assertStrictEquals(isMapIterator(map.entries()), true); - assertStrictEquals(isMapIterator(map[Symbol.iterator]()), true); -}); - -Deno.test("Should return false for invalid Map iterator types", () => { - assertStrictEquals(isMapIterator(new Map()), false); - assertStrictEquals(isMapIterator([]), false); - assertStrictEquals(isMapIterator(new Date()), false); - assertStrictEquals(isMapIterator(new Error()), false); -}); - -// isModuleNamespaceObject -Deno.test("Should return true for valid module namespace objects", () => { - assertStrictEquals(isModuleNamespaceObject(testModuleNamespaceOpbject), true); -}); - -Deno.test("Should return false for invalid module namespace objects", () => { - assertStrictEquals(isModuleNamespaceObject(assertStrictEquals), false); -}); - -// isNativeError -Deno.test("Should return true for valid Error types", () => { - assertStrictEquals(isNativeError(new Error()), true); - assertStrictEquals(isNativeError(new TypeError()), true); - assertStrictEquals(isNativeError(new RangeError()), true); -}); - -Deno.test("Should return false for invalid Error types", () => { - assertStrictEquals(isNativeError(null), false); - assertStrictEquals(isNativeError(NaN), false); -}); - -// isNumberObject -Deno.test("Should return true for valid number objects", () => { - assertStrictEquals(isNumberObject(new Number(0)), true); -}); - -Deno.test("Should return false for invalid number types", () => { - assertStrictEquals(isNumberObject(0), false); -}); - -// isBigIntObject -Deno.test("Should return true for valid number objects", () => { - assertStrictEquals(isBigIntObject(new Object(BigInt(42))), true); -}); - -Deno.test("Should return false for invalid number types", () => { - assertStrictEquals(isBigIntObject(BigInt(42)), false); -}); - -// isPromise -Deno.test("Should return true for valid Promise types", () => { - assertStrictEquals(isPromise(Promise.resolve(42)), true); -}); - -Deno.test("Should return false for invalid Promise types", () => { - assertStrictEquals(isPromise(new Object()), false); -}); - -// isRegExp -Deno.test("Should return true for valid RegExp", () => { - assertStrictEquals(isRegExp(/abc/), true); - assertStrictEquals(isRegExp(new RegExp("abc")), true); -}); - -Deno.test("Should return false for invalid RegExp types", () => { - assertStrictEquals(isRegExp({}), false); - assertStrictEquals(isRegExp("/abc/"), false); -}); - -// isSet -Deno.test("Should return true for valid Set types", () => { - assertStrictEquals(isSet(new Set()), true); -}); - -Deno.test("Should return false for invalid Set types", () => { - assertStrictEquals(isSet({}), false); - assertStrictEquals(isSet([]), false); - assertStrictEquals(isSet(new Map()), false); - assertStrictEquals(isSet(new Error()), false); -}); - -// isSetIterator -Deno.test("Should return true for valid Set Iterator types", () => { - const set = new Set(); - assertStrictEquals(isSetIterator(set.keys()), true); - assertStrictEquals(isSetIterator(set.values()), true); - assertStrictEquals(isSetIterator(set.entries()), true); - assertStrictEquals(isSetIterator(set[Symbol.iterator]()), true); -}); - -Deno.test("Should return false for invalid Set Iterator types", () => { - assertStrictEquals(isSetIterator(new Set()), false); - assertStrictEquals(isSetIterator([]), false); - assertStrictEquals(isSetIterator(new Map()), false); - assertStrictEquals(isSetIterator(new Error()), false); -}); - -// isSharedArrayBuffer -Deno.test("Should return true for valid SharedArrayBuffer types", () => { - assertStrictEquals(isSharedArrayBuffer(new SharedArrayBuffer(0)), true); -}); - -Deno.test("Should return false for invalid SharedArrayBuffer types", () => { - assertStrictEquals(isSharedArrayBuffer(new ArrayBuffer(0)), false); -}); - -// isStringObject -Deno.test("Should return true for valid String Object types", () => { - assertStrictEquals(isStringObject(new String("")), true); - assertStrictEquals(isStringObject(new String("Foo")), true); -}); - -Deno.test("Should return false for invalid String Object types", () => { - assertStrictEquals(isStringObject(""), false); - assertStrictEquals(isStringObject("Foo"), false); -}); - -// isSymbolObject -Deno.test("Should return true for valid Symbol types", () => { - assertStrictEquals(isSymbolObject(Object(Symbol("foo"))), true); -}); - -Deno.test("Should return false for invalid Symbol types", () => { - assertStrictEquals(isSymbolObject(Symbol("foo")), false); -}); - -// isTypedArray -Deno.test("Should return true for valid TypedArray types", () => { - assertStrictEquals(isTypedArray(new Uint8Array(0)), true); - assertStrictEquals(isTypedArray(new Float64Array(0)), true); -}); - -Deno.test("Should return false for invalid TypedArray types", () => { - assertStrictEquals(isTypedArray(new ArrayBuffer(0)), false); -}); - -// isUint8Array -Deno.test("Should return true for valid Uint8Array types", () => { - assertStrictEquals(isUint8Array(new Uint8Array(0)), true); -}); - -Deno.test("Should return false for invalid Uint8Array types", () => { - assertStrictEquals(isUint8Array(new ArrayBuffer(0)), false); - assertStrictEquals(isUint8Array(new Float64Array(0)), false); -}); - -// isUint8ClampedArray -Deno.test("Should return true for valid Uint8ClampedArray types", () => { - assertStrictEquals(isUint8ClampedArray(new Uint8ClampedArray(0)), true); -}); - -Deno.test("Should return false for invalid Uint8Array types", () => { - assertStrictEquals(isUint8ClampedArray(new ArrayBuffer(0)), false); - assertStrictEquals(isUint8ClampedArray(new Float64Array(0)), false); -}); - -// isUint16Array -Deno.test("Should return true for valid isUint16Array types", () => { - assertStrictEquals(isUint16Array(new Uint16Array(0)), true); -}); - -Deno.test("Should return false for invalid Uint16Array types", () => { - assertStrictEquals(isUint16Array(new ArrayBuffer(0)), false); - assertStrictEquals(isUint16Array(new Float64Array(0)), false); -}); - -// isUint32Array -Deno.test("Should return true for valid Uint32Array types", () => { - assertStrictEquals(isUint32Array(new Uint32Array(0)), true); -}); - -Deno.test("Should return false for invalid isUint16Array types", () => { - assertStrictEquals(isUint32Array(new ArrayBuffer(0)), false); - assertStrictEquals(isUint32Array(new Float64Array(0)), false); -}); - -// isWeakMap -Deno.test("Should return true for valid WeakMap types", () => { - assertStrictEquals(isWeakMap(new WeakMap()), true); -}); - -Deno.test("Should return false for invalid WeakMap types", () => { - assertStrictEquals(isWeakMap(new Set()), false); - assertStrictEquals(isWeakMap(new Map()), false); -}); - -// isWeakSet -Deno.test("Should return true for valid WeakSet types", () => { - assertStrictEquals(isWeakSet(new WeakSet()), true); -}); - -Deno.test("Should return false for invalid WeakSet types", () => { - assertStrictEquals(isWeakSet(new Set()), false); - assertStrictEquals(isWeakSet(new Map()), false); -}); diff --git a/std/node/_utils.ts b/std/node/_utils.ts deleted file mode 100644 index 62a911843..000000000 --- a/std/node/_utils.ts +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { deferred } from "../async/mod.ts"; -import { assert, assertStringIncludes, fail } from "../testing/asserts.ts"; - -export type BinaryEncodings = "binary"; - -export type TextEncodings = - | "ascii" - | "utf8" - | "utf-8" - | "utf16le" - | "ucs2" - | "ucs-2" - | "base64" - | "latin1" - | "hex"; - -export type Encodings = BinaryEncodings | TextEncodings; - -export function notImplemented(msg?: string): never { - const message = msg ? `Not implemented: ${msg}` : "Not implemented"; - throw new Error(message); -} - -export type _TextDecoder = typeof TextDecoder.prototype; -export const _TextDecoder = TextDecoder; - -export type _TextEncoder = typeof TextEncoder.prototype; -export const _TextEncoder = TextEncoder; - -// API helpers - -export type MaybeNull<T> = T | null; -export type MaybeDefined<T> = T | undefined; -export type MaybeEmpty<T> = T | null | undefined; - -export function intoCallbackAPI<T>( - // deno-lint-ignore no-explicit-any - func: (...args: any[]) => Promise<T>, - cb: MaybeEmpty<(err: MaybeNull<Error>, value?: MaybeEmpty<T>) => void>, - // deno-lint-ignore no-explicit-any - ...args: any[] -): void { - func(...args).then( - (value) => cb && cb(null, value), - (err) => cb && cb(err), - ); -} - -export function intoCallbackAPIWithIntercept<T1, T2>( - // deno-lint-ignore no-explicit-any - func: (...args: any[]) => Promise<T1>, - interceptor: (v: T1) => T2, - cb: MaybeEmpty<(err: MaybeNull<Error>, value?: MaybeEmpty<T2>) => void>, - // deno-lint-ignore no-explicit-any - ...args: any[] -): void { - func(...args).then( - (value) => cb && cb(null, interceptor(value)), - (err) => cb && cb(err), - ); -} - -export function spliceOne(list: string[], index: number): void { - for (; index + 1 < list.length; index++) list[index] = list[index + 1]; - list.pop(); -} - -// Taken from: https://github.com/nodejs/node/blob/ba684805b6c0eded76e5cd89ee00328ac7a59365/lib/internal/util.js#L125 -// Return undefined if there is no match. -// Move the "slow cases" to a separate function to make sure this function gets -// inlined properly. That prioritizes the common case. -export function normalizeEncoding( - enc: string | null, -): TextEncodings | undefined { - if (enc == null || enc === "utf8" || enc === "utf-8") return "utf8"; - return slowCases(enc); -} - -// https://github.com/nodejs/node/blob/ba684805b6c0eded76e5cd89ee00328ac7a59365/lib/internal/util.js#L130 -function slowCases(enc: string): TextEncodings | undefined { - switch (enc.length) { - case 4: - 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"; - break; - case 3: - 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"; - enc = `${enc}`.toLowerCase(); - 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"; - enc = `${enc}`.toLowerCase(); - if (enc === "base64") return "base64"; - if (enc === "latin1" || enc === "binary") return "latin1"; - break; - case 7: - if ( - enc === "utf16le" || - enc === "UTF16LE" || - `${enc}`.toLowerCase() === "utf16le" - ) { - return "utf16le"; - } - break; - case 8: - if ( - enc === "utf-16le" || - enc === "UTF-16LE" || - `${enc}`.toLowerCase() === "utf-16le" - ) { - return "utf16le"; - } - break; - default: - if (enc === "") return "utf8"; - } -} - -export function validateIntegerRange( - value: number, - name: string, - min = -2147483648, - max = 2147483647, -): void { - // The defaults for min and max correspond to the limits of 32-bit integers. - if (!Number.isInteger(value)) { - throw new Error(`${name} must be 'an integer' but was ${value}`); - } - - if (value < min || value > max) { - throw new Error( - `${name} must be >= ${min} && <= ${max}. Value was ${value}`, - ); - } -} - -type OptionalSpread<T> = T extends undefined ? [] - : [T]; - -export function once<T = undefined>( - callback: (...args: OptionalSpread<T>) => void, -) { - let called = false; - return function (this: unknown, ...args: OptionalSpread<T>) { - if (called) return; - called = true; - callback.apply(this, args); - }; -} - -/** - * @param {number} [expectedExecutions = 1] - * @param {number} [timeout = 1000] Milliseconds to wait before the promise is forcefully exited -*/ -export function mustCall<T extends unknown[]>( - fn: ((...args: T) => void) = () => {}, - expectedExecutions = 1, - timeout = 1000, -): [Promise<void>, (...args: T) => void] { - if (expectedExecutions < 1) { - throw new Error("Expected executions can't be lower than 1"); - } - let timesExecuted = 0; - const completed = deferred(); - - const abort = setTimeout(() => completed.reject(), timeout); - - function callback(this: unknown, ...args: T) { - timesExecuted++; - if (timesExecuted === expectedExecutions) { - completed.resolve(); - } - fn.apply(this, args); - } - - const result = completed - .then(() => clearTimeout(abort)) - .catch(() => - fail( - `Async operation not completed: Expected ${expectedExecutions}, executed ${timesExecuted}`, - ) - ); - - return [ - result, - callback, - ]; -} -/** Asserts that an error thrown in a callback will not be wrongly caught. */ -export async function assertCallbackErrorUncaught( - { prelude, invocation, cleanup }: { - /** Any code which needs to run before the actual invocation (notably, any import statements). */ - prelude?: string; - /** - * The start of the invocation of the function, e.g. `open("foo.txt", `. - * The callback will be added after it. - */ - invocation: string; - /** Called after the subprocess is finished but before running the assertions, e.g. to clean up created files. */ - cleanup?: () => Promise<void> | void; - }, -) { - // Since the error has to be uncaught, and that will kill the Deno process, - // the only way to test this is to spawn a subprocess. - const p = Deno.run({ - cmd: [ - Deno.execPath(), - "eval", - "--no-check", // Running TSC for every one of these tests would take way too long - "--unstable", - `${prelude ?? ""} - - ${invocation}(err) => { - // If the bug is present and the callback is called again with an error, - // don't throw another error, so if the subprocess fails we know it had the correct behaviour. - if (!err) throw new Error("success"); - });`, - ], - stderr: "piped", - }); - const status = await p.status(); - const stderr = new TextDecoder().decode(await Deno.readAll(p.stderr)); - p.close(); - p.stderr.close(); - await cleanup?.(); - assert(!status.success); - assertStringIncludes(stderr, "Error: success"); -} diff --git a/std/node/assert.ts b/std/node/assert.ts deleted file mode 100644 index 7b144b690..000000000 --- a/std/node/assert.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -export { AssertionError } from "./assertion_error.ts"; -import { - assertEquals as deepStrictEqual, - AssertionError, - assertMatch as match, - assertNotEquals as notDeepStrictEqual, - assertNotStrictEquals as notStrictEqual, - assertStrictEquals as strictEqual, - assertThrows as throws, - fail, -} from "../testing/asserts.ts"; - -function assert(expr: unknown, msg = ""): asserts expr { - if (!expr) { - throw new AssertionError(msg); - } -} -const ok = assert; -export default assert; - -Object.assign(assert, { - deepStrictEqual, - fail, - match, - notDeepStrictEqual, - notStrictEqual, - ok, - strictEqual, - throws, -}); - -export { - deepStrictEqual, - fail, - match, - notDeepStrictEqual, - notStrictEqual, - ok, - strictEqual, - throws, -}; diff --git a/std/node/assert_test.ts b/std/node/assert_test.ts deleted file mode 100644 index ab4bec79b..000000000 --- a/std/node/assert_test.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert as denoAssert, - assertEquals, - assertMatch, - assertNotEquals, - assertNotStrictEquals, - assertStrictEquals, - assertThrows, - fail as denoFail, -} from "../testing/asserts.ts"; - -import AssertionError from "./assertion_error.ts"; - -import assert, { - AssertionError as AssertionError_, - deepStrictEqual, - fail, - match, - notDeepStrictEqual, - notStrictEqual, - ok, - strictEqual, - throws, -} from "./assert.ts"; - -Deno.test("API should be exposed", () => { - assertStrictEquals(assert, ok, "`assert()` should be an alias of `ok()`"); - assertStrictEquals( - assertEquals, - deepStrictEqual, - "`assertEquals()` should be exposed as `deepStrictEqual()`", - ); - assertStrictEquals( - assertNotEquals, - notDeepStrictEqual, - "`assertNotEquals()` should be exposed as `notDeepStrictEqual()`", - ); - assertStrictEquals( - assertStrictEquals, - strictEqual, - "`assertStrictEquals()` should be exposed as `strictEqual()`", - ); - assertStrictEquals( - assertNotStrictEquals, - notStrictEqual, - "`assertNotStrictEquals()` should be exposed as `notStrictEqual()`", - ); - assertStrictEquals( - assertMatch, - match, - "`assertMatch()` should be exposed as `match()`", - ); - assertStrictEquals( - assertThrows, - throws, - "`assertThrows()` should be exposed as `throws()`", - ); - assertStrictEquals(fail, denoFail, "`fail()` should be exposed"); - assertStrictEquals( - AssertionError, - AssertionError_, - "`AssertionError()` constructor should be exposed", - ); -}); diff --git a/std/node/assertion_error.ts b/std/node/assertion_error.ts deleted file mode 100644 index dcce1478b..000000000 --- a/std/node/assertion_error.ts +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: - -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// TODO(schwarzkopfb): change this when `Deno.consoleSize()` will be stable -interface DenoUnstable { - consoleSize?(rid: number): { columns: number }; -} -function getConsoleWidth(): number { - return (Deno as DenoUnstable).consoleSize?.(Deno.stderr.rid).columns ?? 80; -} - -import { inspect } from "./util.ts"; -import { stripColor as removeColors } from "../fmt/colors.ts"; - -// TODO(schwarzkopfb): we should implement Node's concept of "primordials" -// Ref: https://github.com/denoland/deno/issues/6040#issuecomment-637305828 -const MathMax = Math.max; -const { Error } = globalThis; -const { - create: ObjectCreate, - defineProperty: ObjectDefineProperty, - getPrototypeOf: ObjectGetPrototypeOf, - getOwnPropertyDescriptor: ObjectGetOwnPropertyDescriptor, - keys: ObjectKeys, -} = Object; - -import { ERR_INVALID_ARG_TYPE } from "./_errors.ts"; - -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:", - strictEqualObject: 'Expected "actual" to be reference-equal to "expected":', - 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:", -}; - -// Comparing short primitives should just show === / !== instead of using the -// diff. -const kMaxShortLength = 12; - -export function copyError(source: Error): Error { - const keys = ObjectKeys(source); - const target = ObjectCreate(ObjectGetPrototypeOf(source)); - for (const key of keys) { - const desc = ObjectGetOwnPropertyDescriptor(source, key); - - if (desc !== undefined) { - ObjectDefineProperty(target, key, desc); - } - } - ObjectDefineProperty(target, "message", { value: source.message }); - return target; -} - -export function inspectValue(val: unknown): string { - // The util.inspect default values could be changed. This makes sure the - // error messages contain the necessary information nevertheless. - return inspect( - val, - { - compact: false, - 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, -): string { - let other = ""; - let res = ""; - let end = ""; - let skipped = false; - const actualInspected = inspectValue(actual); - const actualLines = actualInspected.split("\n"); - const expectedLines = inspectValue(expected).split("\n"); - - let i = 0; - 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 = "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[0] !== expectedLines[0] - ) { - // Check for the visible length using the `removeColors()` function, if - // appropriate. - const c = inspect.defaultOptions.colors; - const actualRaw = c ? removeColors(actualLines[0]) : actualLines[0]; - const expectedRaw = c ? removeColors(expectedLines[0]) : expectedLines[0]; - const inputLength = actualRaw.length + expectedRaw.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) && - (actual !== 0 || expected !== 0) - ) { // -0 === +0 - return `${kReadableOperator[operator]}\n\n` + - `${actualLines[0]} !== ${expectedLines[0]}\n`; - } - } 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. - const maxLength = Deno.isatty(Deno.stderr.rid) ? getConsoleWidth() : 80; - if (inputLength < maxLength) { - while (actualRaw[i] === expectedRaw[i]) { - i++; - } - // Ignore the first characters. - 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)}^`; - i = 0; - } - } - } - } - - // Remove all ending lines that match (this optimizes the output for - // readability by reducing the number of total changed lines). - let a = actualLines[actualLines.length - 1]; - let b = expectedLines[expectedLines.length - 1]; - while (a === b) { - if (i++ < 3) { - end = `\n ${a}${end}`; - } else { - other = a; - } - actualLines.pop(); - expectedLines.pop(); - if (actualLines.length === 0 || expectedLines.length === 0) { - break; - } - a = actualLines[actualLines.length - 1]; - b = expectedLines[expectedLines.length - 1]; - } - - const maxLines = MathMax(actualLines.length, expectedLines.length); - // Strict equal with identical objects that are not identical by reference. - // 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"); - - // Only remove lines in case it makes sense to collapse those. - if (actualLines.length > 50) { - actualLines[46] = `${blue}...${defaultColor}`; - while (actualLines.length > 47) { - actualLines.pop(); - } - } - - return `${kReadableOperator.notIdentical}\n\n${actualLines.join("\n")}\n`; - } - - // There were at least five identical lines at the end. Mark a couple of - // skipped. - if (i >= 5) { - end = `\n${blue}...${defaultColor}${end}`; - skipped = true; - } - if (other !== "") { - end = `\n ${other}${end}`; - other = ""; - } - - let printedLines = 0; - let identical = 0; - const msg = kReadableOperator[operator] + - `\n${green}+ actual${defaultColor} ${red}- expected${defaultColor}`; - const skippedMsg = ` ${blue}...${defaultColor} Lines skipped`; - - let lines = actualLines; - let plusMinus = `${green}+${defaultColor}`; - let maxLength = expectedLines.length; - if (actualLines.length < maxLines) { - lines = expectedLines; - plusMinus = `${red}-${defaultColor}`; - maxLength = actualLines.length; - } - - for (i = 0; i < maxLines; i++) { - if (maxLength < i + 1) { - // If more than two former lines are identical, print them. Collapse them - // in case more than five lines were identical. - if (identical > 2) { - if (identical > 3) { - if (identical > 4) { - if (identical === 5) { - res += `\n ${lines[i - 3]}`; - printedLines++; - } else { - res += `\n${blue}...${defaultColor}`; - skipped = true; - } - } - res += `\n ${lines[i - 2]}`; - printedLines++; - } - res += `\n ${lines[i - 1]}`; - printedLines++; - } - // No identical lines before. - identical = 0; - // Add the expected line to the cache. - if (lines === actualLines) { - res += `\n${plusMinus} ${lines[i]}`; - } else { - other += `\n${plusMinus} ${lines[i]}`; - } - printedLines++; - // Only extra actual lines exist - // Lines diverge - } else { - const expectedLine = expectedLines[i]; - let actualLine = actualLines[i]; - // 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.endsWith(",") || - actualLine.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 - // look weird as in: - // - // [ - // 1 // No comma at the end! - // + 2 - // ] - // - if ( - divergingLines && - expectedLine.endsWith(",") && - expectedLine.slice(0, -1) === actualLine - ) { - divergingLines = false; - actualLine += ","; - } - if (divergingLines) { - // If more than two former lines are identical, print them. Collapse - // them in case more than five lines were identical. - if (identical > 2) { - if (identical > 3) { - if (identical > 4) { - if (identical === 5) { - res += `\n ${actualLines[i - 3]}`; - printedLines++; - } else { - res += `\n${blue}...${defaultColor}`; - skipped = true; - } - } - res += `\n ${actualLines[i - 2]}`; - printedLines++; - } - res += `\n ${actualLines[i - 1]}`; - printedLines++; - } - // No identical lines before. - identical = 0; - // Add the actual line to the result and cache the expected diverging - // line so consecutive diverging lines show up as +++--- and not +-+-+-. - res += `\n${green}+${defaultColor} ${actualLine}`; - other += `\n${red}-${defaultColor} ${expectedLine}`; - printedLines += 2; - // Lines are identical - } else { - // Add all cached information to the result before adding other things - // and reset the cache. - res += other; - other = ""; - identical++; - // The very first identical line since the last diverging line is be - // added to the result. - if (identical <= 2) { - res += `\n ${actualLine}`; - printedLines++; - } - } - } - // 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}${skipped ? skippedMsg : ""}\n${res}${other}${end}${indicator}`; -} - -export interface AssertionErrorDetailsDescriptor { - message: string; - actual: unknown; - expected: unknown; - operator: string; - stack: Error; -} - -export interface AssertionErrorConstructorOptions { - message?: string; - actual?: unknown; - expected?: unknown; - operator?: string; - details?: AssertionErrorDetailsDescriptor[]; - // deno-lint-ignore ban-types - stackStartFn?: Function; - // Compatibility with older versions. - // deno-lint-ignore ban-types - stackStartFunction?: Function; -} - -interface ErrorWithStackTraceLimit extends ErrorConstructor { - stackTraceLimit: number; -} - -export class AssertionError extends Error { - [key: string]: unknown - - // deno-lint-ignore constructor-super - constructor(options: AssertionErrorConstructorOptions) { - if (typeof options !== "object" || options === null) { - throw new ERR_INVALID_ARG_TYPE("options", "Object", options); - } - const { - message, - operator, - stackStartFn, - details, - // Compatibility with older versions. - stackStartFunction, - } = options; - let { - actual, - expected, - } = options; - - // TODO(schwarzkopfb): `stackTraceLimit` should be added to `ErrorConstructor` in - // cli/dts/lib.deno.shared_globals.d.ts - const limit = (Error as ErrorWithStackTraceLimit).stackTraceLimit; - (Error as ErrorWithStackTraceLimit).stackTraceLimit = 0; - - if (message != null) { - super(String(message)); - } else { - if (Deno.isatty(Deno.stderr.rid)) { - // Reset on each call to make sure we handle dynamically set environment - // variables correct. - if (Deno.noColor) { - blue = ""; - green = ""; - defaultColor = ""; - red = ""; - } else { - blue = "\u001b[34m"; - green = "\u001b[32m"; - defaultColor = "\u001b[39m"; - red = "\u001b[31m"; - } - } - // Prevent the error stack from being visible by duplicating the 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 - ) { - actual = copyError(actual); - expected = copyError(expected); - } - - if (operator === "deepStrictEqual" || operator === "strictEqual") { - super(createErrDiff(actual, expected, operator)); - } else if ( - 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"); - - // 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") - ) { - base = kReadableOperator.notStrictEqualObject; - } - - // Only remove lines in case it makes sense to collapse those. - if (res.length > 50) { - res[46] = `${blue}...${defaultColor}`; - while (res.length > 47) { - res.pop(); - } - } - - // Only print a single input. - if (res.length === 1) { - super(`${base}${res[0].length > 5 ? "\n\n" : " "}${res[0]}`); - } else { - 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) { - res = `${knownOperator}\n\n${res}`; - if (res.length > 1024) { - res = `${res.slice(0, 1021)}...`; - } - super(res); - } else { - if (res.length > 512) { - res = `${res.slice(0, 509)}...`; - } - if (other.length > 512) { - other = `${other.slice(0, 509)}...`; - } - if (operator === "deepEqual") { - res = `${knownOperator}\n\n${res}\n\nshould loosely deep-equal\n\n`; - } else { - const newOp = kReadableOperator[`${operator}Unequal`]; - if (newOp) { - res = `${newOp}\n\n${res}\n\nshould not loosely deep-equal\n\n`; - } else { - other = ` ${operator} ${other}`; - } - } - super(`${res}${other}`); - } - } - } - - (Error as ErrorWithStackTraceLimit).stackTraceLimit = limit; - - this.generatedMessage = !message; - ObjectDefineProperty(this, "name", { - value: "AssertionError [ERR_ASSERTION]", - enumerable: false, - writable: true, - configurable: true, - }); - this.code = "ERR_ASSERTION"; - - if (details) { - this.actual = undefined; - this.expected = undefined; - this.operator = undefined; - - for (let i = 0; i < details.length; i++) { - this["message " + i] = details[i].message; - this["actual " + i] = details[i].actual; - this["expected " + i] = details[i].expected; - this["operator " + i] = details[i].operator; - this["stack trace " + i] = details[i].stack; - } - } else { - this.actual = actual; - this.expected = expected; - this.operator = operator; - } - - Error.captureStackTrace(this, stackStartFn || stackStartFunction); - // Create error message including the error code in the name. - this.stack; - // Reset the name. - this.name = "AssertionError"; - } - - toString() { - return `${this.name} [${this.code}]: ${this.message}`; - } - - [inspect.custom](recurseTimes: number, ctx: Record<string, unknown>) { - // Long strings should not be fully inspected. - const tmpActual = this.actual; - const tmpExpected = this.expected; - - for (const name of ["actual", "expected"]) { - if (typeof this[name] === "string") { - const value = (this[name] as string); - const lines = value.split("\n"); - if (lines.length > 10) { - lines.length = 10; - this[name] = `${lines.join("\n")}\n...`; - } else if (value.length > 512) { - this[name] = `${value.slice(512)}...`; - } - } - } - - // This limits the `actual` and `expected` property default inspection to - // the minimum depth. Otherwise those values would be too verbose compared - // to the actual error message which contains a combined view of these two - // input values. - const result = inspect(this, { - ...ctx, - customInspect: false, - depth: 0, - }); - - // Reset the properties after inspection. - this.actual = tmpActual; - this.expected = tmpExpected; - - return result; - } -} - -export default AssertionError; diff --git a/std/node/assertion_error_test.ts b/std/node/assertion_error_test.ts deleted file mode 100644 index f4c9f2b19..000000000 --- a/std/node/assertion_error_test.ts +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { stripColor } from "../fmt/colors.ts"; -import { - assert, - assertEquals, - assertNotStrictEquals, - assertStrictEquals, -} from "../testing/asserts.ts"; -import { - AssertionError, - copyError, - createErrDiff, - inspectValue, -} from "./assertion_error.ts"; - -Deno.test({ - name: "copyError()", - fn() { - class TestError extends Error {} - const err = new TestError("this is a test"); - const copy = copyError(err); - - assert(copy instanceof Error, "Copy should inherit from Error."); - assert(copy instanceof TestError, "Copy should inherit from TestError."); - assertEquals(copy, err, "Copy should be equal to the original error."); - assertNotStrictEquals( - copy, - err, - "Copy should not be strictly equal to the original error.", - ); - }, -}); - -Deno.test({ - name: "inspectValue()", - fn() { - const obj = { a: 1, b: [2] }; - Object.defineProperty(obj, "c", { value: 3, enumerable: false }); - assertStrictEquals( - stripColor(inspectValue(obj)), - "{ a: 1, b: [ 2 ] }", - ); - }, -}); - -Deno.test({ - name: "createErrDiff()", - fn() { - assertStrictEquals( - stripColor( - createErrDiff({ a: 1, b: 2 }, { a: 2, b: 2 }, "strictEqual"), - ), - stripColor( - 'Expected "actual" to be reference-equal to "expected":' + "\n" + - "+ actual - expected" + "\n" + - "\n" + - "+ { a: 1, b: 2 }" + "\n" + - "- { a: 2, b: 2 }", - ), - ); - }, -}); - -Deno.test({ - name: "construct AssertionError() with given message", - fn() { - const err = new AssertionError( - { - message: "answer", - actual: "42", - expected: "42", - operator: "notStrictEqual", - }, - ); - assertStrictEquals(err.name, "AssertionError"); - assertStrictEquals(err.message, "answer"); - assertStrictEquals(err.generatedMessage, false); - assertStrictEquals(err.code, "ERR_ASSERTION"); - assertStrictEquals(err.actual, "42"); - assertStrictEquals(err.expected, "42"); - assertStrictEquals(err.operator, "notStrictEqual"); - }, -}); - -Deno.test({ - name: "construct AssertionError() with generated message", - fn() { - const err = new AssertionError( - { actual: 1, expected: 2, operator: "equal" }, - ); - assertStrictEquals(err.name, "AssertionError"); - assertStrictEquals(stripColor(err.message), "1 equal 2"); - assertStrictEquals(err.generatedMessage, true); - assertStrictEquals(err.code, "ERR_ASSERTION"); - assertStrictEquals(err.actual, 1); - assertStrictEquals(err.expected, 2); - assertStrictEquals(err.operator, "equal"); - }, -}); - -Deno.test({ - name: "construct AssertionError() with stackStartFn", - fn: function stackStartFn() { - const expected = /node/; - const err = new AssertionError({ - actual: "deno", - expected, - operator: "match", - stackStartFn, - }); - assertStrictEquals(err.name, "AssertionError"); - assertStrictEquals(stripColor(err.message), `"deno" match /node/`); - assertStrictEquals(err.generatedMessage, true); - assertStrictEquals(err.code, "ERR_ASSERTION"); - assertStrictEquals(err.actual, "deno"); - assertStrictEquals(err.expected, expected); - assertStrictEquals(err.operator, "match"); - assert(err.stack, "error should have a stack"); - assert( - !err.stack?.includes("stackStartFn"), - "stackStartFn() should not present in stack trace", - ); - }, -}); - -Deno.test({ - name: "error details", - fn() { - const stack0 = new Error(); - const stack1 = new Error(); - const err = new AssertionError({ - message: "Function(s) were not called the expected number of times", - details: [ - { - message: - "Expected the calls function to be executed 2 time(s) but was executed 3 time(s).", - actual: 3, - expected: 2, - operator: "calls", - stack: stack0, - }, - { - message: - "Expected the fn function to be executed 1 time(s) but was executed 0 time(s).", - actual: 0, - expected: 1, - operator: "fn", - stack: stack1, - }, - ], - }); - - assertStrictEquals( - err.message, - "Function(s) were not called the expected number of times", - ); - - assertStrictEquals( - err["message 0"], - "Expected the calls function to be executed 2 time(s) but was executed 3 time(s).", - ); - assertStrictEquals(err["actual 0"], 3); - assertStrictEquals(err["expected 0"], 2); - assertStrictEquals(err["operator 0"], "calls"); - assertStrictEquals(err["stack trace 0"], stack0); - - assertStrictEquals( - err["message 1"], - "Expected the fn function to be executed 1 time(s) but was executed 0 time(s).", - ); - assertStrictEquals(err["actual 1"], 0); - assertStrictEquals(err["expected 1"], 1); - assertStrictEquals(err["operator 1"], "fn"); - assertStrictEquals(err["stack trace 1"], stack1); - }, -}); diff --git a/std/node/buffer.ts b/std/node/buffer.ts deleted file mode 100644 index 379a2c09a..000000000 --- a/std/node/buffer.ts +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import * as hex from "../encoding/hex.ts"; -import * as base64 from "../encoding/base64.ts"; -import { Encodings, normalizeEncoding, notImplemented } from "./_utils.ts"; - -const notImplementedEncodings = [ - "ascii", - "binary", - "latin1", - "ucs2", - "utf16le", -]; - -function checkEncoding(encoding = "utf8", strict = true): Encodings { - if (typeof encoding !== "string" || (strict && encoding === "")) { - if (!strict) return "utf8"; - throw new TypeError(`Unkown encoding: ${encoding}`); - } - - const normalized = normalizeEncoding(encoding); - - if (normalized === undefined) { - throw new TypeError(`Unkown encoding: ${encoding}`); - } - - if (notImplementedEncodings.includes(encoding)) { - notImplemented(`"${encoding}" encoding`); - } - - return normalized; -} - -interface EncodingOp { - byteLength(string: string): number; -} - -// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/lib/buffer.js#L598 -const encodingOps: { [key: string]: EncodingOp } = { - utf8: { - byteLength: (string: string): number => - new TextEncoder().encode(string).byteLength, - }, - ucs2: { - byteLength: (string: string): number => string.length * 2, - }, - utf16le: { - byteLength: (string: string): number => string.length * 2, - }, - latin1: { - byteLength: (string: string): number => string.length, - }, - ascii: { - byteLength: (string: string): number => string.length, - }, - base64: { - byteLength: (string: string): number => - base64ByteLength(string, string.length), - }, - hex: { - byteLength: (string: string): number => string.length >>> 1, - }, -}; - -function base64ByteLength(str: string, bytes: number): number { - // Handle padding - if (str.charCodeAt(bytes - 1) === 0x3d) bytes--; - if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3d) bytes--; - - // Base64 ratio: 3/4 - return (bytes * 3) >>> 2; -} - -/** - * See also https://nodejs.org/api/buffer.html - */ -export class Buffer extends Uint8Array { - /** - * Allocates a new Buffer of size bytes. - */ - static alloc( - size: number, - fill?: number | string | Uint8Array | Buffer, - encoding = "utf8", - ): Buffer { - if (typeof size !== "number") { - throw new TypeError( - `The "size" argument must be of type number. Received type ${typeof size}`, - ); - } - - const buf = new Buffer(size); - if (size === 0) return buf; - - let bufFill; - if (typeof fill === "string") { - const clearEncoding = checkEncoding(encoding); - if ( - typeof fill === "string" && - fill.length === 1 && - clearEncoding === "utf8" - ) { - buf.fill(fill.charCodeAt(0)); - } else bufFill = Buffer.from(fill, clearEncoding); - } else if (typeof fill === "number") { - buf.fill(fill); - } else if (fill instanceof Uint8Array) { - if (fill.length === 0) { - throw new TypeError( - `The argument "value" is invalid. Received ${fill.constructor.name} []`, - ); - } - - bufFill = fill; - } - - if (bufFill) { - if (bufFill.length > buf.length) { - bufFill = bufFill.subarray(0, buf.length); - } - - let offset = 0; - while (offset < size) { - buf.set(bufFill, offset); - offset += bufFill.length; - if (offset + bufFill.length >= size) break; - } - if (offset !== size) { - buf.set(bufFill.subarray(0, size - offset), offset); - } - } - - return buf; - } - - static allocUnsafe(size: number): Buffer { - return new Buffer(size); - } - - /** - * Returns the byte length of a string when encoded. This is not the same as - * String.prototype.length, which does not account for the encoding that is - * used to convert the string into bytes. - */ - static byteLength( - string: string | Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, - encoding = "utf8", - ): number { - if (typeof string != "string") return string.byteLength; - - encoding = normalizeEncoding(encoding) || "utf8"; - return encodingOps[encoding].byteLength(string); - } - - /** - * Returns a new Buffer which is the result of concatenating all the Buffer - * instances in the list together. - */ - static concat(list: Buffer[] | Uint8Array[], totalLength?: number): Buffer { - if (totalLength == undefined) { - totalLength = 0; - for (const buf of list) { - totalLength += buf.length; - } - } - - const buffer = Buffer.allocUnsafe(totalLength); - let pos = 0; - for (const item of list) { - let buf: Buffer; - if (!(item instanceof Buffer)) { - buf = Buffer.from(item); - } else { - buf = item; - } - buf.copy(buffer, pos); - pos += buf.length; - } - - return buffer; - } - - /** - * Allocates a new Buffer using an array of bytes in the range 0 – 255. Array - * entries outside that range will be truncated to fit into it. - */ - static from(array: number[]): Buffer; - /** - * This creates a view of the ArrayBuffer without copying the underlying - * memory. For example, when passed a reference to the .buffer property of a - * TypedArray instance, the newly created Buffer will share the same allocated - * memory as the TypedArray. - */ - static from( - arrayBuffer: ArrayBuffer | SharedArrayBuffer, - byteOffset?: number, - length?: number, - ): Buffer; - /** - * Copies the passed buffer data onto a new Buffer instance. - */ - static from(buffer: Buffer | Uint8Array): Buffer; - /** - * Creates a new Buffer containing string. - */ - static from(string: string, encoding?: string): Buffer; - static from( - // deno-lint-ignore no-explicit-any - value: any, - offsetOrEncoding?: number | string, - length?: number, - ): Buffer { - const offset = typeof offsetOrEncoding === "string" - ? undefined - : offsetOrEncoding; - let encoding = typeof offsetOrEncoding === "string" - ? offsetOrEncoding - : undefined; - - if (typeof value == "string") { - encoding = checkEncoding(encoding, false); - if (encoding === "hex") return new Buffer(hex.decodeString(value).buffer); - if (encoding === "base64") return new Buffer(base64.decode(value).buffer); - return new Buffer(new TextEncoder().encode(value).buffer); - } - - // workaround for https://github.com/microsoft/TypeScript/issues/38446 - return new Buffer(value, offset!, length); - } - - /** - * Returns true if obj is a Buffer, false otherwise. - */ - static isBuffer(obj: unknown): obj is Buffer { - return obj instanceof Buffer; - } - - // deno-lint-ignore no-explicit-any - static isEncoding(encoding: any): boolean { - return ( - typeof encoding === "string" && - encoding.length !== 0 && - normalizeEncoding(encoding) !== undefined - ); - } - - /** - * Copies data from a region of buf to a region in target, even if the target - * memory region overlaps with buf. - */ - copy( - targetBuffer: Buffer | Uint8Array, - targetStart = 0, - sourceStart = 0, - sourceEnd = this.length, - ): number { - const sourceBuffer = this - .subarray(sourceStart, sourceEnd) - .subarray(0, Math.max(0, targetBuffer.length - targetStart)); - - if (sourceBuffer.length === 0) return 0; - - targetBuffer.set(sourceBuffer, targetStart); - return sourceBuffer.length; - } - - /* - * Returns true if both buf and otherBuffer have exactly the same bytes, false otherwise. - */ - equals(otherBuffer: Uint8Array | Buffer): boolean { - if (!(otherBuffer instanceof Uint8Array)) { - throw new TypeError( - `The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received type ${typeof otherBuffer}`, - ); - } - - if (this === otherBuffer) return true; - if (this.byteLength !== otherBuffer.byteLength) return false; - - for (let i = 0; i < this.length; i++) { - if (this[i] !== otherBuffer[i]) return false; - } - - return true; - } - - readBigInt64BE(offset = 0): bigint { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getBigInt64(offset); - } - readBigInt64LE(offset = 0): bigint { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getBigInt64(offset, true); - } - - readBigUInt64BE(offset = 0): bigint { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getBigUint64(offset); - } - readBigUInt64LE(offset = 0): bigint { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getBigUint64(offset, true); - } - - readDoubleBE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getFloat64(offset); - } - readDoubleLE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getFloat64(offset, true); - } - - readFloatBE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getFloat32(offset); - } - readFloatLE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getFloat32(offset, true); - } - - readInt8(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt8( - offset, - ); - } - - readInt16BE(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16( - offset, - ); - } - readInt16LE(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16( - offset, - true, - ); - } - - readInt32BE(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32( - offset, - ); - } - readInt32LE(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32( - offset, - true, - ); - } - - readUInt8(offset = 0): number { - return new DataView(this.buffer, this.byteOffset, this.byteLength).getUint8( - offset, - ); - } - - readUInt16BE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getUint16(offset); - } - readUInt16LE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getUint16(offset, true); - } - - readUInt32BE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getUint32(offset); - } - readUInt32LE(offset = 0): number { - return new DataView( - this.buffer, - this.byteOffset, - this.byteLength, - ).getUint32(offset, true); - } - - /** - * Returns a new Buffer that references the same memory as the original, but - * offset and cropped by the start and end indices. - */ - slice(begin = 0, end = this.length): Buffer { - // workaround for https://github.com/microsoft/TypeScript/issues/38665 - return this.subarray(begin, end) as Buffer; - } - - /** - * Returns a JSON representation of buf. JSON.stringify() implicitly calls - * this function when stringifying a Buffer instance. - */ - toJSON(): Record<string, unknown> { - return { type: "Buffer", data: Array.from(this) }; - } - - /** - * Decodes buf to a string according to the specified character encoding in - * encoding. start and end may be passed to decode only a subset of buf. - */ - toString(encoding = "utf8", start = 0, end = this.length): string { - encoding = checkEncoding(encoding); - - const b = this.subarray(start, end); - if (encoding === "hex") return hex.encodeToString(b); - if (encoding === "base64") return base64.encode(b.buffer); - - return new TextDecoder(encoding).decode(b); - } - - /** - * Writes string to buf at offset according to the character encoding in - * encoding. The length parameter is the number of bytes to write. If buf did - * not contain enough space to fit the entire string, only part of string will - * be written. However, partially encoded characters will not be written. - */ - write(string: string, offset = 0, length = this.length): number { - return new TextEncoder().encodeInto( - string, - this.subarray(offset, offset + length), - ).written; - } - - writeBigInt64BE(value: bigint, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64( - offset, - value, - ); - return offset + 4; - } - writeBigInt64LE(value: bigint, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64( - offset, - value, - true, - ); - return offset + 4; - } - - writeBigUInt64BE(value: bigint, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64( - offset, - value, - ); - return offset + 4; - } - writeBigUInt64LE(value: bigint, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64( - offset, - value, - true, - ); - return offset + 4; - } - - writeDoubleBE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64( - offset, - value, - ); - return offset + 8; - } - writeDoubleLE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64( - offset, - value, - true, - ); - return offset + 8; - } - - writeFloatBE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32( - offset, - value, - ); - return offset + 4; - } - writeFloatLE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32( - offset, - value, - true, - ); - return offset + 4; - } - - writeInt8(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setInt8( - offset, - value, - ); - return offset + 1; - } - - writeInt16BE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16( - offset, - value, - ); - return offset + 2; - } - writeInt16LE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16( - offset, - value, - true, - ); - return offset + 2; - } - - writeInt32BE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( - offset, - value, - ); - return offset + 4; - } - writeInt32LE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setInt32( - offset, - value, - true, - ); - return offset + 4; - } - - writeUInt8(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint8( - offset, - value, - ); - return offset + 1; - } - - writeUInt16BE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16( - offset, - value, - ); - return offset + 2; - } - writeUInt16LE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16( - offset, - value, - true, - ); - return offset + 2; - } - - writeUInt32BE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( - offset, - value, - ); - return offset + 4; - } - writeUInt32LE(value: number, offset = 0): number { - new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( - offset, - value, - true, - ); - return offset + 4; - } -} - -export default { Buffer }; diff --git a/std/node/buffer_test.ts b/std/node/buffer_test.ts deleted file mode 100644 index f3fee8e29..000000000 --- a/std/node/buffer_test.ts +++ /dev/null @@ -1,649 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals, assertThrows } from "../testing/asserts.ts"; -import { Buffer } from "./buffer.ts"; - -Deno.test({ - name: "alloc fails on negative numbers", - fn() { - assertThrows( - () => { - Buffer.alloc(-1); - }, - RangeError, - "Invalid typed array length: -1", - "should throw on negative numbers", - ); - }, -}); - -Deno.test({ - name: "alloc fails if size is not a number", - fn() { - const invalidSizes = [{}, "1", "foo", []]; - - for (const size of invalidSizes) { - assertThrows( - () => { - // deno-lint-ignore ban-ts-comment - // @ts-expect-error - Buffer.alloc(size); - }, - TypeError, - `The "size" argument must be of type number. Received type ${typeof size}`, - "should throw on non-number size", - ); - } - }, -}); - -Deno.test({ - name: "alloc(>0) fails if value is an empty Buffer/Uint8Array", - fn() { - const invalidValues = [new Uint8Array(), Buffer.alloc(0)]; - - for (const value of invalidValues) { - assertThrows( - () => { - console.log(value.constructor.name); - Buffer.alloc(1, value); - }, - TypeError, - `The argument "value" is invalid. Received ${value.constructor.name} []`, - "should throw for empty Buffer/Uint8Array", - ); - } - }, -}); - -Deno.test({ - name: "alloc(0) doesn't fail if value is an empty Buffer/Uint8Array", - fn() { - const invalidValues = [new Uint8Array(), Buffer.alloc(0)]; - - for (const value of invalidValues) { - assertEquals(Buffer.alloc(0, value).length, 0); - } - }, -}); - -Deno.test({ - name: "alloc allocates a buffer with the expected size", - fn() { - const buffer: Buffer = Buffer.alloc(1); - assertEquals(buffer.length, 1, "Buffer size should be 1"); - assertEquals(buffer[0], 0, "Content should be filled with 0"); - }, -}); - -Deno.test({ - name: "alloc(0) creates an empty buffer", - fn() { - const buffer: Buffer = Buffer.alloc(0); - assertEquals(buffer.length, 0, "Buffer size should be 0"); - }, -}); - -Deno.test({ - name: "allocUnsafe allocates a buffer with the expected size", - fn() { - const buffer: Buffer = Buffer.allocUnsafe(1); - assertEquals(buffer.length, 1, "Buffer size should be 1"); - }, -}); - -Deno.test({ - name: "allocUnsafe(0) creates an empty buffer", - fn() { - const buffer: Buffer = Buffer.allocUnsafe(0); - assertEquals(buffer.length, 0, "Buffer size should be 0"); - }, -}); - -Deno.test({ - name: "alloc filled correctly with integer", - fn() { - const buffer: Buffer = Buffer.alloc(3, 5); - assertEquals(buffer, new Uint8Array([5, 5, 5])); - }, -}); - -Deno.test({ - name: "alloc filled correctly with single character", - fn() { - assertEquals(Buffer.alloc(5, "a"), new Uint8Array([97, 97, 97, 97, 97])); - }, -}); - -Deno.test({ - name: "alloc filled correctly with base64 string", - fn() { - assertEquals( - Buffer.alloc(11, "aGVsbG8gd29ybGQ=", "base64"), - new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), - ); - }, -}); - -Deno.test({ - name: "alloc filled correctly with hex string", - fn() { - assertEquals( - Buffer.alloc(4, "64656e6f", "hex"), - new Uint8Array([100, 101, 110, 111]), - ); - }, -}); - -Deno.test({ - name: "alloc filled correctly with hex string smaller than alloc size", - fn() { - assertEquals( - Buffer.alloc(13, "64656e6f", "hex").toString(), - "denodenodenod", - ); - }, -}); - -Deno.test({ - name: "alloc filled correctly with Uint8Array smaller than alloc size", - fn() { - assertEquals( - Buffer.alloc(7, new Uint8Array([100, 101])), - new Uint8Array([100, 101, 100, 101, 100, 101, 100]), - ); - assertEquals( - Buffer.alloc(6, new Uint8Array([100, 101])), - new Uint8Array([100, 101, 100, 101, 100, 101]), - ); - }, -}); - -Deno.test({ - name: "alloc filled correctly with Uint8Array bigger than alloc size", - fn() { - assertEquals( - Buffer.alloc(1, new Uint8Array([100, 101])), - new Uint8Array([100]), - ); - }, -}); - -Deno.test({ - name: "alloc filled correctly with Buffer", - fn() { - assertEquals( - Buffer.alloc(6, new Buffer([100, 101])), - new Uint8Array([100, 101, 100, 101, 100, 101]), - ); - assertEquals( - Buffer.alloc(7, new Buffer([100, 101])), - new Uint8Array([100, 101, 100, 101, 100, 101, 100]), - ); - }, -}); - -// tests from: -// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/test/parallel/test-buffer-bytelength.js#L70 -Deno.test({ - name: "Byte length is the expected for strings", - fn() { - // Special case: zero length string - assertEquals(Buffer.byteLength("", "ascii"), 0); - assertEquals(Buffer.byteLength("", "HeX"), 0); - - // utf8 - assertEquals(Buffer.byteLength("∑éllö wørl∂!", "utf-8"), 19); - assertEquals(Buffer.byteLength("κλμνξο", "utf8"), 12); - assertEquals(Buffer.byteLength("挵挶挷挸挹", "utf-8"), 15); - assertEquals(Buffer.byteLength("𠝹𠱓𠱸", "UTF8"), 12); - // Without an encoding, utf8 should be assumed - assertEquals(Buffer.byteLength("hey there"), 9); - assertEquals(Buffer.byteLength("𠱸挶νξ#xx :)"), 17); - assertEquals(Buffer.byteLength("hello world", ""), 11); - // It should also be assumed with unrecognized encoding - assertEquals(Buffer.byteLength("hello world", "abc"), 11); - assertEquals(Buffer.byteLength("ßœ∑≈", "unkn0wn enc0ding"), 10); - - // base64 - assertEquals(Buffer.byteLength("aGVsbG8gd29ybGQ=", "base64"), 11); - assertEquals(Buffer.byteLength("aGVsbG8gd29ybGQ=", "BASE64"), 11); - assertEquals(Buffer.byteLength("bm9kZS5qcyByb2NrcyE=", "base64"), 14); - assertEquals(Buffer.byteLength("aGkk", "base64"), 3); - assertEquals( - Buffer.byteLength("bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==", "base64"), - 25, - ); - // special padding - assertEquals(Buffer.byteLength("aaa=", "base64"), 2); - assertEquals(Buffer.byteLength("aaaa==", "base64"), 3); - - assertEquals(Buffer.byteLength("Il était tué"), 14); - assertEquals(Buffer.byteLength("Il était tué", "utf8"), 14); - - ["ascii", "latin1", "binary"] - .reduce((es: string[], e: string) => es.concat(e, e.toUpperCase()), []) - .forEach((encoding: string) => { - assertEquals(Buffer.byteLength("Il était tué", encoding), 12); - }); - - ["ucs2", "ucs-2", "utf16le", "utf-16le"] - .reduce((es: string[], e: string) => es.concat(e, e.toUpperCase()), []) - .forEach((encoding: string) => { - assertEquals(Buffer.byteLength("Il était tué", encoding), 24); - }); - }, -}); - -Deno.test({ - name: "Byte length is the expected one for non-strings", - fn() { - assertEquals( - Buffer.byteLength(Buffer.alloc(0)), - Buffer.alloc(0).byteLength, - "Byte lenght differs on buffers", - ); - }, -}); - -Deno.test({ - name: "Two Buffers are concatenated", - fn() { - const data1 = [1, 2, 3]; - const data2 = [4, 5, 6]; - - const buffer1 = Buffer.from(data1); - const buffer2 = Buffer.from(data2); - - const resultBuffer = Buffer.concat([buffer1, buffer2]); - const expectedBuffer = Buffer.from([...data1, ...data2]); - assertEquals(resultBuffer, expectedBuffer); - }, -}); - -Deno.test({ - name: "A single buffer concatenates and return the same buffer", - fn() { - const buffer1 = Buffer.alloc(1); - const resultBuffer = Buffer.concat([buffer1]); - assertEquals(resultBuffer.length, 1, "Buffer length should be 1"); - }, -}); - -Deno.test({ - name: "No buffers concat returns an empty buffer", - fn() { - const resultBuffer = Buffer.concat([]); - assertEquals(resultBuffer.length, 0, "Buffer length should be 0"); - }, -}); - -Deno.test({ - name: "Buffer concat respects totalLenght parameter", - fn() { - const maxLength1 = 10; - const buffer1 = Buffer.alloc(2); - const buffer2 = Buffer.alloc(2); - assertEquals( - Buffer.concat([buffer1, buffer2], maxLength1).length, - maxLength1, - ); - - const maxLength2 = 3; - const buffer3 = Buffer.alloc(2); - const buffer4 = Buffer.alloc(2); - assertEquals( - Buffer.concat([buffer3, buffer4], maxLength2).length, - maxLength2, - ); - }, -}); - -Deno.test({ - name: "Buffer copy works as expected", - fn() { - const data1 = new Uint8Array([1, 2, 3]); - const data2 = new Uint8Array([4, 5, 6]); - - const buffer1 = Buffer.from(data1); - const buffer2 = Buffer.from(data2); - - //Mutates data_1 - data1.set(data2); - //Mutates buffer_1 - buffer2.copy(buffer1); - - assertEquals( - data1, - buffer1, - ); - }, -}); - -Deno.test({ - name: "Buffer copy respects the starting point for copy", - fn() { - const buffer1 = Buffer.from([1, 2, 3]); - const buffer2 = Buffer.alloc(8); - - buffer1.copy(buffer2, 5); - - const expected = Buffer.from([0, 0, 0, 0, 0, 1, 2, 3]); - - assertEquals( - buffer2, - expected, - ); - }, -}); - -Deno.test({ - name: "Buffer copy doesn't throw on offset but copies until offset reached", - fn() { - const buffer1 = Buffer.from([1, 2, 3]); - const buffer2 = Buffer.alloc(8); - - const writtenBytes1 = buffer1.copy(buffer2, 6); - - assertEquals( - writtenBytes1, - 2, - ); - - assertEquals( - buffer2, - Buffer.from([0, 0, 0, 0, 0, 0, 1, 2]), - ); - - const buffer3 = Buffer.from([1, 2, 3]); - const buffer4 = Buffer.alloc(8); - - const writtenBytes2 = buffer3.copy(buffer4, 8); - - assertEquals( - writtenBytes2, - 0, - ); - - assertEquals( - buffer4, - Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), - ); - }, -}); - -Deno.test({ - name: "Buffer from string creates a Buffer", - fn() { - const buffer: Buffer = Buffer.from("test"); - assertEquals(buffer.length, 4, "Buffer length should be 4"); - assertEquals( - buffer.toString(), - "test", - "Buffer to string should recover the string", - ); - }, -}); - -Deno.test({ - name: "Buffer from string hex", - fn() { - for (const encoding of ["hex", "HEX"]) { - const buffer: Buffer = Buffer.from( - "7468697320697320612074c3a97374", - encoding, - ); - assertEquals(buffer.length, 15, "Buffer length should be 15"); - assertEquals( - buffer.toString(), - "this is a tést", - "Buffer to string should recover the string", - ); - } - }, -}); - -Deno.test({ - name: "Buffer from string base64", - fn() { - for (const encoding of ["base64", "BASE64"]) { - const buffer: Buffer = Buffer.from("dGhpcyBpcyBhIHTDqXN0", encoding); - assertEquals(buffer.length, 15, "Buffer length should be 15"); - assertEquals( - buffer.toString(), - "this is a tést", - "Buffer to string should recover the string", - ); - } - }, -}); - -Deno.test({ - name: "Buffer to string base64", - fn() { - for (const encoding of ["base64", "BASE64"]) { - const buffer: Buffer = Buffer.from("deno land"); - assertEquals( - buffer.toString(encoding), - "ZGVubyBsYW5k", - "Buffer to string should recover the string in base64", - ); - } - const b64 = "dGhpcyBpcyBhIHTDqXN0"; - assertEquals(Buffer.from(b64, "base64").toString("base64"), b64); - }, -}); - -Deno.test({ - name: "Buffer to string hex", - fn() { - for (const encoding of ["hex", "HEX"]) { - const buffer: Buffer = Buffer.from("deno land"); - assertEquals( - buffer.toString(encoding), - "64656e6f206c616e64", - "Buffer to string should recover the string", - ); - } - const hex = "64656e6f206c616e64"; - assertEquals(Buffer.from(hex, "hex").toString("hex"), hex); - }, -}); - -Deno.test({ - name: "Buffer to string invalid encoding", - fn() { - const buffer: Buffer = Buffer.from("deno land"); - const invalidEncodings = [null, 5, {}, true, false, "foo", ""]; - - for (const encoding of invalidEncodings) { - assertThrows( - () => { - // deno-lint-ignore ban-ts-comment - // @ts-expect-error - buffer.toString(encoding); - }, - TypeError, - `Unkown encoding: ${encoding}`, - "Should throw on invalid encoding", - ); - } - }, -}); - -Deno.test({ - name: "Buffer from string invalid encoding", - fn() { - const defaultToUtf8Encodings = [null, 5, {}, true, false, ""]; - const invalidEncodings = ["deno", "base645"]; - - for (const encoding of defaultToUtf8Encodings) { - // deno-lint-ignore ban-ts-comment - // @ts-expect-error - assertEquals(Buffer.from("yes", encoding).toString(), "yes"); - } - - for (const encoding of invalidEncodings) { - assertThrows( - () => { - Buffer.from("yes", encoding); - }, - TypeError, - `Unkown encoding: ${encoding}`, - ); - } - }, -}); - -Deno.test({ - name: "Buffer to/from string not implemented encodings", - fn() { - const buffer: Buffer = Buffer.from("deno land"); - const notImplemented = ["ascii", "binary"]; - - for (const encoding of notImplemented) { - assertThrows( - () => { - buffer.toString(encoding); - }, - Error, - `"${encoding}" encoding`, - "Should throw on invalid encoding", - ); - - assertThrows( - () => { - Buffer.from("", encoding); - }, - Error, - `"${encoding}" encoding`, - "Should throw on invalid encoding", - ); - } - }, -}); - -Deno.test({ - name: "Buffer from another buffer creates a Buffer", - fn() { - const buffer: Buffer = Buffer.from(Buffer.from("test")); - assertEquals(buffer.length, 4, "Buffer length should be 4"); - assertEquals( - buffer.toString(), - "test", - "Buffer to string should recover the string", - ); - }, -}); - -Deno.test({ - name: "isBuffer returns true if the object is a buffer", - fn() { - assertEquals(Buffer.isBuffer(Buffer.from("test")), true); - }, -}); - -Deno.test({ - name: "isBuffer returns false if the object is not a buffer", - fn() { - assertEquals(Buffer.isBuffer({ test: 3 }), false); - assertEquals(Buffer.isBuffer(new Uint8Array()), false); - }, -}); - -Deno.test({ - name: "Buffer toJSON", - fn() { - assertEquals( - JSON.stringify(Buffer.from("deno")), - '{"type":"Buffer","data":[100,101,110,111]}', - ); - }, -}); - -Deno.test({ - name: "buf.slice does not create a copy", - fn() { - const buf = Buffer.from("ceno"); - // This method is not compatible with the Uint8Array.prototype.slice() - const slice = buf.slice(); - slice[0]++; - assertEquals(slice.toString(), "deno"); - }, -}); - -Deno.test({ - name: "isEncoding returns true for valid encodings", - fn() { - [ - "hex", - "HEX", - "HeX", - "utf8", - "utf-8", - "ascii", - "latin1", - "binary", - "base64", - "BASE64", - "BASe64", - "ucs2", - "ucs-2", - "utf16le", - "utf-16le", - ].forEach((enc) => { - assertEquals(Buffer.isEncoding(enc), true); - }); - }, -}); - -Deno.test({ - name: "isEncoding returns false for invalid encodings", - fn() { - [ - "utf9", - "utf-7", - "Unicode-FTW", - "new gnu gun", - false, - NaN, - {}, - Infinity, - [], - 1, - 0, - -1, - ].forEach((enc) => { - assertEquals(Buffer.isEncoding(enc), false); - }); - }, -}); - -// ported from: -// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/test/parallel/test-buffer-equals.js#L6 -Deno.test({ - name: "buf.equals", - fn() { - const b = Buffer.from("abcdf"); - const c = Buffer.from("abcdf"); - const d = Buffer.from("abcde"); - const e = Buffer.from("abcdef"); - - assertEquals(b.equals(c), true); - assertEquals(d.equals(d), true); - assertEquals( - d.equals(new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65])), - true, - ); - - assertEquals(c.equals(d), false); - assertEquals(d.equals(e), false); - - assertThrows( - // deno-lint-ignore ban-ts-comment - // @ts-expect-error - () => Buffer.alloc(1).equals("abc"), - TypeError, - `The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received type string`, - ); - }, -}); diff --git a/std/node/crypto.ts b/std/node/crypto.ts deleted file mode 100644 index 8b933a99c..000000000 --- a/std/node/crypto.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { default as randomBytes } from "./_crypto/randomBytes.ts"; -import { pbkdf2, pbkdf2Sync } from "./_crypto/pbkdf2.ts"; - -export default { randomBytes, pbkdf2, pbkdf2Sync }; -export { pbkdf2, pbkdf2Sync, randomBytes }; diff --git a/std/node/events.ts b/std/node/events.ts deleted file mode 100644 index f737c884c..000000000 --- a/std/node/events.ts +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// Copyright (c) 2019 Denolibs authors. All rights reserved. MIT license. -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -import { validateIntegerRange } from "./_utils.ts"; -import { assert } from "../_util/assert.ts"; - -// deno-lint-ignore no-explicit-any -export type GenericFunction = (...args: any[]) => any; - -export interface WrappedFunction extends Function { - listener: GenericFunction; -} - -// deno-lint-ignore no-explicit-any -function createIterResult(value: any, done: boolean): IteratorResult<any> { - return { value, done }; -} - -interface AsyncIterable { - // deno-lint-ignore no-explicit-any - next(): Promise<IteratorResult<any, any>>; - // deno-lint-ignore no-explicit-any - return(): Promise<IteratorResult<any, any>>; - throw(err: Error): void; - // deno-lint-ignore no-explicit-any - [Symbol.asyncIterator](): any; -} - -export let defaultMaxListeners = 10; - -/** - * See also https://nodejs.org/api/events.html - */ -export default class EventEmitter { - public static captureRejectionSymbol = Symbol.for("nodejs.rejection"); - public static errorMonitor = Symbol("events.errorMonitor"); - public static get defaultMaxListeners() { - return defaultMaxListeners; - } - public static set defaultMaxListeners(value: number) { - defaultMaxListeners = value; - } - - private maxListeners: number | undefined; - private _events: Map< - string | symbol, - Array<GenericFunction | WrappedFunction> - >; - - public constructor() { - this._events = new Map(); - } - - private _addListener( - eventName: string | symbol, - listener: GenericFunction | WrappedFunction, - prepend: boolean, - ): this { - this.emit("newListener", eventName, listener); - if (this._events.has(eventName)) { - const listeners = this._events.get(eventName) as Array< - GenericFunction | WrappedFunction - >; - if (prepend) { - listeners.unshift(listener); - } else { - listeners.push(listener); - } - } else { - this._events.set(eventName, [listener]); - } - const max = this.getMaxListeners(); - if (max > 0 && this.listenerCount(eventName) > max) { - const warning = new Error( - `Possible EventEmitter memory leak detected. - ${this.listenerCount(eventName)} ${eventName.toString()} listeners. - Use emitter.setMaxListeners() to increase limit`, - ); - warning.name = "MaxListenersExceededWarning"; - console.warn(warning); - } - - return this; - } - - /** Alias for emitter.on(eventName, listener). */ - public addListener( - eventName: string | symbol, - listener: GenericFunction | WrappedFunction, - ): this { - return this._addListener(eventName, listener, false); - } - - /** - * Synchronously calls each of the listeners registered for the event named - * eventName, in the order they were registered, passing the supplied - * arguments to each. - * @return true if the event had listeners, false otherwise - */ - // deno-lint-ignore no-explicit-any - public emit(eventName: string | symbol, ...args: any[]): boolean { - if (this._events.has(eventName)) { - if ( - eventName === "error" && - this._events.get(EventEmitter.errorMonitor) - ) { - this.emit(EventEmitter.errorMonitor, ...args); - } - const listeners = (this._events.get( - eventName, - ) as GenericFunction[]).slice(); // We copy with slice() so array is not mutated during emit - for (const listener of listeners) { - try { - listener.apply(this, args); - } catch (err) { - this.emit("error", err); - } - } - return true; - } else if (eventName === "error") { - if (this._events.get(EventEmitter.errorMonitor)) { - this.emit(EventEmitter.errorMonitor, ...args); - } - const errMsg = args.length > 0 ? args[0] : Error("Unhandled error."); - throw errMsg; - } - return false; - } - - /** - * Returns an array listing the events for which the emitter has - * registered listeners. - */ - public eventNames(): [string | symbol] { - return Array.from(this._events.keys()) as [string | symbol]; - } - - /** - * Returns the current max listener value for the EventEmitter which is - * either set by emitter.setMaxListeners(n) or defaults to - * EventEmitter.defaultMaxListeners. - */ - public getMaxListeners(): number { - return this.maxListeners || EventEmitter.defaultMaxListeners; - } - - /** - * Returns the number of listeners listening to the event named - * eventName. - */ - public listenerCount(eventName: string | symbol): number { - if (this._events.has(eventName)) { - return (this._events.get(eventName) as GenericFunction[]).length; - } else { - return 0; - } - } - - private _listeners( - target: EventEmitter, - eventName: string | symbol, - unwrap: boolean, - ): GenericFunction[] { - if (!target._events.has(eventName)) { - return []; - } - const eventListeners = target._events.get(eventName) as GenericFunction[]; - - return unwrap - ? this.unwrapListeners(eventListeners) - : eventListeners.slice(0); - } - - private unwrapListeners(arr: GenericFunction[]): GenericFunction[] { - const unwrappedListeners = new Array(arr.length) as GenericFunction[]; - for (let i = 0; i < arr.length; i++) { - // deno-lint-ignore no-explicit-any - unwrappedListeners[i] = (arr[i] as any)["listener"] || arr[i]; - } - return unwrappedListeners; - } - - /** Returns a copy of the array of listeners for the event named eventName.*/ - public listeners(eventName: string | symbol): GenericFunction[] { - return this._listeners(this, eventName, true); - } - - /** - * Returns a copy of the array of listeners for the event named eventName, - * including any wrappers (such as those created by .once()). - */ - public rawListeners( - eventName: string | symbol, - ): Array<GenericFunction | WrappedFunction> { - return this._listeners(this, eventName, false); - } - - /** Alias for emitter.removeListener(). */ - public off(eventName: string | symbol, listener: GenericFunction): this { - return this.removeListener(eventName, listener); - } - - /** - * Adds the listener function to the end of the listeners array for the event - * named eventName. No checks are made to see if the listener has already - * been added. Multiple calls passing the same combination of eventName and - * listener will result in the listener being added, and called, multiple - * times. - */ - public on( - eventName: string | symbol, - listener: GenericFunction | WrappedFunction, - ): this { - return this._addListener(eventName, listener, false); - } - - /** - * Adds a one-time listener function for the event named eventName. The next - * time eventName is triggered, this listener is removed and then invoked. - */ - public once(eventName: string | symbol, listener: GenericFunction): this { - const wrapped: WrappedFunction = this.onceWrap(eventName, listener); - this.on(eventName, wrapped); - return this; - } - - // Wrapped function that calls EventEmitter.removeListener(eventName, self) on execution. - private onceWrap( - eventName: string | symbol, - listener: GenericFunction, - ): WrappedFunction { - const wrapper = function ( - this: { - eventName: string | symbol; - listener: GenericFunction; - rawListener: GenericFunction | WrappedFunction; - context: EventEmitter; - }, - // deno-lint-ignore no-explicit-any - ...args: any[] - ): void { - this.context.removeListener( - this.eventName, - this.rawListener as GenericFunction, - ); - this.listener.apply(this.context, args); - }; - const wrapperContext = { - eventName: eventName, - listener: listener, - rawListener: (wrapper as unknown) as WrappedFunction, - context: this, - }; - const wrapped = (wrapper.bind( - wrapperContext, - ) as unknown) as WrappedFunction; - wrapperContext.rawListener = wrapped; - wrapped.listener = listener; - return wrapped as WrappedFunction; - } - - /** - * Adds the listener function to the beginning of the listeners array for the - * event named eventName. No checks are made to see if the listener has - * already been added. Multiple calls passing the same combination of - * eventName and listener will result in the listener being added, and - * called, multiple times. - */ - public prependListener( - eventName: string | symbol, - listener: GenericFunction | WrappedFunction, - ): this { - return this._addListener(eventName, listener, true); - } - - /** - * Adds a one-time listener function for the event named eventName to the - * beginning of the listeners array. The next time eventName is triggered, - * this listener is removed, and then invoked. - */ - public prependOnceListener( - eventName: string | symbol, - listener: GenericFunction, - ): this { - const wrapped: WrappedFunction = this.onceWrap(eventName, listener); - this.prependListener(eventName, wrapped); - return this; - } - - /** Removes all listeners, or those of the specified eventName. */ - public removeAllListeners(eventName?: string | symbol): this { - if (this._events === undefined) { - return this; - } - - if (eventName) { - if (this._events.has(eventName)) { - const listeners = (this._events.get(eventName) as Array< - GenericFunction | WrappedFunction - >).slice(); // Create a copy; We use it AFTER it's deleted. - this._events.delete(eventName); - for (const listener of listeners) { - this.emit("removeListener", eventName, listener); - } - } - } else { - const eventList: [string | symbol] = this.eventNames(); - eventList.map((value: string | symbol) => { - this.removeAllListeners(value); - }); - } - - return this; - } - - /** - * Removes the specified listener from the listener array for the event - * named eventName. - */ - public removeListener( - eventName: string | symbol, - listener: GenericFunction, - ): this { - if (this._events.has(eventName)) { - const arr: - | Array<GenericFunction | WrappedFunction> - | undefined = this._events.get(eventName); - - assert(arr); - - let listenerIndex = -1; - for (let i = arr.length - 1; i >= 0; i--) { - // arr[i]["listener"] is the reference to the listener inside a bound 'once' wrapper - if ( - arr[i] == listener || - (arr[i] && (arr[i] as WrappedFunction)["listener"] == listener) - ) { - listenerIndex = i; - break; - } - } - - if (listenerIndex >= 0) { - arr.splice(listenerIndex, 1); - this.emit("removeListener", eventName, listener); - if (arr.length === 0) { - this._events.delete(eventName); - } - } - } - return this; - } - - /** - * By default EventEmitters will print a warning if more than 10 listeners - * are added for a particular event. This is a useful default that helps - * finding memory leaks. Obviously, not all events should be limited to just - * 10 listeners. The emitter.setMaxListeners() method allows the limit to be - * modified for this specific EventEmitter instance. The value can be set to - * Infinity (or 0) to indicate an unlimited number of listeners. - */ - public setMaxListeners(n: number): this { - if (n !== Infinity) { - if (n === 0) { - n = Infinity; - } else { - validateIntegerRange(n, "maxListeners", 0); - } - } - - this.maxListeners = n; - return this; - } - - /** - * Creates a Promise that is fulfilled when the EventEmitter emits the given - * event or that is rejected when the EventEmitter emits 'error'. The Promise - * will resolve with an array of all the arguments emitted to the given event. - */ - public static once( - emitter: EventEmitter | EventTarget, - name: string, - // deno-lint-ignore no-explicit-any - ): Promise<any[]> { - return new Promise((resolve, reject) => { - if (emitter instanceof EventTarget) { - // EventTarget does not have `error` event semantics like Node - // EventEmitters, we do not listen to `error` events here. - emitter.addEventListener( - name, - (...args) => { - resolve(args); - }, - { once: true, passive: false, capture: false }, - ); - return; - } else if (emitter instanceof EventEmitter) { - // deno-lint-ignore no-explicit-any - const eventListener = (...args: any[]): void => { - if (errorListener !== undefined) { - emitter.removeListener("error", errorListener); - } - resolve(args); - }; - let errorListener: GenericFunction; - - // Adding an error listener is not optional because - // if an error is thrown on an event emitter we cannot - // guarantee that the actual event we are waiting will - // be fired. The result could be a silent way to create - // memory or file descriptor leaks, which is something - // we should avoid. - if (name !== "error") { - // deno-lint-ignore no-explicit-any - errorListener = (err: any): void => { - emitter.removeListener(name, eventListener); - reject(err); - }; - - emitter.once("error", errorListener); - } - - emitter.once(name, eventListener); - return; - } - }); - } - - /** - * Returns an AsyncIterator that iterates eventName events. It will throw if - * the EventEmitter emits 'error'. It removes all listeners when exiting the - * loop. The value returned by each iteration is an array composed of the - * emitted event arguments. - */ - public static on( - emitter: EventEmitter, - event: string | symbol, - ): AsyncIterable { - // deno-lint-ignore no-explicit-any - const unconsumedEventValues: any[] = []; - // deno-lint-ignore no-explicit-any - const unconsumedPromises: any[] = []; - let error: Error | null = null; - let finished = false; - - const iterator = { - // deno-lint-ignore no-explicit-any - next(): Promise<IteratorResult<any>> { - // First, we consume all unread events - // deno-lint-ignore no-explicit-any - const value: any = unconsumedEventValues.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<never> = 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 }); - }); - }, - - // deno-lint-ignore no-explicit-any - return(): Promise<IteratorResult<any>> { - emitter.removeListener(event, eventHandler); - emitter.removeListener("error", errorHandler); - finished = true; - - for (const promise of unconsumedPromises) { - promise.resolve(createIterResult(undefined, true)); - } - - return Promise.resolve(createIterResult(undefined, true)); - }, - - throw(err: Error): void { - error = err; - emitter.removeListener(event, eventHandler); - emitter.removeListener("error", errorHandler); - }, - - // deno-lint-ignore no-explicit-any - [Symbol.asyncIterator](): any { - return this; - }, - }; - - emitter.on(event, eventHandler); - emitter.on("error", errorHandler); - - return iterator; - - // deno-lint-ignore no-explicit-any - function eventHandler(...args: any[]): void { - const promise = unconsumedPromises.shift(); - if (promise) { - promise.resolve(createIterResult(args, false)); - } else { - unconsumedEventValues.push(args); - } - } - - // deno-lint-ignore no-explicit-any - function errorHandler(err: any): void { - finished = true; - - const toError = unconsumedPromises.shift(); - if (toError) { - toError.reject(err); - } else { - // The next time we call next() - error = err; - } - - iterator.return(); - } - } -} - -export { EventEmitter }; -export const once = EventEmitter.once; -export const on = EventEmitter.on; -export const captureRejectionSymbol = EventEmitter.captureRejectionSymbol; -export const errorMonitor = EventEmitter.errorMonitor; diff --git a/std/node/events_test.ts b/std/node/events_test.ts deleted file mode 100644 index 6942fe847..000000000 --- a/std/node/events_test.ts +++ /dev/null @@ -1,687 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertThrows, - fail, -} from "../testing/asserts.ts"; -import EventEmitter, { on, once, WrappedFunction } from "./events.ts"; - -const shouldNeverBeEmitted = () => { - fail("Should never be called"); -}; - -Deno.test({ - name: - 'When adding a new event, "eventListener" event is fired before adding the listener', - fn() { - let eventsFired: string[] = []; - const testEmitter = new EventEmitter(); - testEmitter.on("newListener", (event: string) => { - if (event !== "newListener") { - eventsFired.push("newListener"); - } - }); - testEmitter.on("event", () => { - eventsFired.push("event"); - }); - assertEquals(eventsFired, ["newListener"]); - eventsFired = []; - testEmitter.emit("event"); - assertEquals(eventsFired, ["event"]); - }, -}); - -Deno.test({ - name: - 'When removing a listenert, "removeListener" event is fired after removal', - fn() { - const eventsFired: string[] = []; - const testEmitter = new EventEmitter(); - testEmitter.on("removeListener", () => { - eventsFired.push("removeListener"); - }); - const eventFunction = function (): void { - eventsFired.push("event"); - }; - testEmitter.on("event", eventFunction); - - assertEquals(eventsFired, []); - testEmitter.removeListener("event", eventFunction); - assertEquals(eventsFired, ["removeListener"]); - }, -}); - -Deno.test({ - name: - "Default max listeners is 10, but can be changed by direct assignment only", - fn() { - assertEquals(EventEmitter.defaultMaxListeners, 10); - new EventEmitter().setMaxListeners(20); - assertEquals(EventEmitter.defaultMaxListeners, 10); - EventEmitter.defaultMaxListeners = 20; - assertEquals(EventEmitter.defaultMaxListeners, 20); - EventEmitter.defaultMaxListeners = 10; //reset back to original value - - assertThrows(() => { - new EventEmitter().setMaxListeners(-1); - }); - - const ee = new EventEmitter(); - const noop = (): void => {}; - const origWarn = console.warn; - - for (let i = 10; i--;) { - ee.on("test", noop); - } - - // there are only sync actions until it gets restored, - // so it's safe to overwrite this - console.warn = (): void => fail("Infinity listeners should be allowed"); - - ee.setMaxListeners(Infinity); - ee.on("test", noop); - - // 0 means that unlimited listeners are allowed - ee.setMaxListeners(0); - ee.on("test", noop); - - console.warn = origWarn; - }, -}); - -Deno.test({ - name: "addListener adds a listener, and listener count is correct", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - assertEquals(1, testEmitter.listenerCount("event")); - testEmitter.on("event", shouldNeverBeEmitted); - assertEquals(2, testEmitter.listenerCount("event")); - }, -}); - -Deno.test({ - name: "Emitted events are called synchronously in the order they were added", - fn() { - const testEmitter = new EventEmitter(); - const eventsFired: string[] = []; - testEmitter.on("event", (oneArg: string) => { - eventsFired.push("event(" + oneArg + ")"); - }); - testEmitter.on("event", (oneArg: string, twoArg: string) => { - eventsFired.push("event(" + oneArg + ", " + twoArg + ")"); - }); - - testEmitter.on("non-event", shouldNeverBeEmitted); - - testEmitter.on( - "event", - (oneArg: string, twoArg: string, threeArg: string) => { - eventsFired.push( - "event(" + oneArg + ", " + twoArg + ", " + threeArg + ")", - ); - }, - ); - testEmitter.emit("event", 1, 2, 3); - assertEquals(eventsFired, ["event(1)", "event(1, 2)", "event(1, 2, 3)"]); - }, -}); - -Deno.test({ - name: "Registered event names are returned as strings or Sybols", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("event", shouldNeverBeEmitted); - const sym = Symbol("symbol"); - testEmitter.on(sym, shouldNeverBeEmitted); - assertEquals(testEmitter.eventNames(), ["event", sym]); - }, -}); - -Deno.test({ - name: "You can set and get max listeners", - fn() { - const testEmitter = new EventEmitter(); - assertEquals(testEmitter.getMaxListeners(), 10); - testEmitter.setMaxListeners(20); - assertEquals(testEmitter.getMaxListeners(), 20); - }, -}); - -Deno.test({ - name: "You can retrieve registered functions for an event", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("someOtherEvent", shouldNeverBeEmitted); - testEmitter.on("event", shouldNeverBeEmitted); - const testFunction = (): void => {}; - testEmitter.on("event", testFunction); - assertEquals(testEmitter.listeners("event"), [ - shouldNeverBeEmitted, - testFunction, - ]); - }, -}); - -Deno.test({ - name: "Off is alias for removeListener", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 1); - testEmitter.off("event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 0); - }, -}); - -Deno.test({ - name: "Event registration can be chained", - fn() { - const testEmitter = new EventEmitter(); - testEmitter - .on("event", shouldNeverBeEmitted) - .on("event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 2); - }, -}); - -Deno.test({ - name: "Events can be registered to only fire once", - fn() { - let eventsFired: string[] = []; - const testEmitter = new EventEmitter(); - //prove multiple emits on same event first (when registered with 'on') - testEmitter.on("multiple event", () => { - eventsFired.push("multiple event"); - }); - testEmitter.emit("multiple event"); - testEmitter.emit("multiple event"); - assertEquals(eventsFired, ["multiple event", "multiple event"]); - - //now prove multiple events registered via 'once' only emit once - eventsFired = []; - testEmitter.once("single event", () => { - eventsFired.push("single event"); - }); - testEmitter.emit("single event"); - testEmitter.emit("single event"); - assertEquals(eventsFired, ["single event"]); - }, -}); - -Deno.test({ - name: - "You can inject a listener into the start of the stack, rather than at the end", - fn() { - const eventsFired: string[] = []; - const testEmitter = new EventEmitter(); - testEmitter.on("event", () => { - eventsFired.push("first"); - }); - testEmitter.on("event", () => { - eventsFired.push("second"); - }); - testEmitter.prependListener("event", () => { - eventsFired.push("third"); - }); - testEmitter.emit("event"); - assertEquals(eventsFired, ["third", "first", "second"]); - }, -}); - -Deno.test({ - name: 'You can prepend a "once" listener', - fn() { - const eventsFired: string[] = []; - const testEmitter = new EventEmitter(); - testEmitter.on("event", () => { - eventsFired.push("first"); - }); - testEmitter.on("event", () => { - eventsFired.push("second"); - }); - testEmitter.prependOnceListener("event", () => { - eventsFired.push("third"); - }); - testEmitter.emit("event"); - testEmitter.emit("event"); - assertEquals(eventsFired, ["third", "first", "second", "first", "second"]); - }, -}); - -Deno.test({ - name: "Remove all listeners, which can also be chained", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("other event", shouldNeverBeEmitted); - testEmitter.on("other event", shouldNeverBeEmitted); - testEmitter.once("other event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 2); - assertEquals(testEmitter.listenerCount("other event"), 3); - - testEmitter.removeAllListeners("event").removeAllListeners("other event"); - - assertEquals(testEmitter.listenerCount("event"), 0); - assertEquals(testEmitter.listenerCount("other event"), 0); - }, -}); - -Deno.test({ - name: "Provide a non-existent event to removeAllListeners will do nothing", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("other event", shouldNeverBeEmitted); - testEmitter.on("other event", shouldNeverBeEmitted); - testEmitter.once("other event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 2); - assertEquals(testEmitter.listenerCount("other event"), 3); - - testEmitter.removeAllListeners("non-existent"); - - assertEquals(testEmitter.listenerCount("event"), 2); - assertEquals(testEmitter.listenerCount("other event"), 3); - }, -}); - -Deno.test({ - name: "Remove individual listeners, which can also be chained", - fn() { - const testEmitter = new EventEmitter(); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.on("event", shouldNeverBeEmitted); - testEmitter.once("other event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 2); - assertEquals(testEmitter.listenerCount("other event"), 1); - - testEmitter.removeListener("other event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 2); - assertEquals(testEmitter.listenerCount("other event"), 0); - - testEmitter - .removeListener("event", shouldNeverBeEmitted) - .removeListener("event", shouldNeverBeEmitted); - - assertEquals(testEmitter.listenerCount("event"), 0); - assertEquals(testEmitter.listenerCount("other event"), 0); - }, -}); - -Deno.test({ - name: "It is OK to try to remove non-existent listener", - fn() { - const testEmitter = new EventEmitter(); - - const madeUpEvent = (): void => { - fail("Should never be called"); - }; - - testEmitter.on("event", shouldNeverBeEmitted); - assertEquals(testEmitter.listenerCount("event"), 1); - - testEmitter.removeListener("event", madeUpEvent); - testEmitter.removeListener("non-existent event", madeUpEvent); - - assertEquals(testEmitter.listenerCount("event"), 1); - }, -}); - -Deno.test({ - name: "all listeners complete execution even if removed before execution", - fn() { - const testEmitter = new EventEmitter(); - let eventsProcessed: string[] = []; - const listenerB = (): number => eventsProcessed.push("B"); - const listenerA = (): void => { - eventsProcessed.push("A"); - testEmitter.removeListener("event", listenerB); - }; - - testEmitter.on("event", listenerA); - testEmitter.on("event", listenerB); - - testEmitter.emit("event"); - assertEquals(eventsProcessed, ["A", "B"]); - - eventsProcessed = []; - testEmitter.emit("event"); - assertEquals(eventsProcessed, ["A"]); - }, -}); - -Deno.test({ - name: 'Raw listener will return event listener or wrapped "once" function', - fn() { - const testEmitter = new EventEmitter(); - const eventsProcessed: string[] = []; - const listenerA = (): number => eventsProcessed.push("A"); - const listenerB = (): number => eventsProcessed.push("B"); - testEmitter.on("event", listenerA); - testEmitter.once("once-event", listenerB); - - const rawListenersForEvent = testEmitter.rawListeners("event"); - const rawListenersForOnceEvent = testEmitter.rawListeners("once-event"); - - assertEquals(rawListenersForEvent.length, 1); - assertEquals(rawListenersForOnceEvent.length, 1); - assertEquals(rawListenersForEvent[0], listenerA); - assertEquals( - (rawListenersForOnceEvent[0] as WrappedFunction).listener, - listenerB, - ); - }, -}); - -Deno.test({ - name: - "Once wrapped raw listeners may be executed multiple times, until the wrapper is executed", - fn() { - const testEmitter = new EventEmitter(); - let eventsProcessed: string[] = []; - const listenerA = (): number => eventsProcessed.push("A"); - testEmitter.once("once-event", listenerA); - - const rawListenersForOnceEvent = testEmitter.rawListeners("once-event"); - const wrappedFn: WrappedFunction = - rawListenersForOnceEvent[0] as WrappedFunction; - wrappedFn.listener(); - wrappedFn.listener(); - wrappedFn.listener(); - assertEquals(eventsProcessed, ["A", "A", "A"]); - - eventsProcessed = []; - wrappedFn(); // executing the wrapped listener function will remove it from the event - assertEquals(eventsProcessed, ["A"]); - assertEquals(testEmitter.listeners("once-event").length, 0); - }, -}); - -Deno.test({ - name: "Can add once event listener to EventEmitter via standalone function", - async fn() { - const ee = new EventEmitter(); - setTimeout(() => { - ee.emit("event", 42, "foo"); - }, 0); - // deno-lint-ignore no-explicit-any - const valueArr: any[] = await once(ee, "event"); - assertEquals(valueArr, [42, "foo"]); - }, -}); - -Deno.test({ - name: "Can add once event listener to EventTarget via standalone function", - async fn() { - const et: EventTarget = new EventTarget(); - setTimeout(() => { - const event: Event = new Event("event", { composed: true }); - et.dispatchEvent(event); - }, 0); - // deno-lint-ignore no-explicit-any - const eventObj: any[] = await once(et, "event"); - assert(!eventObj[0].isTrusted); - }, -}); - -Deno.test({ - name: "Only valid integers are allowed for max listeners", - fn() { - const ee = new EventEmitter(); - ee.setMaxListeners(0); - assertThrows( - () => { - ee.setMaxListeners(-1); - }, - Error, - "must be >= 0", - ); - assertThrows( - () => { - ee.setMaxListeners(3.45); - }, - Error, - "must be 'an integer'", - ); - }, -}); - -Deno.test({ - name: "ErrorMonitor can spy on error events without consuming them", - fn() { - const ee = new EventEmitter(); - let events: string[] = []; - //unhandled error scenario should throw - assertThrows( - () => { - ee.emit("error"); - }, - Error, - "Unhandled error", - ); - - ee.on(EventEmitter.errorMonitor, () => { - events.push("errorMonitor event"); - }); - - //error is still unhandled but also intercepted by error monitor - assertThrows( - () => { - ee.emit("error"); - }, - Error, - "Unhandled error", - ); - assertEquals(events, ["errorMonitor event"]); - - //A registered error handler won't throw, but still be monitored - events = []; - ee.on("error", () => { - events.push("error"); - }); - ee.emit("error"); - assertEquals(events, ["errorMonitor event", "error"]); - }, -}); - -Deno.test({ - name: "asynchronous iteration of events are handled as expected", - async fn() { - const ee = new EventEmitter(); - setTimeout(() => { - ee.emit("foo", "bar"); - ee.emit("bar", 24); - ee.emit("foo", 42); - }, 0); - - const iterable = on(ee, "foo"); - - const expected = [["bar"], [42]]; - - for await (const event of iterable) { - const current = expected.shift(); - - assertEquals(current, event); - - if (expected.length === 0) { - break; - } - } - assertEquals(ee.listenerCount("foo"), 0); - assertEquals(ee.listenerCount("error"), 0); - }, -}); - -Deno.test({ - name: "asynchronous error handling of emitted events works as expected", - async fn() { - const ee = new EventEmitter(); - const _err = new Error("kaboom"); - setTimeout(() => { - ee.emit("error", _err); - }, 0); - - const iterable = on(ee, "foo"); - let thrown = false; - - try { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const event of iterable) { - fail("no events should be processed due to the error thrown"); - } - } catch (err) { - thrown = true; - assertEquals(err, _err); - } - assertEquals(thrown, true); - }, -}); - -Deno.test({ - name: "error thrown during asynchronous processing of events is handled", - async fn() { - const ee = new EventEmitter(); - const _err = new Error("kaboom"); - setTimeout(() => { - ee.emit("foo", 42); - ee.emit("error", _err); - }, 0); - - const iterable = on(ee, "foo"); - const expected = [[42]]; - let thrown = false; - - try { - for await (const event of iterable) { - const current = expected.shift(); - assertEquals(current, event); - } - } catch (err) { - thrown = true; - assertEquals(err, _err); - } - assertEquals(thrown, true); - assertEquals(ee.listenerCount("foo"), 0); - assertEquals(ee.listenerCount("error"), 0); - }, -}); - -Deno.test({ - name: - "error thrown in processing loop of asynchronous event prevents processing of additional events", - async fn() { - const ee = new EventEmitter(); - const _err = new Error("kaboom"); - - setTimeout(() => { - ee.emit("foo", 42); - ee.emit("foo", 999); - }, 0); - - try { - for await (const event of on(ee, "foo")) { - assertEquals(event, [42]); - throw _err; - } - } catch (err) { - assertEquals(err, _err); - } - - assertEquals(ee.listenerCount("foo"), 0); - assertEquals(ee.listenerCount("error"), 0); - }, -}); - -Deno.test({ - name: "asynchronous iterator next() works as expected", - async fn() { - const ee = new EventEmitter(); - const iterable = on(ee, "foo"); - - setTimeout(function () { - ee.emit("foo", "bar"); - ee.emit("foo", 42); - iterable.return(); - }, 0); - - const results = await Promise.all([ - iterable.next(), - iterable.next(), - iterable.next(), - ]); - - assertEquals(results, [ - { - value: ["bar"], - done: false, - }, - { - value: [42], - done: false, - }, - { - value: undefined, - done: true, - }, - ]); - - assertEquals(await iterable.next(), { - value: undefined, - done: true, - }); - }, -}); - -Deno.test({ - name: "async iterable throw handles various scenarios", - async fn() { - const ee = new EventEmitter(); - const iterable = on(ee, "foo"); - - setTimeout(() => { - ee.emit("foo", "bar"); - ee.emit("foo", 42); // lost in the queue - iterable.throw(_err); - }, 0); - - const _err = new Error("kaboom"); - let thrown = false; - - const expected = [["bar"], [42]]; - - try { - for await (const event of iterable) { - assertEquals(event, expected.shift()); - } - } catch (err) { - thrown = true; - assertEquals(err, _err); - } - assertEquals(thrown, true); - assertEquals(expected.length, 0); - assertEquals(ee.listenerCount("foo"), 0); - assertEquals(ee.listenerCount("error"), 0); - }, -}); - -// Event emitter's `on` previously referenced addListener internally, so overriding addListener -// would cause a deadlock -// This is a regression test -Deno.test("Elements that extend EventEmitter listener alias don't end up in a deadlock", () => { - class X extends EventEmitter { - addListener(eventName: string, listener: () => void) { - return super.on(eventName, listener); - } - } - - const x = new X(); - try { - x.on("x", () => {}); - } catch (e) { - fail(); - } -}); diff --git a/std/node/fs.ts b/std/node/fs.ts deleted file mode 100644 index f62f93168..000000000 --- a/std/node/fs.ts +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { access, accessSync } from "./_fs/_fs_access.ts"; -import { appendFile, appendFileSync } from "./_fs/_fs_appendFile.ts"; -import { chmod, chmodSync } from "./_fs/_fs_chmod.ts"; -import { chown, chownSync } from "./_fs/_fs_chown.ts"; -import { close, closeSync } from "./_fs/_fs_close.ts"; -import * as constants from "./_fs/_fs_constants.ts"; -import { readFile, readFileSync } from "./_fs/_fs_readFile.ts"; -import { readlink, readlinkSync } from "./_fs/_fs_readlink.ts"; -import { exists, existsSync } from "./_fs/_fs_exists.ts"; -import { mkdir, mkdirSync } from "./_fs/_fs_mkdir.ts"; -import { mkdtemp, mkdtempSync } from "./_fs/_fs_mkdtemp.ts"; -import { copyFile, copyFileSync } from "./_fs/_fs_copy.ts"; -import { writeFile, writeFileSync } from "./_fs/_fs_writeFile.ts"; -import { readdir, readdirSync } from "./_fs/_fs_readdir.ts"; -import { realpath, realpathSync } from "./_fs/_fs_realpath.ts"; -import { rename, renameSync } from "./_fs/_fs_rename.ts"; -import { rmdir, rmdirSync } from "./_fs/_fs_rmdir.ts"; -import { unlink, unlinkSync } from "./_fs/_fs_unlink.ts"; -import { watch } from "./_fs/_fs_watch.ts"; -import { open, openSync } from "./_fs/_fs_open.ts"; -import { stat, statSync } from "./_fs/_fs_stat.ts"; -import { lstat, lstatSync } from "./_fs/_fs_lstat.ts"; - -import * as promises from "./_fs/promises/mod.ts"; - -export default { - access, - accessSync, - appendFile, - appendFileSync, - chmod, - chmodSync, - chown, - chownSync, - close, - closeSync, - constants, - copyFile, - copyFileSync, - exists, - existsSync, - lstat, - lstatSync, - mkdir, - mkdirSync, - mkdtemp, - mkdtempSync, - open, - openSync, - promises, - readdir, - readdirSync, - readFile, - readFileSync, - readlink, - readlinkSync, - realpath, - realpathSync, - rename, - renameSync, - rmdir, - rmdirSync, - stat, - statSync, - unlink, - unlinkSync, - watch, - writeFile, - writeFileSync, -}; - -export { - access, - accessSync, - appendFile, - appendFileSync, - chmod, - chmodSync, - chown, - chownSync, - close, - closeSync, - constants, - copyFile, - copyFileSync, - exists, - existsSync, - lstat, - lstatSync, - mkdir, - mkdirSync, - mkdtemp, - mkdtempSync, - open, - openSync, - promises, - readdir, - readdirSync, - readFile, - readFileSync, - readlink, - readlinkSync, - realpath, - realpathSync, - rename, - renameSync, - rmdir, - rmdirSync, - stat, - statSync, - unlink, - unlinkSync, - watch, - writeFile, - writeFileSync, -}; diff --git a/std/node/global.d.ts b/std/node/global.d.ts deleted file mode 100644 index 94baf03b7..000000000 --- a/std/node/global.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import processModule from "./process.ts"; -import { Buffer as bufferModule } from "./buffer.ts"; -import timers from "./timers.ts"; - -// d.ts files allow us to declare Buffer as a value and as a type -// type something = Buffer | something_else; is quite common - -type GlobalType = { - process: typeof processModule; - Buffer: typeof bufferModule; - setImmediate: typeof timers.setImmediate; - clearImmediate: typeof timers.clearImmediate; -}; - -declare global { - interface Window { - global: GlobalType; - } - - interface globalThis { - global: GlobalType; - } - - var global: GlobalType; - var process: typeof processModule; - var Buffer: typeof bufferModule; - type Buffer = bufferModule; - var setImmediate: typeof timers.setImmediate; - var clearImmediate: typeof timers.clearImmediate; -} - -export {}; diff --git a/std/node/global.ts b/std/node/global.ts deleted file mode 100644 index 550f6ddf9..000000000 --- a/std/node/global.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -/// <reference path="./global.d.ts" /> -import processModule from "./process.ts"; -import { Buffer as bufferModule } from "./buffer.ts"; -import timers from "./timers.ts"; - -Object.defineProperty(globalThis, "global", { - value: globalThis, - writable: false, - enumerable: false, - configurable: true, -}); - -Object.defineProperty(globalThis, "process", { - value: processModule, - enumerable: false, - writable: true, - configurable: true, -}); - -Object.defineProperty(globalThis, "Buffer", { - value: bufferModule, - enumerable: false, - writable: true, - configurable: true, -}); - -Object.defineProperty(globalThis, "setImmediate", { - value: timers.setImmediate, - enumerable: true, - writable: true, - configurable: true, -}); - -Object.defineProperty(globalThis, "clearImmediate", { - value: timers.clearImmediate, - enumerable: true, - writable: true, - configurable: true, -}); - -export {}; diff --git a/std/node/global_test.ts b/std/node/global_test.ts deleted file mode 100644 index 2ff768f88..000000000 --- a/std/node/global_test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import "./global.ts"; -import { assert, assertStrictEquals } from "../testing/asserts.ts"; -import { Buffer as BufferModule } from "./buffer.ts"; -import processModule from "./process.ts"; -import timers from "./timers.ts"; - -// Definitions for this are quite delicate -// This ensures modifications to the global namespace don't break on TypeScript - -// TODO(bartlomieju): -// Deno lint marks globals defined by this module as undefined -// probably gonna change in the future - -Deno.test("global is correctly defined", () => { - // deno-lint-ignore no-undef - assertStrictEquals(global, globalThis); - // deno-lint-ignore no-undef - assertStrictEquals(global.Buffer, BufferModule); - // deno-lint-ignore no-undef - assertStrictEquals(global.process, process); -}); - -Deno.test("Buffer is correctly defined", () => { - //Check that Buffer is defined as a type as well - type x = Buffer; - // deno-lint-ignore no-undef - assertStrictEquals(Buffer, BufferModule); - // deno-lint-ignore no-undef - assert(Buffer.from); - // deno-lint-ignore no-undef - assertStrictEquals(global.Buffer, BufferModule); - // deno-lint-ignore no-undef - assert(global.Buffer.from); - assertStrictEquals(globalThis.Buffer, BufferModule); - assert(globalThis.Buffer.from); - assertStrictEquals(window.Buffer, BufferModule); - assert(window.Buffer.from); -}); - -Deno.test("process is correctly defined", () => { - // deno-lint-ignore no-undef - assertStrictEquals(process, processModule); - // deno-lint-ignore no-undef - assert(process.arch); - // deno-lint-ignore no-undef - assertStrictEquals(global.process, processModule); - // deno-lint-ignore no-undef - assert(global.process.arch); - assertStrictEquals(globalThis.process, processModule); - assert(globalThis.process.arch); - assertStrictEquals(window.process, processModule); - assert(window.process.arch); -}); - -Deno.test("setImmediate is correctly defined", () => { - // deno-lint-ignore no-undef - assertStrictEquals(setImmediate, timers.setImmediate); - // deno-lint-ignore no-undef - assertStrictEquals(global.setImmediate, timers.setImmediate); - assertStrictEquals(globalThis.setImmediate, timers.setImmediate); - assertStrictEquals(window.setImmediate, timers.setImmediate); -}); - -Deno.test("clearImmediate is correctly defined", () => { - // deno-lint-ignore no-undef - assertStrictEquals(clearImmediate, timers.clearImmediate); - // deno-lint-ignore no-undef - assertStrictEquals(global.clearImmediate, timers.clearImmediate); - assertStrictEquals(globalThis.clearImmediate, timers.clearImmediate); - assertStrictEquals(window.clearImmediate, timers.clearImmediate); -}); diff --git a/std/node/module.ts b/std/node/module.ts deleted file mode 100644 index 0d6ef9133..000000000 --- a/std/node/module.ts +++ /dev/null @@ -1,1163 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -import "./global.ts"; - -import * as nodeBuffer from "./buffer.ts"; -import * as nodeEvents from "./events.ts"; -import * as nodeFS from "./fs.ts"; -import * as nodeOs from "./os.ts"; -import * as nodePath from "./path.ts"; -import * as nodeQueryString from "./querystring.ts"; -import * as nodeStream from "./stream.ts"; -import * as nodeStringDecoder from "./string_decoder.ts"; -import * as nodeTimers from "./timers.ts"; -import * as nodeUtil from "./util.ts"; - -import * as path from "../path/mod.ts"; -import { assert } from "../_util/assert.ts"; -import { fileURLToPath, pathToFileURL } from "./url.ts"; -import { isWindows } from "../_util/os.ts"; - -const CHAR_FORWARD_SLASH = "/".charCodeAt(0); -const CHAR_BACKWARD_SLASH = "\\".charCodeAt(0); -const CHAR_COLON = ":".charCodeAt(0); - -const relativeResolveCache = Object.create(null); - -let requireDepth = 0; -let statCache: Map<string, StatResult> | null = null; - -type StatResult = -1 | 0 | 1; -// Returns 0 if the path refers to -// a file, 1 when it's a directory or < 0 on error. -function stat(filename: string): StatResult { - filename = path.toNamespacedPath(filename); - if (statCache !== null) { - const result = statCache.get(filename); - if (result !== undefined) return result; - } - try { - const info = Deno.statSync(filename); - const result = info.isFile ? 0 : 1; - if (statCache !== null) statCache.set(filename, result); - return result; - } catch (e) { - if (e instanceof Deno.errors.PermissionDenied) { - throw new Error("CJS loader requires --allow-read."); - } - return -1; - } -} - -function updateChildren( - parent: Module | null, - child: Module, - scan: boolean, -): void { - const children = parent && parent.children; - if (children && !(scan && children.includes(child))) { - children.push(child); - } -} - -class Module { - id: string; - // deno-lint-ignore no-explicit-any - exports: any; - parent: Module | null; - filename: string | null; - loaded: boolean; - children: Module[]; - paths: string[]; - path: string; - constructor(id = "", parent?: Module | null) { - this.id = id; - this.exports = {}; - this.parent = parent || null; - updateChildren(parent || null, this, false); - this.filename = null; - this.loaded = false; - this.children = []; - this.paths = []; - this.path = path.dirname(id); - } - static builtinModules: string[] = []; - static _extensions: { - // deno-lint-ignore no-explicit-any - [key: string]: (module: Module, filename: string) => any; - } = Object.create(null); - static _cache: { [key: string]: Module } = Object.create(null); - static _pathCache = Object.create(null); - static globalPaths: string[] = []; - // Proxy related code removed. - static wrapper = [ - "(function (exports, require, module, __filename, __dirname) { ", - "\n});", - ]; - - // Loads a module at the given file path. Returns that module's - // `exports` property. - // deno-lint-ignore no-explicit-any - require(id: string): any { - if (id === "") { - throw new Error(`id '${id}' must be a non-empty string`); - } - requireDepth++; - try { - return Module._load(id, this, /* isMain */ false); - } finally { - requireDepth--; - } - } - - // Given a file name, pass it to the proper extension handler. - load(filename: string): void { - assert(!this.loaded); - this.filename = filename; - this.paths = Module._nodeModulePaths(path.dirname(filename)); - - const extension = findLongestRegisteredExtension(filename); - // Removed ESM code - Module._extensions[extension](this, filename); - this.loaded = true; - // Removed ESM code - } - - // Run the file contents in the correct scope or sandbox. Expose - // the correct helper variables (require, module, exports) to - // the file. - // Returns exception, if any. - // deno-lint-ignore no-explicit-any - _compile(content: string, filename: string): any { - // manifest code removed - const compiledWrapper = wrapSafe(filename, content); - // inspector code remove - const dirname = path.dirname(filename); - const require = makeRequireFunction(this); - const exports = this.exports; - const thisValue = exports; - if (requireDepth === 0) { - statCache = new Map(); - } - const result = compiledWrapper.call( - thisValue, - exports, - require, - this, - filename, - dirname, - ); - if (requireDepth === 0) { - statCache = null; - } - return result; - } - - /* - * Check for node modules paths. - * */ - static _resolveLookupPaths( - request: string, - parent: Module | null, - ): string[] | null { - if ( - request.charAt(0) !== "." || - (request.length > 1 && - request.charAt(1) !== "." && - request.charAt(1) !== "/" && - (!isWindows || request.charAt(1) !== "\\")) - ) { - let paths = modulePaths; - if (parent !== null && parent.paths && parent.paths.length) { - paths = parent.paths.concat(paths); - } - - return paths.length > 0 ? paths : null; - } - - // With --eval, parent.id is not set and parent.filename is null. - if (!parent || !parent.id || !parent.filename) { - // Make require('./path/to/foo') work - normally the path is taken - // from realpath(__filename) but with eval there is no filename - return ["."].concat(Module._nodeModulePaths("."), modulePaths); - } - // Returns the parent path of the file - return [path.dirname(parent.filename)]; - } - - static _resolveFilename( - request: string, - parent: Module, - isMain: boolean, - options?: { paths: string[] }, - ): string { - // Polyfills. - if (nativeModuleCanBeRequiredByUsers(request)) { - return request; - } - - let paths: string[]; - - if (typeof options === "object" && options !== null) { - if (Array.isArray(options.paths)) { - const isRelative = request.startsWith("./") || - request.startsWith("../") || - (isWindows && request.startsWith(".\\")) || - request.startsWith("..\\"); - - if (isRelative) { - paths = options.paths; - } else { - const fakeParent = new Module("", null); - - paths = []; - - for (let i = 0; i < options.paths.length; i++) { - const path = options.paths[i]; - fakeParent.paths = Module._nodeModulePaths(path); - const lookupPaths = Module._resolveLookupPaths(request, fakeParent); - - for (let j = 0; j < lookupPaths!.length; j++) { - if (!paths.includes(lookupPaths![j])) { - paths.push(lookupPaths![j]); - } - } - } - } - } else if (options.paths === undefined) { - paths = Module._resolveLookupPaths(request, parent)!; - } else { - throw new Error("options.paths is invalid"); - } - } else { - paths = Module._resolveLookupPaths(request, parent)!; - } - - // Look up the filename first, since that's the cache key. - const filename = Module._findPath(request, paths, isMain); - if (!filename) { - const requireStack = []; - for (let cursor: Module | null = parent; cursor; cursor = cursor.parent) { - requireStack.push(cursor.filename || cursor.id); - } - let message = `Cannot find module '${request}'`; - if (requireStack.length > 0) { - message = message + "\nRequire stack:\n- " + requireStack.join("\n- "); - } - const err = new Error(message) as Error & { - code: string; - requireStack: string[]; - }; - err.code = "MODULE_NOT_FOUND"; - err.requireStack = requireStack; - throw err; - } - return filename as string; - } - - static _findPath( - request: string, - paths: string[], - isMain: boolean, - ): string | boolean { - const absoluteRequest = path.isAbsolute(request); - if (absoluteRequest) { - paths = [""]; - } else if (!paths || paths.length === 0) { - return false; - } - - const cacheKey = request + "\x00" + - (paths.length === 1 ? paths[0] : paths.join("\x00")); - const entry = Module._pathCache[cacheKey]; - if (entry) { - return entry; - } - - let exts; - let trailingSlash = request.length > 0 && - request.charCodeAt(request.length - 1) === CHAR_FORWARD_SLASH; - if (!trailingSlash) { - trailingSlash = /(?:^|\/)\.?\.$/.test(request); - } - - // For each path - for (let i = 0; i < paths.length; i++) { - // Don't search further if path doesn't exist - const curPath = paths[i]; - - if (curPath && stat(curPath) < 1) continue; - const basePath = resolveExports(curPath, request, absoluteRequest); - let filename; - - const rc = stat(basePath); - if (!trailingSlash) { - if (rc === 0) { - // File. - // preserveSymlinks removed - filename = toRealPath(basePath); - } - - if (!filename) { - // Try it with each of the extensions - if (exts === undefined) exts = Object.keys(Module._extensions); - filename = tryExtensions(basePath, exts, isMain); - } - } - - if (!filename && rc === 1) { - // Directory. - // try it with each of the extensions at "index" - if (exts === undefined) exts = Object.keys(Module._extensions); - filename = tryPackage(basePath, exts, isMain, request); - } - - if (filename) { - Module._pathCache[cacheKey] = filename; - return filename; - } - } - // trySelf removed. - - return false; - } - - // Check the cache for the requested file. - // 1. If a module already exists in the cache: return its exports object. - // 2. If the module is native: call - // `NativeModule.prototype.compileForPublicLoader()` and return the exports. - // 3. Otherwise, create a new module for the file and save it to the cache. - // Then have it load the file contents before returning its exports - // object. - // deno-lint-ignore no-explicit-any - static _load(request: string, parent: Module, isMain: boolean): any { - let relResolveCacheIdentifier: string | undefined; - if (parent) { - // Fast path for (lazy loaded) modules in the same directory. The indirect - // caching is required to allow cache invalidation without changing the old - // cache key names. - relResolveCacheIdentifier = `${parent.path}\x00${request}`; - const filename = relativeResolveCache[relResolveCacheIdentifier]; - if (filename !== undefined) { - const cachedModule = Module._cache[filename]; - if (cachedModule !== undefined) { - updateChildren(parent, cachedModule, true); - if (!cachedModule.loaded) { - return getExportsForCircularRequire(cachedModule); - } - return cachedModule.exports; - } - delete relativeResolveCache[relResolveCacheIdentifier]; - } - } - - const filename = Module._resolveFilename(request, parent, isMain); - - const cachedModule = Module._cache[filename]; - if (cachedModule !== undefined) { - updateChildren(parent, cachedModule, true); - if (!cachedModule.loaded) { - return getExportsForCircularRequire(cachedModule); - } - return cachedModule.exports; - } - - // Native module polyfills - const mod = loadNativeModule(filename, request); - if (mod) return mod.exports; - - // Don't call updateChildren(), Module constructor already does. - const module = new Module(filename, parent); - - if (isMain) { - // TODO(bartlomieju): set process info - // process.mainModule = module; - module.id = "."; - } - - Module._cache[filename] = module; - if (parent !== undefined) { - assert(relResolveCacheIdentifier); - relativeResolveCache[relResolveCacheIdentifier] = filename; - } - - let threw = true; - try { - // Source map code removed - module.load(filename); - threw = false; - } finally { - if (threw) { - delete Module._cache[filename]; - if (parent !== undefined) { - assert(relResolveCacheIdentifier); - delete relativeResolveCache[relResolveCacheIdentifier]; - } - } else if ( - module.exports && - Object.getPrototypeOf(module.exports) === - CircularRequirePrototypeWarningProxy - ) { - Object.setPrototypeOf(module.exports, PublicObjectPrototype); - } - } - - return module.exports; - } - - static wrap(script: string): string { - return `${Module.wrapper[0]}${script}${Module.wrapper[1]}`; - } - - static _nodeModulePaths(from: string): string[] { - if (isWindows) { - // Guarantee that 'from' is absolute. - from = path.resolve(from); - - // note: this approach *only* works when the path is guaranteed - // to be absolute. Doing a fully-edge-case-correct path.split - // that works on both Windows and Posix is non-trivial. - - // return root node_modules when path is 'D:\\'. - // path.resolve will make sure from.length >=3 in Windows. - if ( - from.charCodeAt(from.length - 1) === CHAR_BACKWARD_SLASH && - from.charCodeAt(from.length - 2) === CHAR_COLON - ) { - return [from + "node_modules"]; - } - - const paths = []; - for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) { - const code = from.charCodeAt(i); - // The path segment separator check ('\' and '/') was used to get - // node_modules path for every path segment. - // Use colon as an extra condition since we can get node_modules - // path for drive root like 'C:\node_modules' and don't need to - // parse drive name. - if ( - code === CHAR_BACKWARD_SLASH || - code === CHAR_FORWARD_SLASH || - code === CHAR_COLON - ) { - if (p !== nmLen) paths.push(from.slice(0, last) + "\\node_modules"); - last = i; - p = 0; - } else if (p !== -1) { - if (nmChars[p] === code) { - ++p; - } else { - p = -1; - } - } - } - - return paths; - } else { - // posix - // Guarantee that 'from' is absolute. - from = path.resolve(from); - // Return early not only to avoid unnecessary work, but to *avoid* returning - // an array of two items for a root: [ '//node_modules', '/node_modules' ] - if (from === "/") return ["/node_modules"]; - - // note: this approach *only* works when the path is guaranteed - // to be absolute. Doing a fully-edge-case-correct path.split - // that works on both Windows and Posix is non-trivial. - const paths = []; - for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) { - const code = from.charCodeAt(i); - if (code === CHAR_FORWARD_SLASH) { - if (p !== nmLen) paths.push(from.slice(0, last) + "/node_modules"); - last = i; - p = 0; - } else if (p !== -1) { - if (nmChars[p] === code) { - ++p; - } else { - p = -1; - } - } - } - - // Append /node_modules to handle root paths. - paths.push("/node_modules"); - - return paths; - } - } - - /** - * Create a `require` function that can be used to import CJS modules. - * Follows CommonJS resolution similar to that of Node.js, - * with `node_modules` lookup and `index.js` lookup support. - * Also injects available Node.js builtin module polyfills. - * - * const require = createRequire(import.meta.url); - * const fs = require("fs"); - * const leftPad = require("left-pad"); - * const cjsModule = require("./cjs_mod"); - * - * @param filename path or URL to current module - * @return Require function to import CJS modules - */ - static createRequire(filename: string | URL): RequireFunction { - let filepath: string; - if ( - filename instanceof URL || - (typeof filename === "string" && !path.isAbsolute(filename)) - ) { - filepath = fileURLToPath(filename); - } else if (typeof filename !== "string") { - throw new Error("filename should be a string"); - } else { - filepath = filename; - } - return createRequireFromPath(filepath); - } - - static _initPaths(): void { - const homeDir = Deno.env.get("HOME"); - const nodePath = Deno.env.get("NODE_PATH"); - - // Removed $PREFIX/bin/node case - - let paths = []; - - if (homeDir) { - paths.unshift(path.resolve(homeDir, ".node_libraries")); - paths.unshift(path.resolve(homeDir, ".node_modules")); - } - - if (nodePath) { - paths = nodePath - .split(path.delimiter) - .filter(function pathsFilterCB(path) { - return !!path; - }) - .concat(paths); - } - - modulePaths = paths; - - // Clone as a shallow copy, for introspection. - Module.globalPaths = modulePaths.slice(0); - } - - static _preloadModules(requests: string[]): void { - if (!Array.isArray(requests)) { - return; - } - - // Preloaded modules have a dummy parent module which is deemed to exist - // in the current working directory. This seeds the search path for - // preloaded modules. - const parent = new Module("internal/preload", null); - try { - parent.paths = Module._nodeModulePaths(Deno.cwd()); - } catch (e) { - if (e.code !== "ENOENT") { - throw e; - } - } - for (let n = 0; n < requests.length; n++) { - parent.require(requests[n]); - } - } -} - -// Polyfills. -const nativeModulePolyfill = new Map<string, Module>(); -// deno-lint-ignore no-explicit-any -function createNativeModule(id: string, exports: any): Module { - const mod = new Module(id); - mod.exports = exports; - mod.loaded = true; - return mod; -} - -nativeModulePolyfill.set("buffer", createNativeModule("buffer", nodeBuffer)); -nativeModulePolyfill.set("events", createNativeModule("events", nodeEvents)); -nativeModulePolyfill.set("fs", createNativeModule("fs", nodeFS)); -nativeModulePolyfill.set("os", createNativeModule("os", nodeOs)); -nativeModulePolyfill.set("path", createNativeModule("path", nodePath)); -nativeModulePolyfill.set( - "querystring", - createNativeModule("querystring", nodeQueryString), -); -nativeModulePolyfill.set( - "stream", - createNativeModule("string_decoder", nodeStream), -); -nativeModulePolyfill.set( - "string_decoder", - createNativeModule("string_decoder", nodeStringDecoder), -); -nativeModulePolyfill.set("timers", createNativeModule("timers", nodeTimers)); -nativeModulePolyfill.set("util", createNativeModule("util", nodeUtil)); - -function loadNativeModule( - _filename: string, - request: string, -): Module | undefined { - return nativeModulePolyfill.get(request); -} -function nativeModuleCanBeRequiredByUsers(request: string): boolean { - return nativeModulePolyfill.has(request); -} -// Populate with polyfill names -for (const id of nativeModulePolyfill.keys()) { - Module.builtinModules.push(id); -} - -let modulePaths: string[] = []; - -// Given a module name, and a list of paths to test, returns the first -// matching file in the following precedence. -// -// require("a.<ext>") -// -> a.<ext> -// -// require("a") -// -> a -// -> a.<ext> -// -> a/index.<ext> - -const packageJsonCache = new Map<string, PackageInfo | null>(); - -interface PackageInfo { - name?: string; - main?: string; - // deno-lint-ignore no-explicit-any - exports?: any; - // deno-lint-ignore no-explicit-any - type?: any; -} - -function readPackage(requestPath: string): PackageInfo | null { - const jsonPath = path.resolve(requestPath, "package.json"); - - const existing = packageJsonCache.get(jsonPath); - if (existing !== undefined) { - return existing; - } - - let json: string | undefined; - try { - json = new TextDecoder().decode( - Deno.readFileSync(path.toNamespacedPath(jsonPath)), - ); - } catch { - // pass - } - - if (json === undefined) { - packageJsonCache.set(jsonPath, null); - return null; - } - - try { - const parsed = JSON.parse(json); - const filtered = { - name: parsed.name, - main: parsed.main, - exports: parsed.exports, - type: parsed.type, - }; - packageJsonCache.set(jsonPath, filtered); - return filtered; - } catch (e) { - e.path = jsonPath; - e.message = "Error parsing " + jsonPath + ": " + e.message; - throw e; - } -} - -function readPackageScope( - checkPath: string, -): { path: string; data: PackageInfo } | false { - const rootSeparatorIndex = checkPath.indexOf(path.sep); - let separatorIndex; - while ( - (separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex - ) { - checkPath = checkPath.slice(0, separatorIndex); - if (checkPath.endsWith(path.sep + "node_modules")) return false; - const pjson = readPackage(checkPath); - if (pjson) { - return { - path: checkPath, - data: pjson, - }; - } - } - return false; -} - -function readPackageMain(requestPath: string): string | undefined { - const pkg = readPackage(requestPath); - return pkg ? pkg.main : undefined; -} - -// deno-lint-ignore no-explicit-any -function readPackageExports(requestPath: string): any | undefined { - const pkg = readPackage(requestPath); - return pkg ? pkg.exports : undefined; -} - -function tryPackage( - requestPath: string, - exts: string[], - isMain: boolean, - _originalPath: string, -): string | false { - const pkg = readPackageMain(requestPath); - - if (!pkg) { - return tryExtensions(path.resolve(requestPath, "index"), exts, isMain); - } - - const filename = path.resolve(requestPath, pkg); - let actual = tryFile(filename, isMain) || - tryExtensions(filename, exts, isMain) || - tryExtensions(path.resolve(filename, "index"), exts, isMain); - if (actual === false) { - actual = tryExtensions(path.resolve(requestPath, "index"), exts, isMain); - if (!actual) { - const err = new Error( - `Cannot find module '${filename}'. ` + - 'Please verify that the package.json has a valid "main" entry', - ) as Error & { code: string }; - err.code = "MODULE_NOT_FOUND"; - throw err; - } - } - return actual; -} - -// Check if the file exists and is not a directory -// if using --preserve-symlinks and isMain is false, -// keep symlinks intact, otherwise resolve to the -// absolute realpath. -function tryFile(requestPath: string, _isMain: boolean): string | false { - const rc = stat(requestPath); - return rc === 0 && toRealPath(requestPath); -} - -function toRealPath(requestPath: string): string { - return Deno.realPathSync(requestPath); -} - -// Given a path, check if the file exists with any of the set extensions -function tryExtensions( - p: string, - exts: string[], - isMain: boolean, -): string | false { - for (let i = 0; i < exts.length; i++) { - const filename = tryFile(p + exts[i], isMain); - - if (filename) { - return filename; - } - } - return false; -} - -// Find the longest (possibly multi-dot) extension registered in -// Module._extensions -function findLongestRegisteredExtension(filename: string): string { - const name = path.basename(filename); - let currentExtension; - let index; - let startIndex = 0; - while ((index = name.indexOf(".", startIndex)) !== -1) { - startIndex = index + 1; - if (index === 0) continue; // Skip dotfiles like .gitignore - currentExtension = name.slice(index); - if (Module._extensions[currentExtension]) return currentExtension; - } - return ".js"; -} - -// --experimental-resolve-self trySelf() support removed. - -// deno-lint-ignore no-explicit-any -function isConditionalDotExportSugar(exports: any, _basePath: string): boolean { - if (typeof exports === "string") return true; - if (Array.isArray(exports)) return true; - if (typeof exports !== "object") return false; - let isConditional = false; - let firstCheck = true; - for (const key of Object.keys(exports)) { - const curIsConditional = key[0] !== "."; - if (firstCheck) { - firstCheck = false; - isConditional = curIsConditional; - } else if (isConditional !== curIsConditional) { - throw new Error( - '"exports" cannot ' + - "contain some keys starting with '.' and some not. The exports " + - "object must either be an object of package subpath keys or an " + - "object of main entry condition name keys only.", - ); - } - } - return isConditional; -} - -function applyExports(basePath: string, expansion: string): string { - const mappingKey = `.${expansion}`; - - let pkgExports = readPackageExports(basePath); - if (pkgExports === undefined || pkgExports === null) { - return path.resolve(basePath, mappingKey); - } - - if (isConditionalDotExportSugar(pkgExports, basePath)) { - pkgExports = { ".": pkgExports }; - } - - if (typeof pkgExports === "object") { - if (Object.prototype.hasOwnProperty.call(pkgExports, mappingKey)) { - const mapping = pkgExports[mappingKey]; - return resolveExportsTarget( - pathToFileURL(basePath + "/"), - mapping, - "", - basePath, - mappingKey, - ); - } - - // Fallback to CJS main lookup when no main export is defined - if (mappingKey === ".") return basePath; - - let dirMatch = ""; - for (const candidateKey of Object.keys(pkgExports)) { - if (candidateKey[candidateKey.length - 1] !== "/") continue; - if ( - candidateKey.length > dirMatch.length && - mappingKey.startsWith(candidateKey) - ) { - dirMatch = candidateKey; - } - } - - if (dirMatch !== "") { - const mapping = pkgExports[dirMatch]; - const subpath = mappingKey.slice(dirMatch.length); - return resolveExportsTarget( - pathToFileURL(basePath + "/"), - mapping, - subpath, - basePath, - mappingKey, - ); - } - } - // Fallback to CJS main lookup when no main export is defined - if (mappingKey === ".") return basePath; - - const e = new Error( - `Package exports for '${basePath}' do not define ` + - `a '${mappingKey}' subpath`, - ) as Error & { code?: string }; - e.code = "MODULE_NOT_FOUND"; - throw e; -} - -// This only applies to requests of a specific form: -// 1. name/.* -// 2. @scope/name/.* -const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/; -function resolveExports( - nmPath: string, - request: string, - absoluteRequest: boolean, -): string { - // The implementation's behavior is meant to mirror resolution in ESM. - if (!absoluteRequest) { - const [, name, expansion = ""] = request.match(EXPORTS_PATTERN) || []; - if (!name) { - return path.resolve(nmPath, request); - } - - const basePath = path.resolve(nmPath, name); - return applyExports(basePath, expansion); - } - - return path.resolve(nmPath, request); -} - -function resolveExportsTarget( - pkgPath: URL, - // deno-lint-ignore no-explicit-any - target: any, - subpath: string, - basePath: string, - mappingKey: string, -): string { - if (typeof target === "string") { - if ( - target.startsWith("./") && - (subpath.length === 0 || target.endsWith("/")) - ) { - const resolvedTarget = new URL(target, pkgPath); - const pkgPathPath = pkgPath.pathname; - const resolvedTargetPath = resolvedTarget.pathname; - if ( - resolvedTargetPath.startsWith(pkgPathPath) && - resolvedTargetPath.indexOf("/node_modules/", pkgPathPath.length - 1) === - -1 - ) { - const resolved = new URL(subpath, resolvedTarget); - const resolvedPath = resolved.pathname; - if ( - resolvedPath.startsWith(resolvedTargetPath) && - resolvedPath.indexOf("/node_modules/", pkgPathPath.length - 1) === -1 - ) { - return fileURLToPath(resolved); - } - } - } - } else if (Array.isArray(target)) { - for (const targetValue of target) { - if (Array.isArray(targetValue)) continue; - try { - return resolveExportsTarget( - pkgPath, - targetValue, - subpath, - basePath, - mappingKey, - ); - } catch (e) { - if (e.code !== "MODULE_NOT_FOUND") throw e; - } - } - } else if (typeof target === "object" && target !== null) { - // removed experimentalConditionalExports - if (Object.prototype.hasOwnProperty.call(target, "default")) { - try { - return resolveExportsTarget( - pkgPath, - target.default, - subpath, - basePath, - mappingKey, - ); - } catch (e) { - if (e.code !== "MODULE_NOT_FOUND") throw e; - } - } - } - let e: Error & { code?: string }; - if (mappingKey !== ".") { - e = new Error( - `Package exports for '${basePath}' do not define a ` + - `valid '${mappingKey}' target${subpath ? " for " + subpath : ""}`, - ); - } else { - e = new Error(`No valid exports main found for '${basePath}'`); - } - e.code = "MODULE_NOT_FOUND"; - throw e; -} - -// 'node_modules' character codes reversed -const nmChars = [115, 101, 108, 117, 100, 111, 109, 95, 101, 100, 111, 110]; -const nmLen = nmChars.length; - -// deno-lint-ignore no-explicit-any -function emitCircularRequireWarning(prop: any): void { - console.error( - `Accessing non-existent property '${ - String(prop) - }' of module exports inside circular dependency`, - ); -} - -// A Proxy that can be used as the prototype of a module.exports object and -// warns when non-existent properties are accessed. -const CircularRequirePrototypeWarningProxy = new Proxy( - {}, - { - // deno-lint-ignore no-explicit-any - get(target: Record<string, any>, prop: string): any { - if (prop in target) return target[prop]; - emitCircularRequireWarning(prop); - return undefined; - }, - - getOwnPropertyDescriptor(target, prop): PropertyDescriptor | undefined { - if (Object.prototype.hasOwnProperty.call(target, prop)) { - return Object.getOwnPropertyDescriptor(target, prop); - } - emitCircularRequireWarning(prop); - return undefined; - }, - }, -); - -// Object.prototype and ObjectProtoype refer to our 'primordials' versions -// and are not identical to the versions on the global object. -const PublicObjectPrototype = globalThis.Object.prototype; - -// deno-lint-ignore no-explicit-any -function getExportsForCircularRequire(module: Module): any { - if ( - module.exports && - Object.getPrototypeOf(module.exports) === PublicObjectPrototype && - // Exclude transpiled ES6 modules / TypeScript code because those may - // employ unusual patterns for accessing 'module.exports'. That should be - // okay because ES6 modules have a different approach to circular - // dependencies anyway. - !module.exports.__esModule - ) { - // This is later unset once the module is done loading. - Object.setPrototypeOf(module.exports, CircularRequirePrototypeWarningProxy); - } - - return module.exports; -} - -type RequireWrapper = ( - // deno-lint-ignore no-explicit-any - exports: any, - // deno-lint-ignore no-explicit-any - require: any, - module: Module, - __filename: string, - __dirname: string, -) => void; - -function wrapSafe(filename: string, content: string): RequireWrapper { - // TODO(bartlomieju): fix this - const wrapper = Module.wrap(content); - // deno-lint-ignore no-explicit-any - const [f, err] = (Deno as any).core.evalContext(wrapper, filename); - if (err) { - throw err; - } - return f; - // ESM code removed. -} - -// Native extension for .js -Module._extensions[".js"] = (module: Module, filename: string): void => { - if (filename.endsWith(".js")) { - const pkg = readPackageScope(filename); - if (pkg !== false && pkg.data && pkg.data.type === "module") { - throw new Error("Importing ESM module"); - } - } - const content = new TextDecoder().decode(Deno.readFileSync(filename)); - module._compile(content, filename); -}; - -// Native extension for .json -Module._extensions[".json"] = (module: Module, filename: string): void => { - const content = new TextDecoder().decode(Deno.readFileSync(filename)); - // manifest code removed - try { - module.exports = JSON.parse(stripBOM(content)); - } catch (err) { - err.message = filename + ": " + err.message; - throw err; - } -}; - -// .node extension is not supported - -function createRequireFromPath(filename: string): RequireFunction { - // Allow a directory to be passed as the filename - const trailingSlash = filename.endsWith("/") || - (isWindows && filename.endsWith("\\")); - - const proxyPath = trailingSlash ? path.join(filename, "noop.js") : filename; - - const m = new Module(proxyPath); - m.filename = proxyPath; - - m.paths = Module._nodeModulePaths(m.path); - return makeRequireFunction(m); -} - -// deno-lint-ignore no-explicit-any -type Require = (id: string) => any; -// deno-lint-ignore no-explicit-any -type RequireResolve = (request: string, options: any) => string; -interface RequireResolveFunction extends RequireResolve { - paths: (request: string) => string[] | null; -} - -interface RequireFunction extends Require { - resolve: RequireResolveFunction; - // deno-lint-ignore no-explicit-any - extensions: { [key: string]: (module: Module, filename: string) => any }; - cache: { [key: string]: Module }; -} - -function makeRequireFunction(mod: Module): RequireFunction { - // deno-lint-ignore no-explicit-any - const require = function require(path: string): any { - return mod.require(path); - }; - - function resolve(request: string, options?: { paths: string[] }): string { - return Module._resolveFilename(request, mod, false, options); - } - - require.resolve = resolve; - - function paths(request: string): string[] | null { - return Module._resolveLookupPaths(request, mod); - } - - resolve.paths = paths; - // TODO(bartlomieju): set main - // require.main = process.mainModule; - - // Enable support to add extra extension types. - require.extensions = Module._extensions; - - require.cache = Module._cache; - - return require; -} - -/** - * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) - * because the buffer-to-string conversion in `fs.readFileSync()` - * translates it to FEFF, the UTF-16 BOM. - */ -function stripBOM(content: string): string { - if (content.charCodeAt(0) === 0xfeff) { - content = content.slice(1); - } - return content; -} - -export const builtinModules = Module.builtinModules; -export const createRequire = Module.createRequire; -export default Module; diff --git a/std/node/module_test.ts b/std/node/module_test.ts deleted file mode 100644 index 58c325f94..000000000 --- a/std/node/module_test.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertStringIncludes, -} from "../testing/asserts.ts"; - -import * as path from "../path/mod.ts"; -import { createRequire } from "./module.ts"; - -const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); -const testdataDir = path.resolve(moduleDir, path.join("_fs", "testdata")); - -const require = createRequire(import.meta.url); - -Deno.test("requireSuccess", function () { - // Relative to import.meta.url - const result = require("./tests/cjs/cjs_a.js"); - assert("helloA" in result); - assert("helloB" in result); - assert("C" in result); - assert("leftPad" in result); - assertEquals(result.helloA(), "A"); - assertEquals(result.helloB(), "B"); - assertEquals(result.C, "C"); - assertEquals(result.leftPad("pad", 4), " pad"); -}); - -Deno.test("requireCycle", function () { - const resultA = require("./tests/cjs/cjs_cycle_a"); - const resultB = require("./tests/cjs/cjs_cycle_b"); - assert(resultA); - assert(resultB); -}); - -Deno.test("requireBuiltin", function () { - const fs = require("fs"); - assert("readFileSync" in fs); - const { readFileSync, isNull, extname } = require("./tests/cjs/cjs_builtin"); - - const testData = path.relative( - Deno.cwd(), - path.join(testdataDir, "hello.txt"), - ); - assertEquals( - readFileSync(testData, { encoding: "utf8" }), - "hello world", - ); - assert(isNull(null)); - assertEquals(extname("index.html"), ".html"); -}); - -Deno.test("requireIndexJS", function () { - const { isIndex } = require("./tests/cjs"); - assert(isIndex); -}); - -Deno.test("requireNodeOs", function () { - const os = require("os"); - assert(os.arch); - assert(typeof os.arch() == "string"); -}); - -Deno.test("requireStack", function () { - const { hello } = require("./tests/cjs/cjs_throw"); - try { - hello(); - } catch (e) { - assertStringIncludes(e.stack, "/tests/cjs/cjs_throw.js"); - } -}); - -Deno.test("requireFileInSymlinkDir", () => { - const { C } = require("./tests/cjs/dir"); - assertEquals(C, "C"); -}); diff --git a/std/node/os.ts b/std/node/os.ts deleted file mode 100644 index 776eff92d..000000000 --- a/std/node/os.ts +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -import { notImplemented } from "./_utils.ts"; -import { validateIntegerRange } from "./_utils.ts"; -import { EOL as fsEOL } from "../fs/eol.ts"; -import process from "./process.ts"; - -const SEE_GITHUB_ISSUE = "See https://github.com/denoland/deno/issues/3802"; - -interface CPUTimes { - /** The number of milliseconds the CPU has spent in user mode */ - user: number; - - /** The number of milliseconds the CPU has spent in nice mode */ - nice: number; - - /** The number of milliseconds the CPU has spent in sys mode */ - sys: number; - - /** The number of milliseconds the CPU has spent in idle mode */ - idle: number; - - /** The number of milliseconds the CPU has spent in irq mode */ - irq: number; -} - -interface CPUCoreInfo { - model: string; - - /** in MHz */ - speed: number; - - times: CPUTimes; -} - -interface NetworkAddress { - /** The assigned IPv4 or IPv6 address */ - address: string; - - /** The IPv4 or IPv6 network mask */ - netmask: string; - - family: "IPv4" | "IPv6"; - - /** The MAC address of the network interface */ - mac: string; - - /** true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false */ - internal: boolean; - - /** The numeric IPv6 scope ID (only specified when family is IPv6) */ - scopeid?: number; - - /** The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. */ - cidr: string; -} - -interface NetworkInterfaces { - [key: string]: NetworkAddress[]; -} - -export interface UserInfoOptions { - encoding: string; -} - -interface UserInfo { - username: string; - uid: number; - gid: number; - shell: string; - homedir: string; -} - -arch[Symbol.toPrimitive] = (): string => arch(); -endianness[Symbol.toPrimitive] = (): string => endianness(); -freemem[Symbol.toPrimitive] = (): number => freemem(); -homedir[Symbol.toPrimitive] = (): string | null => homedir(); -hostname[Symbol.toPrimitive] = (): string | null => hostname(); -platform[Symbol.toPrimitive] = (): string => platform(); -release[Symbol.toPrimitive] = (): string => release(); -totalmem[Symbol.toPrimitive] = (): number => totalmem(); -type[Symbol.toPrimitive] = (): string => type(); -uptime[Symbol.toPrimitive] = (): number => uptime(); - -/** Returns the operating system CPU architecture for which the Deno binary was compiled */ -export function arch(): string { - return Deno.build.arch; -} - -/** Not yet implemented */ -export function cpus(): CPUCoreInfo[] { - notImplemented(SEE_GITHUB_ISSUE); -} - -/** - * Returns a string identifying the endianness of the CPU for which the Deno - * binary was compiled. Possible values are 'BE' for big endian and 'LE' for - * little endian. - **/ -export function endianness(): "BE" | "LE" { - // Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness - const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true /* littleEndian */); - // Int16Array uses the platform's endianness. - return new Int16Array(buffer)[0] === 256 ? "LE" : "BE"; -} - -/** Return free memory amount */ -export function freemem(): number { - return Deno.systemMemoryInfo().free; -} - -/** Not yet implemented */ -export function getPriority(pid = 0): number { - validateIntegerRange(pid, "pid"); - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Returns the string path of the current user's home directory. */ -export function homedir(): string | null { - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Returns the host name of the operating system as a string. */ -export function hostname(): string { - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Returns an array containing the 1, 5, and 15 minute load averages */ -export function loadavg(): number[] { - if (Deno.build.os === "windows") { - return [0, 0, 0]; - } - return Deno.loadavg(); -} - -/** Not yet implemented */ -export function networkInterfaces(): NetworkInterfaces { - notImplemented(SEE_GITHUB_ISSUE); -} -/** Returns the a string identifying the operating system platform. The value is set at compile time. Possible values are 'darwin', 'linux', and 'win32'. */ -export function platform(): string { - return process.platform; -} - -/** Returns the operating system as a string */ -export function release(): string { - return Deno.osRelease(); -} - -/** Not yet implemented */ -export function setPriority(pid: number, priority?: number): void { - /* The node API has the 'pid' as the first parameter and as optional. - This makes for a problematic implementation in Typescript. */ - if (priority === undefined) { - priority = pid; - pid = 0; - } - validateIntegerRange(pid, "pid"); - validateIntegerRange(priority, "priority", -20, 19); - - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Returns the operating system's default directory for temporary files as a string. */ -export function tmpdir(): string | null { - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Return total physical memory amount */ -export function totalmem(): number { - return Deno.systemMemoryInfo().total; -} - -/** Returns operating system type (i.e. 'Windows_NT', 'Linux', 'Darwin') */ -export function type(): string { - switch (Deno.build.os) { - case "windows": - return "Windows_NT"; - case "linux": - return "Linux"; - case "darwin": - return "Darwin"; - default: - throw Error("unreachable"); - } -} - -/** Not yet implemented */ -export function uptime(): number { - notImplemented(SEE_GITHUB_ISSUE); -} - -/** Not yet implemented */ -export function userInfo( - options: UserInfoOptions = { encoding: "utf-8" }, -): UserInfo { - notImplemented(SEE_GITHUB_ISSUE); -} - -export const constants = { - // UV_UDP_REUSEADDR: 4, //see https://nodejs.org/docs/latest-v12.x/api/os.html#os_libuv_constants - dlopen: { - // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_dlopen_constants - }, - errno: { - // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_error_constants - }, - signals: Deno.Signal, - priority: { - // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_priority_constants - }, -}; - -export const EOL = Deno.build.os == "windows" ? fsEOL.CRLF : fsEOL.LF; - -export default { - arch, - cpus, - endianness, - freemem, - getPriority, - homedir, - hostname, - loadavg, - networkInterfaces, - platform, - release, - setPriority, - tmpdir, - totalmem, - type, - uptime, - userInfo, - constants, - EOL, -}; diff --git a/std/node/os_test.ts b/std/node/os_test.ts deleted file mode 100644 index 6d5c124ce..000000000 --- a/std/node/os_test.ts +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; -import * as os from "./os.ts"; - -Deno.test({ - name: "build architecture is a string", - fn() { - assertEquals(typeof os.arch(), "string"); - }, -}); - -Deno.test({ - name: "home directory is a string", - ignore: true, - fn() { - assertEquals(typeof os.homedir(), "string"); - }, -}); - -Deno.test({ - name: "tmp directory is a string", - ignore: true, - fn() { - assertEquals(typeof os.tmpdir(), "string"); - }, -}); - -Deno.test({ - name: "hostname is a string", - ignore: true, - fn() { - assertEquals(typeof os.hostname(), "string"); - }, -}); - -Deno.test({ - name: "platform is a string", - fn() { - assertEquals(typeof os.platform(), "string"); - }, -}); - -Deno.test({ - name: "release is a string", - fn() { - assertEquals(typeof os.release(), "string"); - }, -}); - -Deno.test({ - name: "type is a string", - fn() { - assertEquals(typeof os.type(), "string"); - }, -}); - -Deno.test({ - name: "getPriority(): PID must be a 32 bit integer", - fn() { - assertThrows( - () => { - os.getPriority(3.15); - }, - Error, - "pid must be 'an integer'", - ); - assertThrows( - () => { - os.getPriority(9999999999); - }, - Error, - "must be >= -2147483648 && <= 2147483647", - ); - }, -}); - -Deno.test({ - name: "setPriority(): PID must be a 32 bit integer", - fn() { - assertThrows( - () => { - os.setPriority(3.15, 0); - }, - Error, - "pid must be 'an integer'", - ); - assertThrows( - () => { - os.setPriority(9999999999, 0); - }, - Error, - "pid must be >= -2147483648 && <= 2147483647", - ); - }, -}); - -Deno.test({ - name: "setPriority(): priority must be an integer between -20 and 19", - fn() { - assertThrows( - () => { - os.setPriority(0, 3.15); - }, - Error, - "priority must be 'an integer'", - ); - assertThrows( - () => { - os.setPriority(0, -21); - }, - Error, - "priority must be >= -20 && <= 19", - ); - assertThrows( - () => { - os.setPriority(0, 20); - }, - Error, - "priority must be >= -20 && <= 19", - ); - assertThrows( - () => { - os.setPriority(0, 9999999999); - }, - Error, - "priority must be >= -20 && <= 19", - ); - }, -}); - -Deno.test({ - name: - "setPriority(): if only one argument specified, then this is the priority, NOT the pid", - fn() { - assertThrows( - () => { - os.setPriority(3.15); - }, - Error, - "priority must be 'an integer'", - ); - assertThrows( - () => { - os.setPriority(-21); - }, - Error, - "priority must be >= -20 && <= 19", - ); - assertThrows( - () => { - os.setPriority(20); - }, - Error, - "priority must be >= -20 && <= 19", - ); - assertThrows( - () => { - os.setPriority(9999999999); - }, - Error, - "priority must be >= -20 && <= 19", - ); - }, -}); - -Deno.test({ - name: "Signals are as expected", - fn() { - // Test a few random signals for equality - assertEquals(os.constants.signals.SIGKILL, Deno.Signal.SIGKILL); - assertEquals(os.constants.signals.SIGCONT, Deno.Signal.SIGCONT); - assertEquals(os.constants.signals.SIGXFSZ, Deno.Signal.SIGXFSZ); - }, -}); - -Deno.test({ - name: "EOL is as expected", - fn() { - assert(os.EOL == "\r\n" || os.EOL == "\n"); - }, -}); - -Deno.test({ - name: "Endianness is determined", - fn() { - assert(["LE", "BE"].includes(os.endianness())); - }, -}); - -Deno.test({ - name: "Load average is an array of 3 numbers", - fn() { - const result = os.loadavg(); - assert(result.length == 3); - assertEquals(typeof result[0], "number"); - assertEquals(typeof result[1], "number"); - assertEquals(typeof result[2], "number"); - }, -}); - -Deno.test({ - name: "Primitive coercion works as expected", - fn() { - assertEquals(`${os.arch}`, os.arch()); - assertEquals(`${os.endianness}`, os.endianness()); - assertEquals(`${os.platform}`, os.platform()); - }, -}); - -Deno.test({ - name: "Total memory amount should be greater than 0", - fn() { - assert(os.totalmem() > 0); - }, -}); - -Deno.test({ - name: "Free memory amount should be greater than 0", - fn() { - assert(os.freemem() > 0); - }, -}); - -Deno.test({ - name: "APIs not yet implemented", - fn() { - assertThrows( - () => { - os.cpus(); - }, - Error, - "Not implemented", - ); - assertThrows( - () => { - os.getPriority(); - }, - Error, - "Not implemented", - ); - assertThrows( - () => { - os.networkInterfaces(); - }, - Error, - "Not implemented", - ); - assertThrows( - () => { - os.setPriority(0); - }, - Error, - "Not implemented", - ); - assertThrows( - () => { - os.uptime(); - }, - Error, - "Not implemented", - ); - assertThrows( - () => { - os.userInfo(); - }, - Error, - "Not implemented", - ); - }, -}); diff --git a/std/node/path.ts b/std/node/path.ts deleted file mode 100644 index 0f29ad9b0..000000000 --- a/std/node/path.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -export * from "../path/mod.ts"; -import * as m from "../path/mod.ts"; -export default m; diff --git a/std/node/process.ts b/std/node/process.ts deleted file mode 100644 index 419eb8cec..000000000 --- a/std/node/process.ts +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { notImplemented } from "./_utils.ts"; -import EventEmitter from "./events.ts"; -import { fromFileUrl } from "../path/mod.ts"; - -const notImplementedEvents = [ - "beforeExit", - "disconnect", - "message", - "multipleResolves", - "rejectionHandled", - "SIGBREAK", - "SIGBUS", - "SIGFPE", - "SIGHUP", - "SIGILL", - "SIGINT", - "SIGSEGV", - "SIGTERM", - "SIGWINCH", - "uncaughtException", - "uncaughtExceptionMonitor", - "unhandledRejection", - "warning", -]; - -/** https://nodejs.org/api/process.html#process_process_arch */ -export const arch = Deno.build.arch; - -function getArguments() { - return [Deno.execPath(), fromFileUrl(Deno.mainModule), ...Deno.args]; -} - -//deno-lint-ignore ban-ts-comment -//@ts-ignore -const _argv: { - [Deno.customInspect]: () => string; - [key: number]: string; -} = []; - -Object.defineProperty(_argv, Deno.customInspect, { - enumerable: false, - configurable: false, - get: function () { - return getArguments(); - }, -}); - -/** - * https://nodejs.org/api/process.html#process_process_argv - * Read permissions are required in order to get the executable route - * */ -export const argv: Record<string, string> = new Proxy(_argv, { - get(target, prop) { - if (prop === Deno.customInspect) { - return target[Deno.customInspect]; - } - return getArguments()[prop as number]; - }, - ownKeys() { - return Reflect.ownKeys(getArguments()); - }, -}); - -/** https://nodejs.org/api/process.html#process_process_chdir_directory */ -export const chdir = Deno.chdir; - -/** https://nodejs.org/api/process.html#process_process_cwd */ -export const cwd = Deno.cwd; - -//deno-lint-ignore ban-ts-comment -//@ts-ignore -const _env: { - [Deno.customInspect]: () => string; -} = {}; - -Object.defineProperty(_env, Deno.customInspect, { - enumerable: false, - configurable: false, - get: function () { - return Deno.env.toObject(); - }, -}); - -/** - * https://nodejs.org/api/process.html#process_process_env - * Requires env permissions - * */ -export const env: Record<string, string> = new Proxy(_env, { - get(target, prop) { - if (prop === Deno.customInspect) { - return target[Deno.customInspect]; - } - return Deno.env.get(String(prop)); - }, - ownKeys() { - return Reflect.ownKeys(Deno.env.toObject()); - }, - set(_target, prop, value) { - Deno.env.set(String(prop), String(value)); - return value; - }, -}); - -/** https://nodejs.org/api/process.html#process_process_exit_code */ -export const exit = Deno.exit; - -/** https://nodejs.org/api/process.html#process_process_nexttick_callback_args */ -export function nextTick(this: unknown, cb: () => void): void; -export function nextTick<T extends Array<unknown>>( - this: unknown, - cb: (...args: T) => void, - ...args: T -): void; -export function nextTick<T extends Array<unknown>>( - this: unknown, - cb: (...args: T) => void, - ...args: T -) { - if (args) { - queueMicrotask(() => cb.call(this, ...args)); - } else { - queueMicrotask(cb); - } -} - -/** https://nodejs.org/api/process.html#process_process_pid */ -export const pid = Deno.pid; - -/** https://nodejs.org/api/process.html#process_process_platform */ -export const platform = Deno.build.os === "windows" ? "win32" : Deno.build.os; - -/** https://nodejs.org/api/process.html#process_process_version */ -export const version = `v${Deno.version.deno}`; - -/** https://nodejs.org/api/process.html#process_process_versions */ -export const versions = { - node: Deno.version.deno, - ...Deno.version, -}; - -class Process extends EventEmitter { - constructor() { - super(); - - //This causes the exit event to be binded to the unload event - window.addEventListener("unload", () => { - //TODO(Soremwar) - //Get the exit code from the unload event - super.emit("exit", 0); - }); - } - - /** https://nodejs.org/api/process.html#process_process_arch */ - arch = arch; - - /** - * https://nodejs.org/api/process.html#process_process_argv - * Read permissions are required in order to get the executable route - * */ - argv = argv; - - /** https://nodejs.org/api/process.html#process_process_chdir_directory */ - chdir = chdir; - - /** https://nodejs.org/api/process.html#process_process_cwd */ - cwd = cwd; - - /** https://nodejs.org/api/process.html#process_process_exit_code */ - exit = exit; - - /** - * https://nodejs.org/api/process.html#process_process_env - * Requires env permissions - * */ - env = env; - - /** https://nodejs.org/api/process.html#process_process_nexttick_callback_args */ - nextTick = nextTick; - - /** https://nodejs.org/api/process.html#process_process_events */ - //deno-lint-ignore ban-types - on(event: typeof notImplementedEvents[number], listener: Function): never; - on(event: "exit", listener: (code: number) => void): this; - //deno-lint-ignore no-explicit-any - on(event: string, listener: (...args: any[]) => void): this { - if (notImplementedEvents.includes(event)) { - notImplemented(); - } - - super.on(event, listener); - - return this; - } - - /** https://nodejs.org/api/process.html#process_process_pid */ - pid = pid; - - /** https://nodejs.org/api/process.html#process_process_platform */ - platform = platform; - - removeAllListeners(_event: string): never { - notImplemented(); - } - - removeListener( - event: typeof notImplementedEvents[number], - //deno-lint-ignore ban-types - listener: Function, - ): never; - removeListener(event: "exit", listener: (code: number) => void): this; - //deno-lint-ignore no-explicit-any - removeListener(event: string, listener: (...args: any[]) => void): this { - if (notImplementedEvents.includes(event)) { - notImplemented(); - } - - super.removeListener("exit", listener); - - return this; - } - - /** https://nodejs.org/api/process.html#process_process_stderr */ - get stderr() { - return { - fd: Deno.stderr.rid, - get isTTY(): boolean { - return Deno.isatty(this.fd); - }, - pipe(_destination: Deno.Writer, _options: { end: boolean }): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - // deno-lint-ignore ban-types - write(_chunk: string | Uint8Array, _callback: Function): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - // deno-lint-ignore ban-types - on(_event: string, _callback: Function): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - }; - } - - /** https://nodejs.org/api/process.html#process_process_stdin */ - get stdin() { - return { - fd: Deno.stdin.rid, - get isTTY(): boolean { - return Deno.isatty(this.fd); - }, - read(_size: number): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - // deno-lint-ignore ban-types - on(_event: string, _callback: Function): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - }; - } - - /** https://nodejs.org/api/process.html#process_process_stdout */ - get stdout() { - return { - fd: Deno.stdout.rid, - get isTTY(): boolean { - return Deno.isatty(this.fd); - }, - pipe(_destination: Deno.Writer, _options: { end: boolean }): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - // deno-lint-ignore ban-types - write(_chunk: string | Uint8Array, _callback: Function): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - // deno-lint-ignore ban-types - on(_event: string, _callback: Function): void { - // TODO(JayHelton): to be implemented - notImplemented(); - }, - }; - } - - /** https://nodejs.org/api/process.html#process_process_version */ - version = version; - - /** https://nodejs.org/api/process.html#process_process_versions */ - versions = versions; -} - -/** https://nodejs.org/api/process.html#process_process */ -const process = new Process(); - -Object.defineProperty(process, Symbol.toStringTag, { - enumerable: false, - writable: true, - configurable: false, - value: "process", -}); - -export const removeListener = process.removeListener; -export const removeAllListeners = process.removeAllListeners; -export const stderr = process.stderr; -export const stdin = process.stdin; -export const stdout = process.stdout; - -export default process; - -//TODO(Soremwar) -//Remove on 1.0 -//Kept for backwars compatibility with std -export { process }; diff --git a/std/node/process_exit_test.ts b/std/node/process_exit_test.ts deleted file mode 100644 index 54c8bcc01..000000000 --- a/std/node/process_exit_test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "./global.ts"; - -//deno-lint-ignore no-undef -process.on("exit", () => { - console.log(1); -}); - -function unexpected() { - console.log(null); -} -//deno-lint-ignore no-undef -process.on("exit", unexpected); -//deno-lint-ignore no-undef -process.removeListener("exit", unexpected); - -//deno-lint-ignore no-undef -process.on("exit", () => { - console.log(2); -}); diff --git a/std/node/process_test.ts b/std/node/process_test.ts deleted file mode 100644 index 22cebf260..000000000 --- a/std/node/process_test.ts +++ /dev/null @@ -1,196 +0,0 @@ -// deno-lint-ignore-file no-undef -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import "./global.ts"; -import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; -import { stripColor } from "../fmt/colors.ts"; -import * as path from "../path/mod.ts"; -import { delay } from "../async/delay.ts"; -import { env } from "./process.ts"; - -Deno.test({ - name: "process.cwd and process.chdir success", - fn() { - assertEquals(process.cwd(), Deno.cwd()); - - const currentDir = Deno.cwd(); - - const tempDir = Deno.makeTempDirSync(); - process.chdir(tempDir); - assertEquals( - Deno.realPathSync(process.cwd()), - Deno.realPathSync(tempDir), - ); - - process.chdir(currentDir); - }, -}); - -Deno.test({ - name: "process.chdir failure", - fn() { - assertThrows( - () => { - process.chdir("non-existent-directory-name"); - }, - Deno.errors.NotFound, - "file", - // On every OS Deno returns: "No such file" except for Windows, where it's: - // "The system cannot find the file specified. (os error 2)" so "file" is - // the only common string here. - ); - }, -}); - -Deno.test({ - name: "process.version", - fn() { - assertEquals(typeof process, "object"); - assertEquals(typeof process.version, "string"); - assertEquals(typeof process.versions, "object"); - assertEquals(typeof process.versions.node, "string"); - }, -}); - -Deno.test({ - name: "process.platform", - fn() { - assertEquals(typeof process.platform, "string"); - }, -}); - -Deno.test({ - name: "process.arch", - fn() { - assertEquals(typeof process.arch, "string"); - // TODO(rsp): make sure that the arch strings should be the same in Node and Deno: - assertEquals(process.arch, Deno.build.arch); - }, -}); - -Deno.test({ - name: "process.pid", - fn() { - assertEquals(typeof process.pid, "number"); - assertEquals(process.pid, Deno.pid); - }, -}); - -Deno.test({ - name: "process.on", - async fn() { - assertEquals(typeof process.on, "function"); - assertThrows( - () => { - process.on("uncaughtException", (_err: Error) => {}); - }, - Error, - "implemented", - ); - - let triggered = false; - process.on("exit", () => { - triggered = true; - }); - process.emit("exit"); - assert(triggered); - - const cwd = path.dirname(path.fromFileUrl(import.meta.url)); - - const p = Deno.run({ - cmd: [ - Deno.execPath(), - "run", - "./process_exit_test.ts", - ], - cwd, - stdout: "piped", - }); - - const decoder = new TextDecoder(); - const rawOutput = await p.output(); - assertEquals( - stripColor(decoder.decode(rawOutput).trim()), - "1\n2", - ); - p.close(); - }, -}); - -Deno.test({ - name: "process.argv", - fn() { - assert(Array.isArray(process.argv)); - assert( - process.argv[0].match(/[^/\\]*deno[^/\\]*$/), - "deno included in the file name of argv[0]", - ); - assertEquals( - process.argv[1], - path.fromFileUrl(Deno.mainModule), - ); - }, -}); - -Deno.test({ - name: "process.env", - fn() { - Deno.env.set("HELLO", "WORLD"); - - assertEquals(typeof (process.env.HELLO), "string"); - assertEquals(process.env.HELLO, "WORLD"); - - assertEquals(typeof env.HELLO, "string"); - assertEquals(env.HELLO, "WORLD"); - }, -}); - -Deno.test({ - name: "process.stdin", - fn() { - assertEquals(typeof process.stdin.fd, "number"); - assertEquals(process.stdin.fd, Deno.stdin.rid); - // TODO(jayhelton) Uncomment out this assertion once PTY is supported - //assert(process.stdin.isTTY); - }, -}); - -Deno.test({ - name: "process.stdout", - fn() { - assertEquals(typeof process.stdout.fd, "number"); - assertEquals(process.stdout.fd, Deno.stdout.rid); - // TODO(jayhelton) Uncomment out this assertion once PTY is supported - // assert(process.stdout.isTTY); - }, -}); - -Deno.test({ - name: "process.stderr", - fn() { - assertEquals(typeof process.stderr.fd, "number"); - assertEquals(process.stderr.fd, Deno.stderr.rid); - // TODO(jayhelton) Uncomment out this assertion once PTY is supported - // assert(process.stderr.isTTY); - }, -}); - -Deno.test({ - name: "process.nextTick", - async fn() { - let withoutArguments = false; - process.nextTick(() => { - withoutArguments = true; - }); - - const expected = 12; - let result; - process.nextTick((x: number) => { - result = x; - }, 12); - - await delay(10); - assert(withoutArguments); - assertEquals(result, expected); - }, -}); diff --git a/std/node/querystring.ts b/std/node/querystring.ts deleted file mode 100644 index 4d9d0eb27..000000000 --- a/std/node/querystring.ts +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -interface ParseOptions { - /** The function to use when decoding percent-encoded characters in the query string. */ - decodeURIComponent?: (string: string) => string; - /** Specifies the maximum number of keys to parse. */ - maxKeys?: number; -} - -export const hexTable = new Array(256); -for (let i = 0; i < 256; ++i) { - hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase(); -} - -/** - * Parses a URL query string into a collection of key and value pairs. - * @param str The URL query string to parse - * @param sep The substring used to delimit key and value pairs in the query string. Default: '&'. - * @param eq The substring used to delimit keys and values in the query string. Default: '='. - * @param options The parse options - */ -export function parse( - str: string, - sep = "&", - eq = "=", - { decodeURIComponent = unescape, maxKeys = 1000 }: ParseOptions = {}, -): { [key: string]: string[] | string } { - const entries = str - .split(sep) - .map((entry) => entry.split(eq).map(decodeURIComponent)); - const final: { [key: string]: string[] | string } = {}; - - let i = 0; - while (true) { - if ((Object.keys(final).length === maxKeys && !!maxKeys) || !entries[i]) { - break; - } - - const [key, val] = entries[i]; - if (final[key]) { - if (Array.isArray(final[key])) { - (final[key] as string[]).push(val); - } else { - final[key] = [final[key] as string, val]; - } - } else { - final[key] = val; - } - - i++; - } - - return final; -} - -interface StringifyOptions { - /** The function to use when converting URL-unsafe characters to percent-encoding in the query string. */ - encodeURIComponent?: (string: string) => string; -} - -export function encodeStr( - str: string, - noEscapeTable: number[], - hexTable: string[], -): string { - const len = str.length; - if (len === 0) return ""; - - let out = ""; - let lastPos = 0; - - for (let i = 0; i < len; i++) { - let c = str.charCodeAt(i); - // ASCII - if (c < 0x80) { - if (noEscapeTable[c] === 1) continue; - if (lastPos < i) out += str.slice(lastPos, i); - lastPos = i + 1; - out += hexTable[c]; - continue; - } - - if (lastPos < i) out += str.slice(lastPos, i); - - // Multi-byte characters ... - if (c < 0x800) { - lastPos = i + 1; - out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)]; - continue; - } - if (c < 0xd800 || c >= 0xe000) { - lastPos = i + 1; - out += hexTable[0xe0 | (c >> 12)] + - hexTable[0x80 | ((c >> 6) & 0x3f)] + - hexTable[0x80 | (c & 0x3f)]; - continue; - } - // Surrogate pair - ++i; - - // This branch should never happen because all URLSearchParams entries - // should already be converted to USVString. But, included for - // completion's sake anyway. - if (i >= len) throw new Deno.errors.InvalidData("invalid URI"); - - const c2 = str.charCodeAt(i) & 0x3ff; - - lastPos = i + 1; - c = 0x10000 + (((c & 0x3ff) << 10) | c2); - out += hexTable[0xf0 | (c >> 18)] + - hexTable[0x80 | ((c >> 12) & 0x3f)] + - hexTable[0x80 | ((c >> 6) & 0x3f)] + - hexTable[0x80 | (c & 0x3f)]; - } - if (lastPos === 0) return str; - if (lastPos < len) return out + str.slice(lastPos); - return out; -} - -/** - * Produces a URL query string from a given obj by iterating through the object's "own properties". - * @param obj The object to serialize into a URL query string. - * @param sep The substring used to delimit key and value pairs in the query string. Default: '&'. - * @param eq The substring used to delimit keys and values in the query string. Default: '='. - * @param options The stringify options - */ -export function stringify( - // deno-lint-ignore no-explicit-any - obj: Record<string, any>, - sep = "&", - eq = "=", - { encodeURIComponent = escape }: StringifyOptions = {}, -): string { - const final = []; - - for (const entry of Object.entries(obj)) { - if (Array.isArray(entry[1])) { - for (const val of entry[1]) { - final.push(encodeURIComponent(entry[0]) + eq + encodeURIComponent(val)); - } - } else if (typeof entry[1] !== "object" && entry[1] !== undefined) { - final.push(entry.map(encodeURIComponent).join(eq)); - } else { - final.push(encodeURIComponent(entry[0]) + eq); - } - } - - return final.join(sep); -} - -/** Alias of querystring.parse() */ -export const decode = parse; -/** Alias of querystring.stringify() */ -export const encode = stringify; -export const unescape = decodeURIComponent; -export const escape = encodeURIComponent; - -export default { - parse, - encodeStr, - stringify, - hexTable, - decode, - encode, - unescape, - escape, -}; diff --git a/std/node/querystring_test.ts b/std/node/querystring_test.ts deleted file mode 100644 index d05a75eab..000000000 --- a/std/node/querystring_test.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import { parse, stringify } from "./querystring.ts"; - -Deno.test({ - name: "stringify", - fn() { - assertEquals( - stringify({ - a: "hello", - b: 5, - c: true, - d: ["foo", "bar"], - }), - "a=hello&b=5&c=true&d=foo&d=bar", - ); - }, -}); - -Deno.test({ - name: "parse", - fn() { - assertEquals(parse("a=hello&b=5&c=true&d=foo&d=bar"), { - a: "hello", - b: "5", - c: "true", - d: ["foo", "bar"], - }); - }, -}); diff --git a/std/node/stream.ts b/std/node/stream.ts deleted file mode 100644 index 230c5a9d6..000000000 --- a/std/node/stream.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -import Duplex from "./_stream/duplex.ts"; -import eos from "./_stream/end_of_stream.ts"; -import PassThrough from "./_stream/passthrough.ts"; -import pipeline from "./_stream/pipeline.ts"; -import * as promises from "./_stream/promises.ts"; -import Readable from "./_stream/readable.ts"; -import Stream from "./_stream/stream.ts"; -import Transform from "./_stream/transform.ts"; -import Writable from "./_stream/writable.ts"; - -const exports = { - Duplex, - finished: eos, - PassThrough, - pipeline, - promises, - Readable, - Stream, - Transform, - Writable, -}; - -export default exports; -export { - Duplex, - eos as finished, - PassThrough, - pipeline, - promises, - Readable, - Stream, - Transform, - Writable, -}; diff --git a/std/node/stream_test.ts b/std/node/stream_test.ts deleted file mode 100644 index f8d4ecfa5..000000000 --- a/std/node/stream_test.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright Node.js contributors. All rights reserved. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -import { Readable, Transform, Writable } from "./stream.ts"; -import { Buffer } from "./buffer.ts"; -import { deferred } from "../async/mod.ts"; -import { assert, assertEquals } from "../testing/asserts.ts"; -import { mustCall } from "./_utils.ts"; - -Deno.test("Readable and Writable stream backpressure test", async () => { - let pushes = 0; - const total = 65500 + 40 * 1024; - - let rsExecuted = 0; - const rsExecutedExpected = 11; - const rsExpectedExecutions = deferred(); - - let wsExecuted = 0; - const wsExecutedExpected = 410; - const wsExpectedExecutions = deferred(); - - const rs = new Readable({ - read: function () { - rsExecuted++; - if (rsExecuted == rsExecutedExpected) { - rsExpectedExecutions.resolve(); - } - - if (pushes++ === 10) { - this.push(null); - return; - } - - assert(this._readableState.length <= total); - - this.push(Buffer.alloc(65500)); - for (let i = 0; i < 40; i++) { - this.push(Buffer.alloc(1024)); - } - }, - }); - - const ws = new Writable({ - write: function (_data, _enc, cb) { - wsExecuted++; - if (wsExecuted == wsExecutedExpected) { - wsExpectedExecutions.resolve(); - } - cb(); - }, - }); - - rs.pipe(ws); - - const rsTimeout = setTimeout(() => rsExpectedExecutions.reject(), 1000); - const wsTimeout = setTimeout(() => wsExpectedExecutions.reject(), 1000); - await rsExpectedExecutions; - await wsExpectedExecutions; - clearTimeout(rsTimeout); - clearTimeout(wsTimeout); - assertEquals(rsExecuted, rsExecutedExpected); - assertEquals(wsExecuted, wsExecutedExpected); -}); - -Deno.test("Readable can be piped through Transform", async () => { - const [readExecution, readCb] = mustCall(function (this: Readable) { - this.push("content"); - this.push(null); - }); - - const r = new Readable({ - read: readCb, - }); - - const [transformExecution, transformCb] = mustCall( - function ( - this: Transform, - chunk: unknown, - _e, - callback: (error?: Error | null) => void, - ) { - this.push(chunk); - callback(); - }, - ); - - const [flushExecution, flushCb] = mustCall( - function (this: Transform, callback: (error?: Error | null) => void) { - callback(); - }, - ); - - const t = new Transform({ - transform: transformCb, - flush: flushCb, - }); - - r.pipe(t); - - const [readableExecution, readableCb] = mustCall(function () { - while (true) { - const chunk = t.read(); - if (!chunk) { - break; - } - - assertEquals(chunk.toString(), "content"); - } - }, 2); - - t.on("readable", readableCb); - - await readExecution; - await transformExecution; - await flushExecution; - await readableExecution; -}); diff --git a/std/node/string_decoder.ts b/std/node/string_decoder.ts deleted file mode 100644 index d5aba8018..000000000 --- a/std/node/string_decoder.ts +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -import { Buffer } from "./buffer.ts"; -import { normalizeEncoding as castEncoding, notImplemented } from "./_utils.ts"; - -enum NotImplemented { - "ascii", - "latin1", - "utf16le", -} - -function normalizeEncoding(enc?: string): string { - const encoding = castEncoding(enc ?? null); - if (encoding && encoding in NotImplemented) notImplemented(encoding); - if (!encoding && typeof enc === "string" && enc.toLowerCase() !== "raw") { - throw new Error(`Unknown encoding: ${enc}`); - } - return String(encoding); -} -/* - * Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a - * continuation byte. If an invalid byte is detected, -2 is returned. - * */ -function utf8CheckByte(byte: number): number { - if (byte <= 0x7f) return 0; - else if (byte >> 5 === 0x06) return 2; - else if (byte >> 4 === 0x0e) return 3; - else if (byte >> 3 === 0x1e) return 4; - return byte >> 6 === 0x02 ? -1 : -2; -} - -/* - * Checks at most 3 bytes at the end of a Buffer in order to detect an - * incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) - * needed to complete the UTF-8 character (if applicable) are returned. - * */ -function utf8CheckIncomplete( - self: StringDecoderBase, - buf: Buffer, - i: number, -): number { - let j = buf.length - 1; - if (j < i) return 0; - let nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 1; - return nb; - } - if (--j < i || nb === -2) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 2; - return nb; - } - if (--j < i || nb === -2) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) { - if (nb === 2) nb = 0; - else self.lastNeed = nb - 3; - } - return nb; - } - return 0; -} - -/* - * Validates as many continuation bytes for a multi-byte UTF-8 character as - * needed or are available. If we see a non-continuation byte where we expect - * one, we "replace" the validated continuation bytes we've seen so far with - * a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding - * behavior. The continuation byte check is included three times in the case - * where all of the continuation bytes for a character exist in the same buffer. - * It is also done this way as a slight performance increase instead of using a - * loop. - * */ -function utf8CheckExtraBytes( - self: StringDecoderBase, - buf: Buffer, -): string | undefined { - if ((buf[0] & 0xc0) !== 0x80) { - self.lastNeed = 0; - return "\ufffd"; - } - if (self.lastNeed > 1 && buf.length > 1) { - if ((buf[1] & 0xc0) !== 0x80) { - self.lastNeed = 1; - return "\ufffd"; - } - if (self.lastNeed > 2 && buf.length > 2) { - if ((buf[2] & 0xc0) !== 0x80) { - self.lastNeed = 2; - return "\ufffd"; - } - } - } -} - -/* - * Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. - * */ -function utf8FillLastComplete( - this: StringDecoderBase, - buf: Buffer, -): string | undefined { - const p = this.lastTotal - this.lastNeed; - const r = utf8CheckExtraBytes(this, buf); - if (r !== undefined) return r; - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, p, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, p, 0, buf.length); - this.lastNeed -= buf.length; -} - -/* - * Attempts to complete a partial non-UTF-8 character using bytes from a Buffer - * */ -function utf8FillLastIncomplete( - this: StringDecoderBase, - buf: Buffer, -): string | undefined { - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); - this.lastNeed -= buf.length; -} - -/* - * Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a - * partial character, the character's bytes are buffered until the required - * number of bytes are available. - * */ -function utf8Text(this: StringDecoderBase, buf: Buffer, i: number): string { - const total = utf8CheckIncomplete(this, buf, i); - if (!this.lastNeed) return buf.toString("utf8", i); - this.lastTotal = total; - const end = buf.length - (total - this.lastNeed); - buf.copy(this.lastChar, 0, end); - return buf.toString("utf8", i, end); -} - -/* - * For UTF-8, a replacement character is added when ending on a partial - * character. - * */ -function utf8End(this: Utf8Decoder, buf?: Buffer): string { - const r = buf && buf.length ? this.write(buf) : ""; - if (this.lastNeed) return r + "\ufffd"; - return r; -} - -function utf8Write( - this: Utf8Decoder | Base64Decoder, - buf: Buffer | string, -): string { - if (typeof buf === "string") { - return buf; - } - if (buf.length === 0) return ""; - let r; - let i; - if (this.lastNeed) { - r = this.fillLast(buf); - if (r === undefined) return ""; - i = this.lastNeed; - this.lastNeed = 0; - } else { - i = 0; - } - if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); - return r || ""; -} - -function base64Text(this: StringDecoderBase, buf: Buffer, i: number): string { - const n = (buf.length - i) % 3; - if (n === 0) return buf.toString("base64", i); - this.lastNeed = 3 - n; - this.lastTotal = 3; - if (n === 1) { - this.lastChar[0] = buf[buf.length - 1]; - } else { - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - } - return buf.toString("base64", i, buf.length - n); -} - -function base64End(this: Base64Decoder, buf?: Buffer): string { - const r = buf && buf.length ? this.write(buf) : ""; - if (this.lastNeed) { - return r + this.lastChar.toString("base64", 0, 3 - this.lastNeed); - } - return r; -} - -function simpleWrite( - this: StringDecoderBase, - buf: Buffer | string, -): string { - if (typeof buf === "string") { - return buf; - } - return buf.toString(this.encoding); -} - -function simpleEnd(this: GenericDecoder, buf?: Buffer): string { - return buf && buf.length ? this.write(buf) : ""; -} - -class StringDecoderBase { - public lastChar: Buffer; - public lastNeed = 0; - public lastTotal = 0; - constructor(public encoding: string, nb: number) { - this.lastChar = Buffer.allocUnsafe(nb); - } -} - -class Base64Decoder extends StringDecoderBase { - public end = base64End; - public fillLast = utf8FillLastIncomplete; - public text = base64Text; - public write = utf8Write; - - constructor(encoding?: string) { - super(normalizeEncoding(encoding), 3); - } -} - -class GenericDecoder extends StringDecoderBase { - public end = simpleEnd; - public fillLast = undefined; - public text = utf8Text; - public write = simpleWrite; - - constructor(encoding?: string) { - super(normalizeEncoding(encoding), 4); - } -} - -class Utf8Decoder extends StringDecoderBase { - public end = utf8End; - public fillLast = utf8FillLastComplete; - public text = utf8Text; - public write = utf8Write; - - constructor(encoding?: string) { - super(normalizeEncoding(encoding), 4); - } -} - -/* - * StringDecoder provides an interface for efficiently splitting a series of - * buffers into a series of JS strings without breaking apart multi-byte - * characters. - * */ -export class StringDecoder { - public encoding: string; - public end: (buf?: Buffer) => string; - public fillLast: ((buf: Buffer) => string | undefined) | undefined; - public lastChar: Buffer; - public lastNeed: number; - public lastTotal: number; - public text: (buf: Buffer, n: number) => string; - public write: (buf: Buffer) => string; - - constructor(encoding?: string) { - let decoder; - switch (encoding) { - case "utf8": - decoder = new Utf8Decoder(encoding); - break; - case "base64": - decoder = new Base64Decoder(encoding); - break; - default: - decoder = new GenericDecoder(encoding); - } - this.encoding = decoder.encoding; - this.end = decoder.end; - this.fillLast = decoder.fillLast; - this.lastChar = decoder.lastChar; - this.lastNeed = decoder.lastNeed; - this.lastTotal = decoder.lastTotal; - this.text = decoder.text; - this.write = decoder.write; - } -} - -export default { StringDecoder }; diff --git a/std/node/string_decoder_test.ts b/std/node/string_decoder_test.ts deleted file mode 100644 index 70f50820d..000000000 --- a/std/node/string_decoder_test.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import { Buffer } from "./buffer.ts"; -import { StringDecoder } from "./string_decoder.ts"; - -Deno.test({ - name: "String decoder is encoding utf8 correctly", - fn() { - let decoder; - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.write(Buffer.from("E1", "hex")), ""); - assertEquals(decoder.end(), "\ufffd"); - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.write(Buffer.from("E18B", "hex")), ""); - assertEquals(decoder.end(), "\ufffd"); - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.write(Buffer.from("\ufffd")), "\ufffd"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("utf8"); - assertEquals( - decoder.write(Buffer.from("\ufffd\ufffd\ufffd")), - "\ufffd\ufffd\ufffd", - ); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.write(Buffer.from("EFBFBDE2", "hex")), "\ufffd"); - assertEquals(decoder.end(), "\ufffd"); - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.write(Buffer.from("F1", "hex")), ""); - assertEquals(decoder.write(Buffer.from("41F2", "hex")), "\ufffdA"); - assertEquals(decoder.end(), "\ufffd"); - - decoder = new StringDecoder("utf8"); - assertEquals(decoder.text(Buffer.from([0x41]), 2), ""); - }, -}); - -Deno.test({ - name: "String decoder is encoding base64 correctly", - fn() { - let decoder; - - decoder = new StringDecoder("base64"); - assertEquals(decoder.write(Buffer.from("E1", "hex")), "4Q=="); - assertEquals(decoder.end(), "4QAA"); - - decoder = new StringDecoder("base64"); - assertEquals(decoder.write(Buffer.from("E18B", "hex")), "4Ys="); - assertEquals(decoder.end(), "4YsA"); - - decoder = new StringDecoder("base64"); - assertEquals(decoder.write(Buffer.from("\ufffd")), "77+9"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("base64"); - assertEquals( - decoder.write(Buffer.from("\ufffd\ufffd\ufffd")), - "77+977+977+9", - ); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("base64"); - assertEquals(decoder.write(Buffer.from("EFBFBDE2", "hex")), "77+94g=="); - assertEquals(decoder.end(), "4gAA"); - - decoder = new StringDecoder("base64"); - assertEquals(decoder.write(Buffer.from("F1", "hex")), "8Q=="); - assertEquals(decoder.write(Buffer.from("41F2", "hex")), "8UHy"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("base64"); - assertEquals(decoder.text(Buffer.from([0x41]), 2), "QQ=="); - }, -}); - -Deno.test({ - name: "String decoder is encoding hex correctly", - fn() { - let decoder; - - decoder = new StringDecoder("hex"); - assertEquals(decoder.write(Buffer.from("E1", "hex")), "e1"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals(decoder.write(Buffer.from("E18B", "hex")), "e18b"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals(decoder.write(Buffer.from("\ufffd")), "efbfbd"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals( - decoder.write(Buffer.from("\ufffd\ufffd\ufffd")), - "efbfbdefbfbdefbfbd", - ); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals(decoder.write(Buffer.from("EFBFBDE2", "hex")), "efbfbde2"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals(decoder.write(Buffer.from("F1", "hex")), "f1"); - assertEquals(decoder.write(Buffer.from("41F2", "hex")), "41f2"); - assertEquals(decoder.end(), ""); - - decoder = new StringDecoder("hex"); - assertEquals(decoder.text(Buffer.from([0x41]), 2), ""); - }, -}); diff --git a/std/node/tests/cjs/cjs_a.js b/std/node/tests/cjs/cjs_a.js deleted file mode 100644 index b2dae2b6b..000000000 --- a/std/node/tests/cjs/cjs_a.js +++ /dev/null @@ -1,11 +0,0 @@ -// deno-lint-ignore-file no-undef -// deno-lint-ignore-file -const { helloB } = require("./cjs_b.js"); -const C = require("./subdir/cjs_c"); -const leftPad = require("left-pad"); - -function helloA() { - return "A"; -} - -module.exports = { helloA, helloB, C, leftPad }; diff --git a/std/node/tests/cjs/cjs_b.js b/std/node/tests/cjs/cjs_b.js deleted file mode 100644 index 2bbf75809..000000000 --- a/std/node/tests/cjs/cjs_b.js +++ /dev/null @@ -1,6 +0,0 @@ -function helloB() { - return "B"; -} - -// deno-lint-ignore no-undef -module.exports = { helloB }; diff --git a/std/node/tests/cjs/cjs_builtin.js b/std/node/tests/cjs/cjs_builtin.js deleted file mode 100644 index 3a971f605..000000000 --- a/std/node/tests/cjs/cjs_builtin.js +++ /dev/null @@ -1,11 +0,0 @@ -// deno-lint-ignore-file no-undef -// deno-lint-ignore-file -const fs = require("fs"); -const util = require("util"); -const path = require("path"); - -module.exports = { - readFileSync: fs.readFileSync, - isNull: util.isNull, - extname: path.extname, -}; diff --git a/std/node/tests/cjs/cjs_cycle_a.js b/std/node/tests/cjs/cjs_cycle_a.js deleted file mode 100644 index d73da20b9..000000000 --- a/std/node/tests/cjs/cjs_cycle_a.js +++ /dev/null @@ -1,4 +0,0 @@ -// deno-lint-ignore-file no-undef -module.exports = false; -require("./cjs_cycle_a"); -module.exports = true; diff --git a/std/node/tests/cjs/cjs_cycle_b.js b/std/node/tests/cjs/cjs_cycle_b.js deleted file mode 100644 index bd18094ce..000000000 --- a/std/node/tests/cjs/cjs_cycle_b.js +++ /dev/null @@ -1,4 +0,0 @@ -// deno-lint-ignore-file no-undef -module.exports = false; -require("./cjs_cycle_b"); -module.exports = true; diff --git a/std/node/tests/cjs/cjs_throw.js b/std/node/tests/cjs/cjs_throw.js deleted file mode 100644 index 3def8cc85..000000000 --- a/std/node/tests/cjs/cjs_throw.js +++ /dev/null @@ -1,6 +0,0 @@ -function hello() { - throw new Error("bye"); -} - -// deno-lint-ignore no-undef -module.exports = { hello }; diff --git a/std/node/tests/cjs/dir b/std/node/tests/cjs/dir deleted file mode 120000 index abec30059..000000000 --- a/std/node/tests/cjs/dir +++ /dev/null @@ -1 +0,0 @@ -./subdir/dir
\ No newline at end of file diff --git a/std/node/tests/cjs/index.js b/std/node/tests/cjs/index.js deleted file mode 100644 index d55928a89..000000000 --- a/std/node/tests/cjs/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// deno-lint-ignore no-undef -module.exports = { isIndex: true }; diff --git a/std/node/tests/cjs/subdir/cjs_c.js b/std/node/tests/cjs/subdir/cjs_c.js deleted file mode 100644 index b24caa0c4..000000000 --- a/std/node/tests/cjs/subdir/cjs_c.js +++ /dev/null @@ -1,2 +0,0 @@ -// deno-lint-ignore no-undef -module.exports = "C"; diff --git a/std/node/tests/cjs/subdir/dir/index.js b/std/node/tests/cjs/subdir/dir/index.js deleted file mode 100644 index 0b4d11386..000000000 --- a/std/node/tests/cjs/subdir/dir/index.js +++ /dev/null @@ -1,4 +0,0 @@ -// deno-lint-ignore-file no-undef -const C = require("../cjs_c"); - -module.exports = { C }; diff --git a/std/node/tests/node_modules/left-pad/README.md b/std/node/tests/node_modules/left-pad/README.md deleted file mode 100644 index e86ca7cc5..000000000 --- a/std/node/tests/node_modules/left-pad/README.md +++ /dev/null @@ -1,36 +0,0 @@ -## left-pad - -String left pad - -[![Build Status][travis-image]][travis-url] - -## Install - -```bash -$ npm install left-pad -``` - -## Usage - -```js -const leftPad = require('left-pad') - -leftPad('foo', 5) -// => " foo" - -leftPad('foobar', 6) -// => "foobar" - -leftPad(1, 2, '0') -// => "01" - -leftPad(17, 5, 0) -// => "00017" -``` - -**NOTE:** The third argument should be a single `char`. However the module doesn't throw an error if you supply more than one `char`s. See [#28](https://github.com/stevemao/left-pad/pull/28). - -**NOTE:** Characters having code points outside of [BMP plan](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane) are considered a two distinct characters. See [#58](https://github.com/stevemao/left-pad/issues/58). - -[travis-image]: https://travis-ci.org/stevemao/left-pad.svg?branch=master -[travis-url]: https://travis-ci.org/stevemao/left-pad diff --git a/std/node/tests/node_modules/left-pad/index.js b/std/node/tests/node_modules/left-pad/index.js deleted file mode 100644 index 8501bca1b..000000000 --- a/std/node/tests/node_modules/left-pad/index.js +++ /dev/null @@ -1,52 +0,0 @@ -/* This program is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://www.wtfpl.net/ for more details. */ -"use strict"; -module.exports = leftPad; - -var cache = [ - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " " -]; - -function leftPad(str, len, ch) { - // convert `str` to a `string` - str = str + ""; - // `len` is the `pad`'s length now - len = len - str.length; - // doesn't need to pad - if (len <= 0) return str; - // `ch` defaults to `' '` - if (!ch && ch !== 0) ch = " "; - // convert `ch` to a `string` cuz it could be a number - ch = ch + ""; - // cache common use cases - if (ch === " " && len < 10) return cache[len] + str; - // `pad` starts with an empty string - var pad = ""; - // loop - while (true) { - // add `ch` to `pad` if `len` is odd - if (len & 1) pad += ch; - // divide `len` by 2, ditch the remainder - len >>= 1; - // "double" the `ch` so this operation count grows logarithmically on `len` - // each time `ch` is "doubled", the `len` would need to be "doubled" too - // similar to finding a value in binary search tree, hence O(log(n)) - if (len) ch += ch; - // `len` is 0, exit the loop - else break; - } - // pad `str`! - return pad + str; -} diff --git a/std/node/tests/node_modules/left-pad/package.json b/std/node/tests/node_modules/left-pad/package.json deleted file mode 100644 index 57be04271..000000000 --- a/std/node/tests/node_modules/left-pad/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "_from": "left-pad", - "_id": "left-pad@1.3.0", - "_inBundle": false, - "_integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "_location": "/left-pad", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "left-pad", - "name": "left-pad", - "escapedName": "left-pad", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "_shasum": "5b8a3a7765dfe001261dde915589e782f8c94d1e", - "_spec": "left-pad", - "_where": "/Users/kun/Projects/Deno/deno/std/node/tests", - "author": { - "name": "azer" - }, - "bugs": { - "url": "https://github.com/stevemao/left-pad/issues" - }, - "bundleDependencies": false, - "deprecated": "use String.prototype.padStart()", - "description": "String left pad", - "devDependencies": { - "benchmark": "^2.1.0", - "fast-check": "0.0.8", - "tape": "*" - }, - "homepage": "https://github.com/stevemao/left-pad#readme", - "keywords": [ - "leftpad", - "left", - "pad", - "padding", - "string", - "repeat" - ], - "license": "WTFPL", - "main": "index.js", - "maintainers": [ - { - "name": "Cameron Westland", - "email": "camwest@gmail.com" - } - ], - "name": "left-pad", - "repository": { - "url": "git+ssh://git@github.com/stevemao/left-pad.git", - "type": "git" - }, - "scripts": { - "bench": "node perf/perf.js", - "test": "node test" - }, - "types": "index.d.ts", - "version": "1.3.0" -} diff --git a/std/node/tests/package.json b/std/node/tests/package.json deleted file mode 100644 index 08c54d588..000000000 --- a/std/node/tests/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "deno_std_node", - "version": "0.0.1", - "description": "", - "main": "index.js", - "dependencies": { - "left-pad": "^1.3.0" - }, - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC" -} diff --git a/std/node/timers.ts b/std/node/timers.ts deleted file mode 100644 index e81f7e76b..000000000 --- a/std/node/timers.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// TODO(bartlomieju): implement the 'NodeJS.Timeout' and 'NodeJS.Immediate' versions of the timers. -// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1163ead296d84e7a3c80d71e7c81ecbd1a130e9a/types/node/v12/globals.d.ts#L1120-L1131 -export const setTimeout = globalThis.setTimeout; -export const clearTimeout = globalThis.clearTimeout; -export const setInterval = globalThis.setInterval; -export const clearInterval = globalThis.clearInterval; -export const setImmediate = ( - // deno-lint-ignore no-explicit-any - cb: (...args: any[]) => void, - // deno-lint-ignore no-explicit-any - ...args: any[] -): number => globalThis.setTimeout(cb, 0, ...args); -export const clearImmediate = globalThis.clearTimeout; - -export default { - setTimeout, - clearTimeout, - setInterval, - clearInterval, - setImmediate, - clearImmediate, -}; diff --git a/std/node/url.ts b/std/node/url.ts deleted file mode 100644 index 9d2fbe757..000000000 --- a/std/node/url.ts +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -import { - CHAR_BACKWARD_SLASH, - CHAR_FORWARD_SLASH, - CHAR_LOWERCASE_A, - CHAR_LOWERCASE_Z, -} from "../path/_constants.ts"; -import * as path from "./path.ts"; -import { isWindows } from "../_util/os.ts"; - -const forwardSlashRegEx = /\//g; -const percentRegEx = /%/g; -const backslashRegEx = /\\/g; -const newlineRegEx = /\n/g; -const carriageReturnRegEx = /\r/g; -const tabRegEx = /\t/g; - -const _url = URL; -export { _url as URL }; - -/** - * Get fully resolved platform-specific file path from the given URL string/ object - * @param path The file URL string or URL object to convert to a path - */ -export function fileURLToPath(path: string | URL): string { - if (typeof path === "string") path = new URL(path); - else if (!(path instanceof URL)) { - throw new Deno.errors.InvalidData( - "invalid argument path , must be a string or URL", - ); - } - if (path.protocol !== "file:") { - throw new Deno.errors.InvalidData("invalid url scheme"); - } - return isWindows ? getPathFromURLWin(path) : getPathFromURLPosix(path); -} - -function getPathFromURLWin(url: URL): string { - const hostname = url.hostname; - let pathname = url.pathname; - for (let n = 0; n < pathname.length; n++) { - if (pathname[n] === "%") { - const third = pathname.codePointAt(n + 2) || 0x20; - if ( - (pathname[n + 1] === "2" && third === 102) || // 2f 2F / - (pathname[n + 1] === "5" && third === 99) - ) { - // 5c 5C \ - throw new Deno.errors.InvalidData( - "must not include encoded \\ or / characters", - ); - } - } - } - - pathname = pathname.replace(forwardSlashRegEx, "\\"); - pathname = decodeURIComponent(pathname); - if (hostname !== "") { - // TODO(bartlomieju): add support for punycode encodings - return `\\\\${hostname}${pathname}`; - } else { - // Otherwise, it's a local path that requires a drive letter - const letter = pathname.codePointAt(1)! | 0x20; - const sep = pathname[2]; - if ( - letter < CHAR_LOWERCASE_A || - letter > CHAR_LOWERCASE_Z || // a..z A..Z - sep !== ":" - ) { - throw new Deno.errors.InvalidData("file url path must be absolute"); - } - return pathname.slice(1); - } -} - -function getPathFromURLPosix(url: URL): string { - if (url.hostname !== "") { - throw new Deno.errors.InvalidData("invalid file url hostname"); - } - const pathname = url.pathname; - for (let n = 0; n < pathname.length; n++) { - if (pathname[n] === "%") { - const third = pathname.codePointAt(n + 2) || 0x20; - if (pathname[n + 1] === "2" && third === 102) { - throw new Deno.errors.InvalidData( - "must not include encoded / characters", - ); - } - } - } - return decodeURIComponent(pathname); -} - -/** Get fully resolved platform-specific File URL from the given file path */ -export function pathToFileURL(filepath: string): URL { - let resolved = path.resolve(filepath); - // path.resolve strips trailing slashes so we must add them back - const filePathLast = filepath.charCodeAt(filepath.length - 1); - if ( - (filePathLast === CHAR_FORWARD_SLASH || - (isWindows && filePathLast === CHAR_BACKWARD_SLASH)) && - resolved[resolved.length - 1] !== path.sep - ) { - resolved += "/"; - } - const outURL = new URL("file://"); - if (resolved.includes("%")) resolved = resolved.replace(percentRegEx, "%25"); - // In posix, "/" is a valid character in paths - if (!isWindows && resolved.includes("\\")) { - resolved = resolved.replace(backslashRegEx, "%5C"); - } - if (resolved.includes("\n")) resolved = resolved.replace(newlineRegEx, "%0A"); - if (resolved.includes("\r")) { - resolved = resolved.replace(carriageReturnRegEx, "%0D"); - } - if (resolved.includes("\t")) resolved = resolved.replace(tabRegEx, "%09"); - outURL.pathname = resolved; - return outURL; -} - -export default { - fileURLToPath, - pathToFileURL, - URL, -}; diff --git a/std/node/url_test.ts b/std/node/url_test.ts deleted file mode 100644 index 7da8e3bb4..000000000 --- a/std/node/url_test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import * as url from "./url.ts"; - -Deno.test({ - name: "[url] URL", - fn() { - assertEquals(url.URL, URL); - }, -}); diff --git a/std/node/util.ts b/std/node/util.ts deleted file mode 100644 index cbc1e11c5..000000000 --- a/std/node/util.ts +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -export { promisify } from "./_util/_util_promisify.ts"; -export { callbackify } from "./_util/_util_callbackify.ts"; -import { ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, errorMap } from "./_errors.ts"; -import * as types from "./_util/_util_types.ts"; -export { types }; - -const NumberIsSafeInteger = Number.isSafeInteger; - -const DEFAULT_INSPECT_OPTIONS = { - showHidden: false, - depth: 2, - colors: false, - customInspect: true, - showProxy: false, - maxArrayLength: 100, - maxStringLength: Infinity, - breakLength: 80, - compact: 3, - sorted: false, - getters: false, -}; - -inspect.defaultOptions = DEFAULT_INSPECT_OPTIONS; -inspect.custom = Deno.customInspect; - -// TODO(schwarzkopfb): make it in-line with Node's implementation -// Ref: https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_inspect_object_options -// deno-lint-ignore no-explicit-any -export function inspect(object: unknown, ...opts: any): string { - opts = { ...DEFAULT_INSPECT_OPTIONS, ...opts }; - return Deno.inspect(object, { - depth: opts.depth, - iterableLimit: opts.maxArrayLength, - compact: !!opts.compact, - sorted: !!opts.sorted, - showProxy: !!opts.showProxy, - }); -} - -/** @deprecated - use `Array.isArray()` instead. */ -export function isArray(value: unknown): boolean { - return Array.isArray(value); -} - -/** @deprecated - use `typeof value === "boolean" || value instanceof Boolean` instead. */ -export function isBoolean(value: unknown): boolean { - return typeof value === "boolean" || value instanceof Boolean; -} - -/** @deprecated - use `value === null` instead. */ -export function isNull(value: unknown): boolean { - return value === null; -} - -/** @deprecated - use `value === null || value === undefined` instead. */ -export function isNullOrUndefined(value: unknown): boolean { - return value === null || value === undefined; -} - -/** @deprecated - use `typeof value === "number" || value instanceof Number` instead. */ -export function isNumber(value: unknown): boolean { - return typeof value === "number" || value instanceof Number; -} - -/** @deprecated - use `typeof value === "string" || value instanceof String` instead. */ -export function isString(value: unknown): boolean { - return typeof value === "string" || value instanceof String; -} - -/** @deprecated - use `typeof value === "symbol"` instead. */ -export function isSymbol(value: unknown): boolean { - return typeof value === "symbol"; -} - -/** @deprecated - use `value === undefined` instead. */ -export function isUndefined(value: unknown): boolean { - return value === undefined; -} - -/** @deprecated - use `value !== null && typeof value === "object"` instead. */ -export function isObject(value: unknown): boolean { - return value !== null && typeof value === "object"; -} - -/** @deprecated - use `e instanceof Error` instead. */ -export function isError(e: unknown): boolean { - return e instanceof Error; -} - -/** @deprecated - use `typeof value === "function"` instead. */ -export function isFunction(value: unknown): boolean { - return typeof value === "function"; -} - -/** @deprecated - use `value instanceof RegExp` instead. */ -export function isRegExp(value: unknown): boolean { - return value instanceof RegExp; -} - -/** @deprecated - use `value === null || (typeof value !== "object" && typeof value !== "function")` instead. */ -export function isPrimitive(value: unknown): boolean { - return ( - value === null || (typeof value !== "object" && typeof value !== "function") - ); -} - -/** - * Returns a system error name from an error code number. - * @param code error code number - */ -export function getSystemErrorName(code: number): string | undefined { - if (typeof code !== "number") { - throw new ERR_INVALID_ARG_TYPE("err", "number", code); - } - if (code >= 0 || !NumberIsSafeInteger(code)) { - throw new ERR_OUT_OF_RANGE("err", "a negative integer", code); - } - return errorMap.get(code)?.[0]; -} - -/** - * https://nodejs.org/api/util.html#util_util_deprecate_fn_msg_code - * @param _code This implementation of deprecate won't apply the deprecation code - */ -export function deprecate<A extends Array<unknown>, B>( - this: unknown, - callback: (...args: A) => B, - msg: string, - _code?: string, -) { - return function (this: unknown, ...args: A) { - console.warn(msg); - return callback.apply(this, args); - }; -} - -import { _TextDecoder, _TextEncoder } from "./_utils.ts"; - -/** The global TextDecoder */ -export type TextDecoder = import("./_utils.ts")._TextDecoder; -export const TextDecoder = _TextDecoder; - -/** The global TextEncoder */ -export type TextEncoder = import("./_utils.ts")._TextEncoder; -export const TextEncoder = _TextEncoder; - -export default { - inspect, - isArray, - isBoolean, - isNull, - isNullOrUndefined, - isNumber, - isString, - isSymbol, - isUndefined, - isObject, - isError, - isFunction, - isRegExp, - isPrimitive, - getSystemErrorName, - deprecate, - TextDecoder, - TextEncoder, -}; diff --git a/std/node/util_test.ts b/std/node/util_test.ts deleted file mode 100644 index 893994559..000000000 --- a/std/node/util_test.ts +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { - assert, - assertEquals, - assertStrictEquals, - assertThrows, -} from "../testing/asserts.ts"; -import { stripColor } from "../fmt/colors.ts"; -import * as util from "./util.ts"; - -Deno.test({ - name: "[util] inspect", - fn() { - assertEquals(stripColor(util.inspect({ foo: 123 })), "{ foo: 123 }"); - }, -}); - -Deno.test({ - name: "[util] isBoolean", - fn() { - assert(util.isBoolean(true)); - assert(util.isBoolean(new Boolean())); - assert(util.isBoolean(new Boolean(true))); - assert(util.isBoolean(false)); - assert(!util.isBoolean("deno")); - assert(!util.isBoolean("true")); - }, -}); - -Deno.test({ - name: "[util] isNull", - fn() { - let n; - assert(util.isNull(null)); - assert(!util.isNull(n)); - assert(!util.isNull(0)); - assert(!util.isNull({})); - }, -}); - -Deno.test({ - name: "[util] isNullOrUndefined", - fn() { - let n; - assert(util.isNullOrUndefined(null)); - assert(util.isNullOrUndefined(n)); - assert(!util.isNullOrUndefined({})); - assert(!util.isNullOrUndefined("undefined")); - }, -}); - -Deno.test({ - name: "[util] isNumber", - fn() { - assert(util.isNumber(666)); - assert(util.isNumber(new Number(666))); - assert(!util.isNumber("999")); - assert(!util.isNumber(null)); - }, -}); - -Deno.test({ - name: "[util] isString", - fn() { - assert(util.isString("deno")); - assert(util.isString(new String("DIO"))); - assert(!util.isString(1337)); - }, -}); - -Deno.test({ - name: "[util] isSymbol", - fn() { - assert(util.isSymbol(Symbol())); - assert(!util.isSymbol(123)); - assert(!util.isSymbol("string")); - }, -}); - -Deno.test({ - name: "[util] isUndefined", - fn() { - let t; - assert(util.isUndefined(t)); - assert(!util.isUndefined("undefined")); - assert(!util.isUndefined({})); - }, -}); - -Deno.test({ - name: "[util] isObject", - fn() { - const dio = { stand: "Za Warudo" }; - assert(util.isObject(dio)); - assert(util.isObject(new RegExp(/Toki Wo Tomare/))); - assert(!util.isObject("Jotaro")); - }, -}); - -Deno.test({ - name: "[util] isError", - fn() { - const java = new Error(); - const nodejs = new TypeError(); - const deno = "Future"; - assert(util.isError(java)); - assert(util.isError(nodejs)); - assert(!util.isError(deno)); - }, -}); - -Deno.test({ - name: "[util] isFunction", - fn() { - const f = function (): void {}; - assert(util.isFunction(f)); - assert(!util.isFunction({})); - assert(!util.isFunction(new RegExp(/f/))); - }, -}); - -Deno.test({ - name: "[util] isRegExp", - fn() { - assert(util.isRegExp(new RegExp(/f/))); - assert(util.isRegExp(/fuManchu/)); - assert(!util.isRegExp({ evil: "eye" })); - assert(!util.isRegExp(null)); - }, -}); - -Deno.test({ - name: "[util] isArray", - fn() { - assert(util.isArray([])); - assert(!util.isArray({ yaNo: "array" })); - assert(!util.isArray(null)); - }, -}); - -Deno.test({ - name: "[util] isPrimitive", - fn() { - const stringType = "hasti"; - const booleanType = true; - const integerType = 2; - const symbolType = Symbol("anything"); - - const functionType = function doBest(): void {}; - const objectType = { name: "ali" }; - const arrayType = [1, 2, 3]; - - assert(util.isPrimitive(stringType)); - assert(util.isPrimitive(booleanType)); - assert(util.isPrimitive(integerType)); - assert(util.isPrimitive(symbolType)); - assert(util.isPrimitive(null)); - assert(util.isPrimitive(undefined)); - assert(!util.isPrimitive(functionType)); - assert(!util.isPrimitive(arrayType)); - assert(!util.isPrimitive(objectType)); - }, -}); - -Deno.test({ - name: "[util] TextDecoder", - fn() { - assert(util.TextDecoder === TextDecoder); - const td: util.TextDecoder = new util.TextDecoder(); - assert(td instanceof TextDecoder); - }, -}); - -Deno.test({ - name: "[util] TextEncoder", - fn() { - assert(util.TextEncoder === TextEncoder); - const te: util.TextEncoder = new util.TextEncoder(); - assert(te instanceof TextEncoder); - }, -}); - -Deno.test({ - name: "[util] isDate", - fn() { - // Test verifies the method is exposed. See _util/_util_types_test for details - assert(util.types.isDate(new Date())); - }, -}); - -Deno.test({ - name: "[util] getSystemErrorName()", - fn() { - type FnTestInvalidArg = (code?: unknown) => void; - - assertThrows( - () => (util.getSystemErrorName as FnTestInvalidArg)(), - TypeError, - ); - assertThrows( - () => (util.getSystemErrorName as FnTestInvalidArg)(1), - RangeError, - ); - - assertStrictEquals(util.getSystemErrorName(-424242), undefined); - - switch (Deno.build.os) { - case "windows": - assertStrictEquals(util.getSystemErrorName(-4091), "EADDRINUSE"); - break; - - case "darwin": - assertStrictEquals(util.getSystemErrorName(-48), "EADDRINUSE"); - break; - - case "linux": - assertStrictEquals(util.getSystemErrorName(-98), "EADDRINUSE"); - break; - } - }, -}); - -Deno.test("[util] deprecate", () => { - const warn = console.warn.bind(null); - - let output; - console.warn = function (str: string) { - output = str; - warn(output); - }; - - const message = "x is deprecated"; - - const expected = 12; - let result; - const x = util.deprecate(() => { - result = expected; - }, message); - - x(); - - assertEquals(expected, result); - assertEquals(output, message); - - console.warn = warn; -}); |