diff --git a/docs/building-modules.md b/docs/building-modules.md index e8c8c0fa..e1bc9620 100644 --- a/docs/building-modules.md +++ b/docs/building-modules.md @@ -447,7 +447,7 @@ import "./test/user.test.js"; You can use most assertion libraries that are compatible with browsers and Deno, for example [Chai](https://www.chaijs.com). -Zinnia provides a built-in assertion library based on Deno's `std/testing/asserts.ts`. +Zinnia provides a built-in assertion library based on Deno's `std/assert`. Example usage: @@ -458,4 +458,4 @@ assertEquals(true, false); ``` You can find the API documentation at deno.land website: -[https://deno.land/std@0.207.0/testing/asserts.ts](https://deno.land/std@0.207.0/testing/asserts.ts) +[https://deno.land/std@0.214.0/assert](https://deno.land/std@0.214.0/assert) diff --git a/runtime/js/vendored/asserts.bundle.js b/runtime/js/vendored/asserts.bundle.js index 0c4b55b6..fb75a374 100644 --- a/runtime/js/vendored/asserts.bundle.js +++ b/runtime/js/vendored/asserts.bundle.js @@ -3,11 +3,12 @@ // This code was bundled using `deno bundle` and it's not recommended to edit it manually class AssertionError extends Error { - name = "AssertionError"; constructor(message){ super(message); + this.name = "AssertionError"; } } +export { AssertionError as AssertionError }; function assertAlmostEquals(actual, expected, tolerance = 1e-7, msg) { if (Object.is(actual, expected)) { return; @@ -21,6 +22,7 @@ function assertAlmostEquals(actual, expected, tolerance = 1e-7, msg) { throw new AssertionError(`Expected actual: "${f(actual)}" to be close to "${f(expected)}": \ delta "${f(delta)}" is greater than "${f(tolerance)}"${msgSuffix}`); } +export { assertAlmostEquals as assertAlmostEquals }; function isKeyedCollection(x) { return [ Symbol.iterator, @@ -108,6 +110,7 @@ function equal(c, d) { return false; }(c, d); } +export { equal as equal }; function format(v) { const { Deno } = globalThis; return typeof Deno?.inspect === "function" ? Deno.inspect(v, { @@ -116,7 +119,8 @@ function format(v) { trailingComma: true, compact: false, iterableLimit: Infinity, - getters: true + getters: true, + strAbbreviateSize: Infinity }) : `"${String(v).replace(/(?=["\\])/g, "\\")}"`; } function assertArrayIncludes(actual, expected, msg) { @@ -140,6 +144,7 @@ function assertArrayIncludes(actual, expected, msg) { msg = `Expected actual: "${format(actual)}" to include: "${format(expected)}"${msgSuffix}\nmissing: ${format(missing)}`; throw new AssertionError(msg); } +export { assertArrayIncludes as assertArrayIncludes }; const { Deno } = globalThis; const noColor = false; let enabled = !noColor; @@ -195,16 +200,14 @@ const ANSI_PATTERN = new RegExp([ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TXZcf-nq-uy=><~]))" ].join("|"), "g"); -const stripColor = stripAnsiCode; function stripAnsiCode(string) { return string.replace(ANSI_PATTERN, ""); } -var DiffType; -(function(DiffType) { - DiffType["removed"] = "removed"; - DiffType["common"] = "common"; - DiffType["added"] = "added"; -})(DiffType || (DiffType = {})); +const DiffType = { + removed: "removed", + common: "common", + added: "added" +}; const REMOVED = 1; const COMMON = 2; const ADDED = 3; @@ -212,14 +215,22 @@ function createCommon(A, B, reverse) { const common = []; if (A.length === 0 || B.length === 0) return []; for(let i = 0; i < Math.min(A.length, B.length); i += 1){ - if (A[reverse ? A.length - i - 1 : i] === B[reverse ? B.length - i - 1 : i]) { - common.push(A[reverse ? A.length - i - 1 : i]); + const a = reverse ? A[A.length - i - 1] : A[i]; + const b = reverse ? B[B.length - i - 1] : B[i]; + if (a !== undefined && a === b) { + common.push(a); } else { return common; } } return common; } +function ensureDefined(item) { + if (item === undefined) { + throw Error("Unexpected missing FarthestPoint"); + } + return item; +} function diff(A, B) { const prefixCommon = createCommon(A, B); const suffixCommon = createCommon(A.slice(prefixCommon.length), B.slice(prefixCommon.length), true).reverse(); @@ -308,7 +319,8 @@ function diff(A, B) { id: 0 }; } - if (down && down.y === -1 || k === M || (slide && slide.y) > (down && down.y) + 1) { + const isAdding = down?.y === -1 || k === M || (slide?.y || 0) > (down?.y || 0) + 1; + if (slide && isAdding) { const prev = slide.id; ptr++; routes[ptr] = prev; @@ -317,7 +329,7 @@ function diff(A, B) { y: slide.y, id: ptr }; - } else { + } else if (down && !isAdding) { const prev = down.id; ptr++; routes[ptr] = prev; @@ -326,6 +338,8 @@ function diff(A, B) { y: down.y + 1, id: ptr }; + } else { + throw new Error("Unexpected missing FarthestPoint"); } } function snake(k, slide, down, _offset, A, B) { @@ -346,7 +360,8 @@ function diff(A, B) { } return fp; } - while(fp[delta + offset].y < N){ + let currentFP = ensureDefined(fp[delta + offset]); + while(currentFP && currentFP.y < N){ p = p + 1; for(let k = -p; k < delta; ++k){ fp[k + offset] = snake(k, fp[k - 1 + offset], fp[k + 1 + offset], offset, A, B); @@ -355,13 +370,14 @@ function diff(A, B) { fp[k + offset] = snake(k, fp[k - 1 + offset], fp[k + 1 + offset], offset, A, B); } fp[delta + offset] = snake(delta, fp[delta - 1 + offset], fp[delta + 1 + offset], offset, A, B); + currentFP = ensureDefined(fp[delta + offset]); } return [ ...prefixCommon.map((c)=>({ type: DiffType.common, value: c })), - ...backTrace(A, B, fp[delta + offset], swapped), + ...backTrace(A, B, currentFP, swapped), ...suffixCommon.map((c)=>({ type: DiffType.common, value: c @@ -377,23 +393,26 @@ function diffstr(A, B) { const tokens = string.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/); const words = /^[a-zA-Z\u{C0}-\u{FF}\u{D8}-\u{F6}\u{F8}-\u{2C6}\u{2C8}-\u{2D7}\u{2DE}-\u{2FF}\u{1E00}-\u{1EFF}]+$/u; for(let i = 0; i < tokens.length - 1; i++){ - if (!tokens[i + 1] && tokens[i + 2] && words.test(tokens[i]) && words.test(tokens[i + 2])) { - tokens[i] += tokens[i + 2]; + const token = tokens[i]; + const tokenPlusTwo = tokens[i + 2]; + if (!tokens[i + 1] && token && tokenPlusTwo && words.test(token) && words.test(tokenPlusTwo)) { + tokens[i] += tokenPlusTwo; tokens.splice(i + 1, 2); i--; } } return tokens.filter((token)=>token); } else { - const tokens = [], lines = string.split(/(\n|\r\n)/); + const tokens = []; + const lines = string.split(/(\n|\r\n)/); if (!lines[lines.length - 1]) { lines.pop(); } - for(let i = 0; i < lines.length; i++){ + for (const [i, line] of lines.entries()){ if (i % 2) { - tokens[tokens.length - 1] += lines[i]; + tokens[tokens.length - 1] += line; } else { - tokens.push(lines[i]); + tokens.push(line); } } return tokens; @@ -401,10 +420,11 @@ function diffstr(A, B) { } function createDetails(line, tokens) { return tokens.filter(({ type })=>type === line.type || type === DiffType.common).map((result, i, t)=>{ - if (result.type === DiffType.common && t[i - 1] && t[i - 1]?.type === t[i + 1]?.type && /\s+/.test(result.value)) { + const token = t[i - 1]; + if (result.type === DiffType.common && token && token.type === t[i + 1]?.type && /\s+/.test(result.value)) { return { ...result, - type: t[i - 1].type + type: token.type }; } return result; @@ -511,6 +531,7 @@ function assertEquals(actual, expected, msg, options = {}) { } throw new AssertionError(message); } +export { assertEquals as assertEquals }; function assertExists(actual, msg) { if (actual === undefined || actual === null) { const msgSuffix = msg ? `: ${msg}` : "."; @@ -518,11 +539,27 @@ function assertExists(actual, msg) { throw new AssertionError(msg); } } +export { assertExists as assertExists }; function assertFalse(expr, msg = "") { if (expr) { throw new AssertionError(msg); } } +export { assertFalse as assertFalse }; +function assertGreaterOrEqual(actual, expected, msg) { + if (actual >= expected) return; + const actualString = format(actual); + const expectedString = format(expected); + throw new AssertionError(msg ?? `Expect ${actualString} >= ${expectedString}`); +} +export { assertGreaterOrEqual as assertGreaterOrEqual }; +function assertGreater(actual, expected, msg) { + if (actual > expected) return; + const actualString = format(actual); + const expectedString = format(expected); + throw new AssertionError(msg ?? `Expect ${actualString} > ${expectedString}`); +} +export { assertGreater as assertGreater }; function assertInstanceOf(actual, expectedType, msg = "") { if (actual instanceof expectedType) return; const msgSuffix = msg ? `: ${msg}` : "."; @@ -546,20 +583,43 @@ function assertInstanceOf(actual, expectedType, msg = "") { } throw new AssertionError(msg); } -function assertIsError(error, ErrorClass, msgIncludes, msg) { +export { assertInstanceOf as assertInstanceOf }; +function assertIsError(error, ErrorClass, msgMatches, msg) { const msgSuffix = msg ? `: ${msg}` : "."; - if (error instanceof Error === false) { + if (!(error instanceof Error)) { throw new AssertionError(`Expected "error" to be an Error object${msgSuffix}}`); } if (ErrorClass && !(error instanceof ErrorClass)) { msg = `Expected error to be instance of "${ErrorClass.name}", but was "${typeof error === "object" ? error?.constructor?.name : "[not an object]"}"${msgSuffix}`; throw new AssertionError(msg); } - if (msgIncludes && (!(error instanceof Error) || !stripColor(error.message).includes(stripColor(msgIncludes)))) { - msg = `Expected error message to include ${JSON.stringify(msgIncludes)}, but got ${error instanceof Error ? JSON.stringify(error.message) : '"[not an Error]"'}${msgSuffix}`; + let msgCheck; + if (typeof msgMatches === "string") { + msgCheck = stripAnsiCode(error.message).includes(stripAnsiCode(msgMatches)); + } + if (msgMatches instanceof RegExp) { + msgCheck = msgMatches.test(stripAnsiCode(error.message)); + } + if (msgMatches && !msgCheck) { + msg = `Expected error message to include ${msgMatches instanceof RegExp ? msgMatches.toString() : JSON.stringify(msgMatches)}, but got ${error instanceof Error ? JSON.stringify(error.message) : '"[not an Error]"'}${msgSuffix}`; throw new AssertionError(msg); } } +export { assertIsError as assertIsError }; +function assertLessOrEqual(actual, expected, msg) { + if (actual <= expected) return; + const actualString = format(actual); + const expectedString = format(expected); + throw new AssertionError(msg ?? `Expect ${actualString} <= ${expectedString}`); +} +export { assertLessOrEqual as assertLessOrEqual }; +function assertLess(actual, expected, msg) { + if (actual < expected) return; + const actualString = format(actual); + const expectedString = format(expected); + throw new AssertionError(msg ?? `Expect ${actualString} < ${expectedString}`); +} +export { assertLess as assertLess }; function assertMatch(actual, expected, msg) { if (!expected.test(actual)) { const msgSuffix = msg ? `: ${msg}` : "."; @@ -567,6 +627,7 @@ function assertMatch(actual, expected, msg) { throw new AssertionError(msg); } } +export { assertMatch as assertMatch }; function assertNotEquals(actual, expected, msg) { if (!equal(actual, expected)) { return; @@ -576,21 +637,23 @@ function assertNotEquals(actual, expected, msg) { try { actualString = String(actual); } catch { - actualString = "[Cannot display]"; + actualString = CAN_NOT_DISPLAY; } try { expectedString = String(expected); } catch { - expectedString = "[Cannot display]"; + expectedString = CAN_NOT_DISPLAY; } const msgSuffix = msg ? `: ${msg}` : "."; throw new AssertionError(`Expected actual: ${actualString} not to be: ${expectedString}${msgSuffix}`); } +export { assertNotEquals as assertNotEquals }; function assertNotInstanceOf(actual, unexpectedType, msg) { const msgSuffix = msg ? `: ${msg}` : "."; msg = `Expected object to not be an instance of "${typeof unexpectedType}"${msgSuffix}`; assertFalse(actual instanceof unexpectedType, msg); } +export { assertNotInstanceOf as assertNotInstanceOf }; function assertNotMatch(actual, expected, msg) { if (expected.test(actual)) { const msgSuffix = msg ? `: ${msg}` : "."; @@ -598,13 +661,15 @@ function assertNotMatch(actual, expected, msg) { throw new AssertionError(msg); } } +export { assertNotMatch as assertNotMatch }; function assertNotStrictEquals(actual, expected, msg) { if (!Object.is(actual, expected)) { return; } const msgSuffix = msg ? `: ${msg}` : "."; - throw new AssertionError(`Expected "actual" to be strictly unequal to: ${format(actual)}${msgSuffix}\n`); + throw new AssertionError(`Expected "actual" to not be strictly equal to: ${format(actual)}${msgSuffix}\n`); } +export { assertNotStrictEquals as assertNotStrictEquals }; function assertObjectMatch(actual, expected, msg) { function filter(a, b) { const seen = new WeakMap(); @@ -671,6 +736,7 @@ function assertObjectMatch(actual, expected, msg) { } return assertEquals(filter(actual, expected), filter(expected, expected), msg); } +export { assertObjectMatch as assertObjectMatch }; async function assertRejects(fn, errorClassOrMsg, msgIncludesOrMsg, msg) { let ErrorClass = undefined; let msgIncludes = undefined; @@ -710,6 +776,7 @@ async function assertRejects(fn, errorClassOrMsg, msgIncludesOrMsg, msg) { } return err; } +export { assertRejects as assertRejects }; function assertStrictEquals(actual, expected, msg) { if (Object.is(actual, expected)) { return; @@ -735,6 +802,7 @@ function assertStrictEquals(actual, expected, msg) { } throw new AssertionError(message); } +export { assertStrictEquals as assertStrictEquals }; function assertStringIncludes(actual, expected, msg) { if (!actual.includes(expected)) { const msgSuffix = msg ? `: ${msg}` : "."; @@ -742,6 +810,7 @@ function assertStringIncludes(actual, expected, msg) { throw new AssertionError(msg); } } +export { assertStringIncludes as assertStringIncludes }; function assertThrows(fn, errorClassOrMsg, msgIncludesOrMsg, msg) { let ErrorClass = undefined; let msgIncludes = undefined; @@ -776,20 +845,24 @@ function assertThrows(fn, errorClassOrMsg, msgIncludesOrMsg, msg) { } return err; } +export { assertThrows as assertThrows }; function assert(expr, msg = "") { if (!expr) { throw new AssertionError(msg); } } +export { assert as assert }; function fail(msg) { const msgSuffix = msg ? `: ${msg}` : "."; assert(false, `Failed assertion${msgSuffix}`); } +export { fail as fail }; function unimplemented(msg) { const msgSuffix = msg ? `: ${msg}` : "."; throw new AssertionError(`Unimplemented${msgSuffix}`); } +export { unimplemented as unimplemented }; function unreachable() { throw new AssertionError("unreachable"); } -export { assert as assert, assertAlmostEquals as assertAlmostEquals, assertArrayIncludes as assertArrayIncludes, assertEquals as assertEquals, assertExists as assertExists, assertFalse as assertFalse, assertInstanceOf as assertInstanceOf, AssertionError as AssertionError, assertIsError as assertIsError, assertMatch as assertMatch, assertNotEquals as assertNotEquals, assertNotInstanceOf as assertNotInstanceOf, assertNotMatch as assertNotMatch, assertNotStrictEquals as assertNotStrictEquals, assertObjectMatch as assertObjectMatch, assertRejects as assertRejects, assertStrictEquals as assertStrictEquals, assertStringIncludes as assertStringIncludes, assertThrows as assertThrows, equal as equal, fail as fail, unimplemented as unimplemented, unreachable as unreachable }; +export { unreachable as unreachable }; diff --git a/runtime/vendor.js b/runtime/vendor.js index 99730f44..135edd39 100644 --- a/runtime/vendor.js +++ b/runtime/vendor.js @@ -3,15 +3,15 @@ // See https://github.com/filecoin-station/zinnia/issues/43 // // Run this script using the following command: -// deno run --allow-run runtime/vendor.js +// deno run --allow-run --allow-read --allow-write runtime/vendor.js -const STD_VERSION = "0.207.0"; +const STD_VERSION = "0.214.0"; import { fromFileUrl } from "https://deno.land/std@0.181.0/path/mod.ts"; import { green } from "https://deno.land/std@0.183.0/fmt/colors.ts"; let assertsPath = await vendor( - `https://deno.land/std@${STD_VERSION}/testing/asserts.ts`, + `https://deno.land/std@${STD_VERSION}/assert/mod.ts`, "asserts.bundle.js", ); await patchAssertsBundle(assertsPath);