diff --git a/API.md b/API.md index 6294f4348c..768de2d71c 100644 --- a/API.md +++ b/API.md @@ -153,6 +153,78 @@ _Also available globally_ [clearTimeout](https://nodejs.org/api/timers.html#cleartimeouttimeout) +## url +```typescript +export class URL { + constructor(input: string, base?: string | URL); + + hash: string; + host: string; + hostname: string; + href: string; + origin: string; + password: string; + pathname: string; + port: string; + protocol: string; + search: string; + searchParams: URLSearchParams; + username: string; + + canParse(input: string, base?: string): boolean; + toString(): string; +} +``` + +### TODO, URL see tracking [ticket](https://github.com/awslabs/llrt/issues/303): + +```typescript +// Additional utilities in the URL module +export function domainToASCII(domain: string): string; + +export function domainToUnicode(domain: string): string; + +export function fileURLToPath(url: string | URL): string; + +export function pathToFileURL(path: string): URL; + +export function urlToHttpOptions(url: URL): { + protocol?: string; + hostname?: string; + port?: string; + path?: string; +}; +``` + +## URLSearchParams +```typescript +export class URLSearchParams { + constructor(init?: string | string[][] | Record | URLSearchParams); + + // Methods + append(name: string, value: string): void; + delete(name: string): void; + get(name: string): string | null; + getAll(name: string): string[]; + has(name: string): boolean; + set(name: string, value: string): void; + sort(): void; + + [Symbol.iterator](): IterableIterator<[string, string]>; + entries(): IterableIterator<[string, string]>; + values(): IterableIterator; + + toString(): string; +} +``` + + +### TODO, URLSearchParams see tracking [ticket](https://github.com/awslabs/llrt/issues/307): + +```typescript +URLSearchParams.sort(): void; +``` + ## util > [!IMPORTANT] diff --git a/build.mjs b/build.mjs index d01a6ae6a9..1b5338b7a8 100644 --- a/build.mjs +++ b/build.mjs @@ -68,6 +68,7 @@ const ES_BUILD_OPTIONS = { "buffer", "xml", "net", + "url" ], }; @@ -570,7 +571,7 @@ async function buildLibrary() { await esbuild.build({ ...defaultLibEsBuildOption, entryPoints: testEntryPoints, - external: [...ES_BUILD_OPTIONS.external, "@aws-sdk", "@smithy", "uuid"], + external: [...ES_BUILD_OPTIONS.external, "@aws-sdk", "@smithy"], }); } diff --git a/llrt b/llrt new file mode 100755 index 0000000000..e021dbdb5d Binary files /dev/null and b/llrt differ diff --git a/src/http/mod.rs b/src/http/mod.rs index 2daacf0b06..1f2039bf8b 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -6,8 +6,8 @@ mod fetch; mod headers; mod request; mod response; -mod url; -mod url_search_params; +pub mod url; +pub mod url_search_params; use rquickjs::{Class, Ctx, Result}; diff --git a/src/http/url.rs b/src/http/url.rs index 7a9468473d..2c608a32e9 100644 --- a/src/http/url.rs +++ b/src/http/url.rs @@ -58,14 +58,31 @@ impl<'js> URL<'js> { } #[qjs(static)] - pub fn can_parse(input: Value<'js>) -> bool { - if input.is_string() { - match input.get::() { - Ok(string_val) => Url::parse(&string_val).is_ok(), - Err(_) => false, + pub fn can_parse(ctx: Ctx<'js>, input: Value<'js>, base: Opt>) -> bool { + if let Some(base) = base.0 { + let base_string = match get_string(&ctx, base) { + Ok(s) => s, + Err(_) => return false, + }; + let path_string = match get_string(&ctx, input) { + Ok(s) => s, + Err(_) => return false, + }; + + match base_string.parse::() { + Ok(base_url) => base_url.join(&path_string).is_ok(), + Err(_) => false, // Base URL parsing failed } } else { - false + // Handle the case where base is not provided + if input.is_string() { + match input.get::() { + Ok(string_val) => Url::parse(&string_val).is_ok(), + Err(_) => false, + } + } else { + false + } } } diff --git a/src/main.rs b/src/main.rs index 31cddfe932..305f382439 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,7 @@ mod security; mod stream; mod test_utils; mod timers; +mod url; mod utils; mod uuid; mod vm; diff --git a/src/url.rs b/src/url.rs new file mode 100644 index 0000000000..5046a06c80 --- /dev/null +++ b/src/url.rs @@ -0,0 +1,34 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{ + function::Constructor, + module::{Declarations, Exports, ModuleDef}, + Ctx, Result, +}; + +use crate::module::export_default; +pub struct UrlModule; + +impl ModuleDef for UrlModule { + fn declare(declare: &mut Declarations) -> Result<()> { + declare.declare(stringify!(URL))?; + declare.declare(stringify!(URLSearchParams))?; + + declare.declare("default")?; + Ok(()) + } + + fn evaluate<'js>(ctx: &Ctx<'js>, exports: &mut Exports<'js>) -> Result<()> { + let globals = ctx.globals(); + let url: Constructor = globals.get(stringify!(URL))?; + let url_search_params: Constructor = globals.get(stringify!(URLSearchParams))?; + + export_default(ctx, exports, |default| { + default.set(stringify!(URL), url)?; + default.set(stringify!(URLSearchParams), url_search_params)?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/src/vm.rs b/src/vm.rs index 22406184e6..fda74af68f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -54,6 +54,7 @@ use crate::{ path::{dirname, join_path, resolve_path, PathModule}, process::ProcessModule, timers::TimersModule, + url::UrlModule, utils::{ class::get_class_name, clone::structured_clone, @@ -128,7 +129,8 @@ create_modules!( "child_process" => ChildProcessModule, "util" => UtilModule, "uuid" => UuidModule, - "process" => ProcessModule + "process" => ProcessModule, + "url" => UrlModule ); struct ModuleInfo { diff --git a/tests/unit/http.test.ts b/tests/unit/http.test.ts index aaf5b9f635..b413c1e206 100644 --- a/tests/unit/http.test.ts +++ b/tests/unit/http.test.ts @@ -1,28 +1,80 @@ +import * as url from "url"; + +describe("url module import syntax works", () => { + it("global URL and imported URL are equal", () => { + const testUrl = "https://www.example.com"; + const moduleUrl = new url.URL(testUrl); + const globalUrl = new URL(testUrl); + expect(moduleUrl).toEqual(globalUrl); + }); + it("global URLSearchParams and imported URLSearchParams are equal", () => { + const paramsString = "topic=api&a=1&a=2&a=3"; + const moduleSearchParams = new url.URLSearchParams(paramsString); + const globalSearchParams = new URLSearchParams(paramsString); + expect(moduleSearchParams).toEqual(globalSearchParams); + }); + describe("import { URL } from 'url';", () => { + it("should parse a url hostname", () => { + const testUrl = new url.URL("https://www.example.com"); + expect(testUrl.protocol).toEqual("https:"); + expect(testUrl.host).toEqual("www.example.com"); + expect(testUrl.hostname).toEqual("www.example.com"); + }); + it("toString method works", () => { + const testUrl = new url.URL("/base", "https://www.example.com"); + expect(testUrl.toString()).toEqual("https://www.example.com/base"); + }); + it("canParse method works", () => { + const validCanParse = url.URL.canParse("https://www.example.com"); + const invalidCanParse = url.URL.canParse("not_valid"); + expect(validCanParse).toEqual(true); + expect(invalidCanParse).toEqual(false); + expect(url.URL.canParse("/foo", "https://example.org/")).toEqual(true); + }); + }); + + describe("import { URLSearchParams } from 'url';", () => { + it("supports URLSearchParams basic API", () => { + const paramsString = "topic=api&a=1&a=2&a=3"; + const searchParams = new url.URLSearchParams(paramsString); + searchParams.append("foo", "bar"); + expect(searchParams.has("topic")).toBeTruthy(); + expect(searchParams.has("foo")).toBeTruthy(); + searchParams.delete("foo"); + expect(searchParams.has("foo")).toBeFalsy(); + expect(searchParams.get("topic")).toEqual("api"); + expect(searchParams.getAll("a")).toEqual(["1", "2", "3"]); + searchParams.set("topic", "node"); + expect(searchParams.get("topic")).toEqual("node"); + }); + }); +}); + describe("Headers", () => { it("should construct a new Headers object with the provided headers", () => { const headers = { "content-type": "application/json" }; const h = new Headers(headers); - expect(h.get("Content-Type")).toEqual(headers["content-type"]) + expect(h.get("Content-Type")).toEqual(headers["content-type"]); }); it("should add headers to the Headers object", () => { const h = new Headers(); h.set("Content-Type", "application/json"); - expect(h.get("Content-Type")).toEqual("application/json") + expect(h.get("Content-Type")).toEqual("application/json"); }); it("should overwrite headers in the Headers object", () => { const headers = { "Content-Type": "application/json" }; const h = new Headers(headers); h.set("Content-Type", "text/plain"); - expect(h.get("Content-Type")).toEqual("text/plain") + expect(h.get("Content-Type")).toEqual("text/plain"); }); it("should delete headers from the Headers object", () => { const headers = { "Content-Type": "application/json" }; const h = new Headers(headers); h.delete("Content-Type"); - expect(h.get("Content-Type")).toEqual(undefined) + expect(h.get("Content-Type")).toEqual(undefined); }); it("should return an iterator over the headers", () => { @@ -33,11 +85,11 @@ describe("Headers", () => { const h = new Headers(headers); const iterator = h.entries(); let next = iterator.next(); - expect(next.value).toStrictEqual(["authorization", "Bearer 1234"]) + expect(next.value).toStrictEqual(["authorization", "Bearer 1234"]); next = iterator.next(); - expect(next.value).toStrictEqual(["content-type", "application/json"]) + expect(next.value).toStrictEqual(["content-type", "application/json"]); next = iterator.next(); - expect(next.value).toStrictEqual(undefined) + expect(next.value).toStrictEqual(undefined); }); it("should iterate over the headers with forEach", () => { @@ -46,8 +98,8 @@ describe("Headers", () => { }; const h = new Headers(headers); h.forEach((value, key) => { - expect(key).toStrictEqual("content-type") - expect(value).toStrictEqual("application/json") + expect(key).toStrictEqual("content-type"); + expect(value).toStrictEqual("application/json"); }); }); }); @@ -56,36 +108,36 @@ describe("Request", () => { it("should construct a new Request object with the provided URL", () => { const url = "https://example.com"; const request = new Request(url); - expect(request.url).toEqual(url) + expect(request.url).toEqual(url); }); it("should set the method to GET by default", () => { const request = new Request("https://example.com"); - expect(request.method).toEqual("GET") + expect(request.method).toEqual("GET"); }); it("should set the method to the provided value", () => { const method = "POST"; const request = new Request("https://example.com", { method }); - expect(request.method).toEqual(method) + expect(request.method).toEqual(method); }); it("should set the headers to an empty object by default", () => { const request = new Request("https://example.com"); const headers = new Headers(); - expect(request.headers.entries()).toEqual(headers.entries()) + expect(request.headers.entries()).toEqual(headers.entries()); }); it("should set the headers to the provided value", () => { const headers = { "Content-Type": "application/json" }; const headerValue = new Headers(headers); const request = new Request("https://example.com", { headers }); - expect(request.headers).toStrictEqual(headerValue) + expect(request.headers).toStrictEqual(headerValue); }); it("should set the body to null by default", () => { const request = new Request("https://example.com"); - expect(request.body).toEqual(null) + expect(request.body).toEqual(null); }); it("should set the body to the provided value", () => { @@ -94,7 +146,7 @@ describe("Request", () => { body, method: "POST", }); - expect(request.body).toStrictEqual(body) + expect(request.body).toStrictEqual(body); }); it("should set the body to a Blob if a Blob is provided", async () => { @@ -103,29 +155,31 @@ describe("Request", () => { body: blob, method: "POST", }); - expect(request.body).toStrictEqual(new Uint8Array(await blob.arrayBuffer())) + expect(request.body).toStrictEqual( + new Uint8Array(await blob.arrayBuffer()) + ); }); it("should accept another request object as argument", () => { const oldRequest = new Request("https://example.com", { headers: { From: "webmaster@example.org" }, }); - expect(oldRequest.headers.get("From")).toEqual("webmaster@example.org") + expect(oldRequest.headers.get("From")).toEqual("webmaster@example.org"); const newRequest = new Request(oldRequest, { headers: { From: "developer@example.org" }, }); - expect(newRequest.url).toEqual("https://example.com") - expect(newRequest.headers.get("From")).toEqual("developer@example.org") + expect(newRequest.url).toEqual("https://example.com"); + expect(newRequest.headers.get("From")).toEqual("developer@example.org"); }); }); describe("Response class", () => { it("should construct a new Response object with default values", () => { const response = new Response(); - expect(response.status).toEqual(200) - expect(response.statusText).toEqual("OK") + expect(response.status).toEqual(200); + expect(response.statusText).toEqual("OK"); expect(response.headers instanceof Headers).toBeTruthy(); - expect(response.body).toEqual(null) + expect(response.body).toEqual(null); }); it("should set the status and statusText to the provided values", () => { @@ -133,28 +187,30 @@ describe("Response class", () => { status: 404, statusText: "Not Found", }); - expect(response.status).toEqual(404) - expect(response.statusText).toEqual("Not Found") + expect(response.status).toEqual(404); + expect(response.statusText).toEqual("Not Found"); }); it("should set the headers to the provided value", () => { const headers = new Headers({ "Content-Type": "application/json" }); const response = new Response(null, { headers }); - expect(response.headers.get("Content-Type")).toStrictEqual("application/json") + expect(response.headers.get("Content-Type")).toStrictEqual( + "application/json" + ); }); it("should set the body to the provided value", async () => { const body = "Hello, world!"; const response = new Response(body); - expect(await response.text()).toStrictEqual(body) + expect(await response.text()).toStrictEqual(body); }); it("should set the body to a Blob if a Blob is provided", async () => { const blob = new Blob(["Hello, world!"], { type: "text/plain" }); const response = new Response(blob); - expect(await response.text()).toEqual("Hello, world!") + expect(await response.text()).toEqual("Hello, world!"); }); it("should set the body to a JSON object if a JSON object is provided", () => { @@ -163,21 +219,21 @@ describe("Response class", () => { headers: { "Content-Type": "application/json" }, }); return response.json().then((parsedJson) => { - expect(parsedJson).toStrictEqual(jsonBody) + expect(parsedJson).toStrictEqual(jsonBody); }); }); it("should clone the response with the clone() method", () => { const response = new Response("Original response"); const clonedResponse = response.clone(); - expect(response.body).toEqual(clonedResponse.body) - expect(response.url).toEqual(clonedResponse.url) - expect(response.status).toEqual(clonedResponse.status) - expect(response.statusText).toEqual(clonedResponse.statusText) - expect(response.headers).toEqual(clonedResponse.headers) - expect(response.type).toEqual(clonedResponse.type) - expect(response.ok).toEqual(clonedResponse.ok) - expect(response.bodyUsed).toEqual(clonedResponse.bodyUsed) + expect(response.body).toEqual(clonedResponse.body); + expect(response.url).toEqual(clonedResponse.url); + expect(response.status).toEqual(clonedResponse.status); + expect(response.statusText).toEqual(clonedResponse.statusText); + expect(response.headers).toEqual(clonedResponse.headers); + expect(response.type).toEqual(clonedResponse.type); + expect(response.ok).toEqual(clonedResponse.ok); + expect(response.bodyUsed).toEqual(clonedResponse.bodyUsed); }); it("should create a Response object with an ok status for status codes in the range 200-299", () => { @@ -194,20 +250,20 @@ describe("Response class", () => { describe("URL class", () => { it("should parse a valid URL", () => { const url = new URL("https://www.example.com"); - expect(url.protocol).toEqual("https:") - expect(url.hostname).toEqual("www.example.com") + expect(url.protocol).toEqual("https:"); + expect(url.hostname).toEqual("www.example.com"); }); it("should create a copy of a valid URL", () => { const url: any = new URL("https://www.example.com"); const url2 = new URL(url); - expect(url).toEqual(url2) - expect(url).not.toBe(url2) + expect(url).toEqual(url2); + expect(url).not.toBe(url2); }); it("should to append base to a url", () => { const url = new URL("/base", "https://www.example.com"); - expect(url.toString()).toEqual("https://www.example.com/base") + expect(url.toString()).toEqual("https://www.example.com/base"); }); it("should throw an error for an invalid URL", () => { @@ -218,40 +274,45 @@ describe("URL class", () => { it("should return the URL as a string", () => { const url = new URL("https://www.example.com"); - expect(url.toString()).toEqual("https://www.example.com/") + expect(url.toString()).toEqual("https://www.example.com/"); }); it("should parse query parameters", () => { const url = new URL("https://www.example.com/?foo=bar&baz=qux"); - expect(url.searchParams.get("foo")).toEqual("bar") - expect(url.searchParams.get("baz")).toEqual("qux") + expect(url.searchParams.get("foo")).toEqual("bar"); + expect(url.searchParams.get("baz")).toEqual("qux"); }); it("should be able to set and get port", () => { const url: any = new URL("https://www.example.com"); url.port = "1234"; - expect(url.toString()).toEqual("https://www.example.com:1234/") + expect(url.toString()).toEqual("https://www.example.com:1234/"); url.port = 5678; - expect(url.toString()).toEqual("https://www.example.com:5678/") + expect(url.toString()).toEqual("https://www.example.com:5678/"); }); it("should modify query parameters", () => { const url = new URL("https://www.example.com/?foo=bar&baz=qux"); url.searchParams.set("foo", "new-value"); - expect(url.toString()).toEqual("https://www.example.com/?baz=qux&foo=new-value") + expect(url.toString()).toEqual( + "https://www.example.com/?baz=qux&foo=new-value" + ); }); it("should parse username and password", () => { const url = new URL( "https://anonymous:flabada@developer.mozilla.org/en-US/docs/Web/API/URL/username" ); - expect(url.username).toEqual("anonymous") - expect(url.password).toEqual("flabada") + expect(url.username).toEqual("anonymous"); + expect(url.password).toEqual("flabada"); + }); + it("should provide canParse util", () => { + const validUrl = "https://www.example.com/"; + const invalidUrl = "not_a_valid_url"; + expect(URL.canParse(validUrl)).toEqual(true); + expect(URL.canParse(invalidUrl)).toEqual(false); }); - it("should provide can_parse util", () => { - const valid_url = "https://www.example.com/"; - const invalid_url = "not_a_valid_url"; - expect(URL.canParse(valid_url)).toEqual(true) - expect(URL.canParse(invalid_url)).toEqual(false) + it("canParse works for relative urls", () => { + expect(URL.canParse("/foo", "https://example.org/")).toEqual(true); }); }); @@ -279,40 +340,42 @@ describe("URLSearchParams class", () => { const searchParams = new URLSearchParams(paramsString); // TODO FB There is a bug here, searchParams.get("foo") returns undefined, it should return null // expect(searchParams.get("foo")).toBeNull() - expect(searchParams.get("foo")).toBeFalsy() + expect(searchParams.get("foo")).toBeFalsy(); }); it("should return an array of all values of the parameter if it exists", () => { const paramsString = "topic=api&a=1&a=2&a=3"; const searchParams = new URLSearchParams(paramsString); - expect(searchParams.getAll("a")).toEqual(["1", "2", "3"]) + expect(searchParams.getAll("a")).toEqual(["1", "2", "3"]); }); it("should return an empty array if the parameter doesn't exist", () => { const paramsString = "topic=api&a=1&a=2&a=3"; const searchParams = new URLSearchParams(paramsString); - expect(searchParams.getAll("foo")).toEqual([]) + expect(searchParams.getAll("foo")).toEqual([]); }); it("should add the parameter to the end of the query string", () => { const paramsString = "topic=api&a=1&a=2&a=3"; const searchParams = new URLSearchParams(paramsString); searchParams.append("topic", "webdev"); - expect(searchParams.toString()).toEqual("a=1&a=2&a=3&topic=api&topic=webdev") + expect(searchParams.toString()).toEqual( + "a=1&a=2&a=3&topic=api&topic=webdev" + ); }); it("should replace all values of the parameter with the given value", () => { const paramsString = "topic=api&a=1&a=2&a=3"; const searchParams = new URLSearchParams(paramsString); searchParams.set("topic", "More webdev"); - expect(searchParams.toString()).toEqual("a=1&a=2&a=3&topic=More+webdev") + expect(searchParams.toString()).toEqual("a=1&a=2&a=3&topic=More+webdev"); }); it("should remove the parameter from the query string", () => { const paramsString = "topic=api&a=1&a=2&a=3"; const searchParams = new URLSearchParams(paramsString); searchParams.delete("topic"); - expect(searchParams.toString()).toEqual("a=1&a=2&a=3") + expect(searchParams.toString()).toEqual("a=1&a=2&a=3"); }); it("should iterate over all parameters in the query string", () => { @@ -337,24 +400,24 @@ describe("Blob class", () => { const blobOptions = { type: "text/plain" }; const blob = new Blob(blobData, blobOptions); - expect(blob.size).toEqual(blobData[0].length) - expect(blob.type).toEqual(blobOptions.type) + expect(blob.size).toEqual(blobData[0].length); + expect(blob.type).toEqual(blobOptions.type); }); it("should create a Blob with default type if options.type is not provided", () => { const blobData = ["Hello, world!"]; const blob = new Blob(blobData); - expect(blob.size).toEqual(blobData[0].length) - expect(blob.type).toEqual("") + expect(blob.size).toEqual(blobData[0].length); + expect(blob.type).toEqual(""); }); it("should create a Blob with an empty array if no data is provided", () => { // @ts-ignore const blob = new Blob(); - expect(blob.size).toEqual(0) - expect(blob.type).toEqual("") + expect(blob.size).toEqual(0); + expect(blob.type).toEqual(""); }); it("should handle line endings properly", async () => { @@ -366,10 +429,10 @@ describe("Blob class", () => { endings: "native", }); - expect(blob.type).toEqual("") + expect(blob.type).toEqual(""); if (process.platform != "win32") { expect(blob.size < text.length).toBeTruthy(); - expect(await blob.text()).toEqual(text.replace(/\r\n/g, "\n")) + expect(await blob.text()).toEqual(text.replace(/\r\n/g, "\n")); } }); @@ -378,7 +441,7 @@ describe("Blob class", () => { const blob = new Blob(blobData, { type: "text/plain" }); const arrayBuffer = await blob.arrayBuffer(); - + expect(arrayBuffer).toBeInstanceOf(ArrayBuffer); }); @@ -389,7 +452,7 @@ describe("Blob class", () => { const slicedBlob = blob.slice(0, 5, "text/plain"); expect(slicedBlob instanceof Blob).toBeTruthy(); - expect(slicedBlob.size).toEqual(5) - expect(slicedBlob.type).toEqual("text/plain") + expect(slicedBlob.size).toEqual(5); + expect(slicedBlob.type).toEqual("text/plain"); }); }); diff --git a/yarn.lock b/yarn.lock index 657df3f5ee..4cf8147168 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2478,17 +2478,6 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -assert@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" - integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== - dependencies: - call-bind "^1.0.2" - is-nan "^1.3.2" - object-is "^1.1.5" - object.assign "^4.1.4" - util "^0.12.5" - assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -2599,7 +2588,7 @@ cac@^6.7.14: resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5: +call-bind@^1.0.2, call-bind@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== @@ -2723,7 +2712,7 @@ deep-eql@^4.1.3: dependencies: type-detect "^4.0.0" -define-data-property@^1.0.1, define-data-property@^1.1.2: +define-data-property@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.2.tgz#f3c33b4f0102360cd7c0f5f28700f5678510b63a" integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== @@ -2733,15 +2722,6 @@ define-data-property@^1.0.1, define-data-property@^1.1.2: gopd "^1.0.1" has-property-descriptors "^1.0.1" -define-properties@^1.1.3, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -3021,7 +3001,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: +has-property-descriptors@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== @@ -3107,14 +3087,6 @@ is-generator-function@^1.0.7: dependencies: has-tostringtag "^1.0.0" -is-nan@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -3446,29 +3418,6 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - obliterator@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" @@ -3974,7 +3923,7 @@ util-deprecate@^1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.4, util@^0.12.5: +util@^0.12.4: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==