@fedify/fedify
Version:
An ActivityPub server framework
1,014 lines (1,013 loc) • 30.2 kB
JavaScript
import "@js-temporal/polyfill";
import "urlpattern-polyfill";
globalThis.addEventListener = () => {};
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assertion_error.js
/**
* Error thrown when an assertion fails.
*
* @example Usage
* ```ts no-eval
* import { AssertionError } from "@std/assert/assertion-error";
*
* throw new AssertionError("Assertion failed");
* ```
*/ var AssertionError = class extends Error {
/** Constructs a new instance.
*
* @example Usage
* ```ts no-eval
* import { AssertionError } from "@std/assert/assertion-error";
*
* throw new AssertionError("Assertion failed");
* ```
*
* @param message The error message.
*/ constructor(message) {
super(message);
this.name = "AssertionError";
}
};
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/equal.js
function isKeyedCollection(x) {
return [Symbol.iterator, "size"].every((k) => k in x);
}
function constructorsEqual(a, b) {
return a.constructor === b.constructor || a.constructor === Object && !b.constructor || !a.constructor && b.constructor === Object;
}
/**
* Deep equality comparison used in assertions
*
* @param c The actual value
* @param d The expected value
* @returns `true` if the values are deeply equal, `false` otherwise
*
* @example Usage
* ```ts
* import { equal } from "@std/assert/equal";
*
* equal({ foo: "bar" }, { foo: "bar" }); // Returns `true`
* equal({ foo: "bar" }, { foo: "baz" }); // Returns `false
* ```
*/ function equal(c, d) {
const seen = /* @__PURE__ */ new Map();
return function compare(a, b) {
if (a && b && (a instanceof RegExp && b instanceof RegExp || a instanceof URL && b instanceof URL)) return String(a) === String(b);
if (a instanceof Date && b instanceof Date) {
const aTime = a.getTime();
const bTime = b.getTime();
if (Number.isNaN(aTime) && Number.isNaN(bTime)) return true;
return aTime === bTime;
}
if (typeof a === "number" && typeof b === "number") return Number.isNaN(a) && Number.isNaN(b) || a === b;
if (Object.is(a, b)) return true;
if (a && typeof a === "object" && b && typeof b === "object") {
if (a && b && !constructorsEqual(a, b)) return false;
if (a instanceof WeakMap || b instanceof WeakMap) {
if (!(a instanceof WeakMap && b instanceof WeakMap)) return false;
throw new TypeError("cannot compare WeakMap instances");
}
if (a instanceof WeakSet || b instanceof WeakSet) {
if (!(a instanceof WeakSet && b instanceof WeakSet)) return false;
throw new TypeError("cannot compare WeakSet instances");
}
if (a instanceof WeakRef || b instanceof WeakRef) {
if (!(a instanceof WeakRef && b instanceof WeakRef)) return false;
return compare(a.deref(), b.deref());
}
if (seen.get(a) === b) return true;
if (Object.keys(a).length !== Object.keys(b).length) return false;
seen.set(a, b);
if (isKeyedCollection(a) && isKeyedCollection(b)) {
if (a.size !== b.size) return false;
let unmatchedEntries = a.size;
for (const [aKey, aValue] of a.entries()) for (const [bKey, bValue] of b.entries()) if (aKey === aValue && bKey === bValue && compare(aKey, bKey) || compare(aKey, bKey) && compare(aValue, bValue)) {
unmatchedEntries--;
break;
}
return unmatchedEntries === 0;
}
const merged = {
...a,
...b
};
for (const key of [...Object.getOwnPropertyNames(merged), ...Object.getOwnPropertySymbols(merged)]) {
if (!compare(a && a[key], b && b[key])) return false;
if (key in a && !(key in b) || key in b && !(key in a)) return false;
}
return true;
}
return false;
}(c, d);
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/format.js
/**
* Converts the input into a string. Objects, Sets and Maps are sorted so as to
* make tests less flaky.
*
* @param v Value to be formatted
*
* @returns The formatted string
*
* @example Usage
* ```ts
* import { format } from "@std/internal/format";
* import { assertEquals } from "@std/assert";
*
* assertEquals(format({ a: 1, b: 2 }), "{\n a: 1,\n b: 2,\n}");
* assertEquals(format(new Set([1, 2])), "Set(2) {\n 1,\n 2,\n}");
* assertEquals(format(new Map([[1, 2]])), "Map(1) {\n 1 => 2,\n}");
* ```
*/ function format(v) {
const { Deno } = globalThis;
return typeof Deno?.inspect === "function" ? Deno.inspect(v, {
depth: Infinity,
sorted: true,
trailingComma: true,
compact: false,
iterableLimit: Infinity,
getters: true,
strAbbreviateSize: Infinity
}) : `"${String(v).replace(/(?=["\\])/g, "\\")}"`;
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/assertion_state.js
/**
* Check the test suite internal state
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* ```
*/ var AssertionState = class {
#state;
constructor() {
this.#state = {
assertionCount: void 0,
assertionCheck: false,
assertionTriggered: false,
assertionTriggeredCount: 0
};
if (typeof globalThis?.addEventListener === "function") globalThis.addEventListener("unload", () => {
this.#ensureCleanedUp();
});
else if (typeof globalThis?.process?.on === "function") globalThis.process.on("exit", () => {
this.#ensureCleanedUp();
});
else console.warn("AssertionCounter cleanup step was not registered");
}
#ensureCleanedUp() {
if (this.#state.assertionCheck || this.#state.assertionCount !== void 0) throw new Error("AssertionCounter was not cleaned up: If tests are not otherwise failing, ensure `expect.hasAssertion` and `expect.assertions` are only run in bdd tests");
}
/**
* Get the number that through `expect.assertions` api set.
*
* @returns the number that through `expect.assertions` api set.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.assertionCount;
* ```
*/ get assertionCount() {
return this.#state.assertionCount;
}
/**
* Get a certain number that assertions were called before.
*
* @returns return a certain number that assertions were called before.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.assertionTriggeredCount;
* ```
*/ get assertionTriggeredCount() {
return this.#state.assertionTriggeredCount;
}
/**
* If `expect.hasAssertions` called, then through this method to update #state.assertionCheck value.
*
* @param val Set #state.assertionCheck's value
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.setAssertionCheck(true);
* ```
*/ setAssertionCheck(val) {
this.#state.assertionCheck = val;
}
/**
* If any matchers was called, `#state.assertionTriggered` will be set through this method.
*
* @param val Set #state.assertionTriggered's value
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.setAssertionTriggered(true);
* ```
*/ setAssertionTriggered(val) {
this.#state.assertionTriggered = val;
}
/**
* If `expect.assertions` called, then through this method to update #state.assertionCheck value.
*
* @param num Set #state.assertionCount's value, for example if the value is set 2, that means
* you must have two assertion matchers call in your test suite.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.setAssertionCount(2);
* ```
*/ setAssertionCount(num) {
this.#state.assertionCount = num;
}
/**
* If any matchers was called, `#state.assertionTriggeredCount` value will plus one internally.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.updateAssertionTriggerCount();
* ```
*/ updateAssertionTriggerCount() {
if (this.#state.assertionCount !== void 0) this.#state.assertionTriggeredCount += 1;
}
/**
* Check Assertion internal state, if `#state.assertionCheck` is set true, but
* `#state.assertionTriggered` is still false, then should throw an Assertion Error.
*
* @returns a boolean value, that the test suite is satisfied with the check. If not,
* it should throw an AssertionError.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* if (assertionState.checkAssertionErrorState()) {
* // throw AssertionError("");
* }
* ```
*/ checkAssertionErrorState() {
return this.#state.assertionCheck && !this.#state.assertionTriggered;
}
/**
* Reset all assertion state when every test suite function ran completely.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* assertionState.resetAssertionState();
* ```
*/ resetAssertionState() {
this.#state = {
assertionCount: void 0,
assertionCheck: false,
assertionTriggered: false,
assertionTriggeredCount: 0
};
}
/**
* Check Assertion called state, if `#state.assertionCount` is set to a number value, but
* `#state.assertionTriggeredCount` is less then it, then should throw an assertion error.
*
* @returns a boolean value, that the test suite is satisfied with the check. If not,
* it should throw an AssertionError.
*
* @example Usage
* ```ts ignore
* import { AssertionState } from "@std/internal";
*
* const assertionState = new AssertionState();
* if (assertionState.checkAssertionCountSatisfied()) {
* // throw AssertionError("");
* }
* ```
*/ checkAssertionCountSatisfied() {
return this.#state.assertionCount !== void 0 && this.#state.assertionCount !== this.#state.assertionTriggeredCount;
}
};
new AssertionState();
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/styles.js
const { Deno } = globalThis;
const enabled = !(typeof Deno?.noColor === "boolean" ? Deno.noColor : false);
function code(open, close) {
return {
open: `\x1b[${open.join(";")}m`,
close: `\x1b[${close}m`,
regexp: new RegExp(`\\x1b\\[${close}m`, "g")
};
}
function run(str, code) {
return enabled ? `${code.open}${str.replace(code.regexp, code.open)}${code.close}` : str;
}
/**
* Sets the style of text to be printed to bold.
*
* Disable by setting the `NO_COLOR` environmental variable.
*
* @param str Text to make bold
*
* @returns Bold text for printing
*
* @example Usage
* ```ts no-assert
* import { bold } from "@std/internal/styles";
*
* console.log(bold("Hello, world!")); // Prints "Hello, world!" in bold
* ```
*/ function bold(str) {
return run(str, code([1], 22));
}
/**
* Sets the color of text to be printed to red.
*
* Disable by setting the `NO_COLOR` environmental variable.
*
* @param str Text to make red
*
* @returns Red text for printing
*
* @example Usage
* ```ts no-assert
* import { red } from "@std/internal/styles";
*
* console.log(red("Hello, world!")); // Prints "Hello, world!" in red
* ```
*/ function red(str) {
return run(str, code([31], 39));
}
/**
* Sets the color of text to be printed to green.
*
* Disable by setting the `NO_COLOR` environmental variable.
*
* @param str Text to make green
*
* @returns Green text for print
*
* @example Usage
* ```ts no-assert
* import { green } from "@std/internal/styles";
*
* console.log(green("Hello, world!")); // Prints "Hello, world!" in green
* ```
*/ function green(str) {
return run(str, code([32], 39));
}
/**
* Sets the color of text to be printed to white.
*
* @param str Text to make white
*
* @returns White text for print
*
* @example Usage
* ```ts no-assert
* import { white } from "@std/internal/styles";
*
* console.log(white("Hello, world!")); // Prints "Hello, world!" in white
* ```
*/ function white(str) {
return run(str, code([37], 39));
}
/**
* Sets the color of text to be printed to gray.
*
* @param str Text to make gray
*
* @returns Gray text for print
*
* @example Usage
* ```ts no-assert
* import { gray } from "@std/internal/styles";
*
* console.log(gray("Hello, world!")); // Prints "Hello, world!" in gray
* ```
*/ function gray(str) {
return brightBlack(str);
}
/**
* Sets the color of text to be printed to bright-black.
*
* @param str Text to make bright-black
*
* @returns Bright-black text for print
*
* @example Usage
* ```ts no-assert
* import { brightBlack } from "@std/internal/styles";
*
* console.log(brightBlack("Hello, world!")); // Prints "Hello, world!" in bright-black
* ```
*/ function brightBlack(str) {
return run(str, code([90], 39));
}
/**
* Sets the background color of text to be printed to red.
*
* @param str Text to make its background red
*
* @returns Red background text for print
*
* @example Usage
* ```ts no-assert
* import { bgRed } from "@std/internal/styles";
*
* console.log(bgRed("Hello, world!")); // Prints "Hello, world!" with red background
* ```
*/ function bgRed(str) {
return run(str, code([41], 49));
}
/**
* Sets the background color of text to be printed to green.
*
* @param str Text to make its background green
*
* @returns Green background text for print
*
* @example Usage
* ```ts no-assert
* import { bgGreen } from "@std/internal/styles";
*
* console.log(bgGreen("Hello, world!")); // Prints "Hello, world!" with green background
* ```
*/ function bgGreen(str) {
return run(str, code([42], 49));
}
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");
/**
* Remove ANSI escape codes from the string.
*
* @param string Text to remove ANSI escape codes from
*
* @returns Text without ANSI escape codes
*
* @example Usage
* ```ts no-assert
* import { red, stripAnsiCode } from "@std/internal/styles";
*
* console.log(stripAnsiCode(red("Hello, world!"))); // Prints "Hello, world!"
* ```
*/ function stripAnsiCode(string) {
return string.replace(ANSI_PATTERN, "");
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/build_message.js
/**
* Colors the output of assertion diffs.
*
* @param diffType Difference type, either added or removed.
* @param background If true, colors the background instead of the text.
*
* @returns A function that colors the input string.
*
* @example Usage
* ```ts
* import { createColor } from "@std/internal";
* import { assertEquals } from "@std/assert";
* import { bold, green, red, white } from "@std/fmt/colors";
*
* assertEquals(createColor("added")("foo"), green(bold("foo")));
* assertEquals(createColor("removed")("foo"), red(bold("foo")));
* assertEquals(createColor("common")("foo"), white("foo"));
* ```
*/ function createColor(diffType, background = false) {
switch (diffType) {
case "added": return (s) => background ? bgGreen(white(s)) : green(bold(s));
case "removed": return (s) => background ? bgRed(white(s)) : red(bold(s));
default: return white;
}
}
/**
* Prefixes `+` or `-` in diff output.
*
* @param diffType Difference type, either added or removed
*
* @returns A string representing the sign.
*
* @example Usage
* ```ts
* import { createSign } from "@std/internal";
* import { assertEquals } from "@std/assert";
*
* assertEquals(createSign("added"), "+ ");
* assertEquals(createSign("removed"), "- ");
* assertEquals(createSign("common"), " ");
* ```
*/ function createSign(diffType) {
switch (diffType) {
case "added": return "+ ";
case "removed": return "- ";
default: return " ";
}
}
/**
* Builds a message based on the provided diff result.
*
* @param diffResult The diff result array.
* @param options Optional parameters for customizing the message.
*
* @returns An array of strings representing the built message.
*
* @example Usage
* ```ts no-assert
* import { diffStr, buildMessage } from "@std/internal";
*
* const diffResult = diffStr("Hello, world!", "Hello, world");
*
* console.log(buildMessage(diffResult));
* // [
* // "",
* // "",
* // " [Diff] Actual / Expected",
* // "",
* // "",
* // "- Hello, world!",
* // "+ Hello, world",
* // "",
* // ]
* ```
*/ function buildMessage(diffResult, options = {}) {
const { stringDiff = false } = options;
const messages = [
"",
"",
` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${green(bold("Expected"))}`,
"",
""
];
const diffMessages = diffResult.map((result) => {
const color = createColor(result.type);
const line = result.details?.map((detail) => detail.type !== "common" ? createColor(detail.type, true)(detail.value) : detail.value).join("") ?? result.value;
return color(`${createSign(result.type)}${line}`);
});
messages.push(...stringDiff ? [diffMessages.join("")] : diffMessages, "");
return messages;
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/diff.js
const REMOVED = 1;
const COMMON = 2;
const ADDED = 3;
/**
* Creates an array of common elements between two arrays.
*
* @typeParam T The type of elements in the arrays.
*
* @param A The first array.
* @param B The second array.
*
* @returns An array containing the common elements between the two arrays.
*
* @example Usage
* ```ts
* import { createCommon } from "@std/internal/diff";
* import { assertEquals } from "@std/assert";
*
* const a = [1, 2, 3];
* const b = [1, 2, 4];
*
* assertEquals(createCommon(a, b), [1, 2]);
* ```
*/ function createCommon(A, B) {
const common = [];
if (A.length === 0 || B.length === 0) return [];
for (let i = 0; i < Math.min(A.length, B.length); i += 1) {
const a = A[i];
const b = B[i];
if (a !== void 0 && a === b) common.push(a);
else return common;
}
return common;
}
/**
* Asserts that the value is a {@linkcode FarthestPoint}.
* If not, an error is thrown.
*
* @param value The value to check.
*
* @returns A void value that returns once the assertion completes.
*
* @example Usage
* ```ts
* import { assertFp } from "@std/internal/diff";
* import { assertThrows } from "@std/assert";
*
* assertFp({ y: 0, id: 0 });
* assertThrows(() => assertFp({ id: 0 }));
* assertThrows(() => assertFp({ y: 0 }));
* assertThrows(() => assertFp(undefined));
* ```
*/ function assertFp(value) {
if (value == null || typeof value !== "object" || typeof value?.y !== "number" || typeof value?.id !== "number") throw new Error(`Unexpected value, expected 'FarthestPoint': received ${typeof value}`);
}
/**
* Creates an array of backtraced differences.
*
* @typeParam T The type of elements in the arrays.
*
* @param A The first array.
* @param B The second array.
* @param current The current {@linkcode FarthestPoint}.
* @param swapped Boolean indicating if the arrays are swapped.
* @param routes The routes array.
* @param diffTypesPtrOffset The offset of the diff types in the routes array.
*
* @returns An array of backtraced differences.
*
* @example Usage
* ```ts
* import { backTrace } from "@std/internal/diff";
* import { assertEquals } from "@std/assert";
*
* assertEquals(
* backTrace([], [], { y: 0, id: 0 }, false, new Uint32Array(0), 0),
* [],
* );
* ```
*/ function backTrace(A, B, current, swapped, routes, diffTypesPtrOffset) {
const M = A.length;
const N = B.length;
const result = [];
let a = M - 1;
let b = N - 1;
let j = routes[current.id];
let type = routes[current.id + diffTypesPtrOffset];
while (true) {
if (!j && !type) break;
const prev = j;
if (type === REMOVED) {
result.unshift({
type: swapped ? "removed" : "added",
value: B[b]
});
b -= 1;
} else if (type === ADDED) {
result.unshift({
type: swapped ? "added" : "removed",
value: A[a]
});
a -= 1;
} else {
result.unshift({
type: "common",
value: A[a]
});
a -= 1;
b -= 1;
}
j = routes[prev];
type = routes[prev + diffTypesPtrOffset];
}
return result;
}
/**
* Creates a {@linkcode FarthestPoint}.
*
* @param k The current index.
* @param M The length of the first array.
* @param routes The routes array.
* @param diffTypesPtrOffset The offset of the diff types in the routes array.
* @param ptr The current pointer.
* @param slide The slide {@linkcode FarthestPoint}.
* @param down The down {@linkcode FarthestPoint}.
*
* @returns A {@linkcode FarthestPoint}.
*
* @example Usage
* ```ts
* import { createFp } from "@std/internal/diff";
* import { assertEquals } from "@std/assert";
*
* assertEquals(
* createFp(
* 0,
* 0,
* new Uint32Array(0),
* 0,
* 0,
* { y: -1, id: 0 },
* { y: 0, id: 0 },
* ),
* { y: -1, id: 1 },
* );
* ```
*/ function createFp(k, M, routes, diffTypesPtrOffset, ptr, slide, down) {
if (slide && slide.y === -1 && down && down.y === -1) return {
y: 0,
id: 0
};
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;
routes[ptr + diffTypesPtrOffset] = ADDED;
return {
y: slide.y,
id: ptr
};
}
if (down && !isAdding) {
const prev = down.id;
ptr++;
routes[ptr] = prev;
routes[ptr + diffTypesPtrOffset] = REMOVED;
return {
y: down.y + 1,
id: ptr
};
}
throw new Error("Unexpected missing FarthestPoint");
}
/**
* Renders the differences between the actual and expected values.
*
* @typeParam T The type of elements in the arrays.
*
* @param A Actual value
* @param B Expected value
*
* @returns An array of differences between the actual and expected values.
*
* @example Usage
* ```ts
* import { diff } from "@std/internal/diff";
* import { assertEquals } from "@std/assert";
*
* const a = [1, 2, 3];
* const b = [1, 2, 4];
*
* assertEquals(diff(a, b), [
* { type: "common", value: 1 },
* { type: "common", value: 2 },
* { type: "removed", value: 3 },
* { type: "added", value: 4 },
* ]);
* ```
*/ function diff(A, B) {
const prefixCommon = createCommon(A, B);
A = A.slice(prefixCommon.length);
B = B.slice(prefixCommon.length);
const swapped = B.length > A.length;
[A, B] = swapped ? [B, A] : [A, B];
const M = A.length;
const N = B.length;
if (!M && !N && !prefixCommon.length) return [];
if (!N) return [...prefixCommon.map((value) => ({
type: "common",
value
})), ...A.map((value) => ({
type: swapped ? "added" : "removed",
value
}))];
const offset = N;
const delta = M - N;
const length = M + N + 1;
const fp = Array.from({ length }, () => ({
y: -1,
id: -1
}));
/**
* Note: this buffer is used to save memory and improve performance. The first
* half is used to save route and the last half is used to save diff type.
*/ const routes = new Uint32Array((M * N + length + 1) * 2);
const diffTypesPtrOffset = routes.length / 2;
let ptr = 0;
function snake(k, A, B, slide, down) {
const M = A.length;
const N = B.length;
const fp = createFp(k, M, routes, diffTypesPtrOffset, ptr, slide, down);
ptr = fp.id;
while (fp.y + k < M && fp.y < N && A[fp.y + k] === B[fp.y]) {
const prev = fp.id;
ptr++;
fp.id = ptr;
fp.y += 1;
routes[ptr] = prev;
routes[ptr + diffTypesPtrOffset] = COMMON;
}
return fp;
}
let currentFp = fp[delta + offset];
assertFp(currentFp);
let p = -1;
while (currentFp.y < N) {
p = p + 1;
for (let k = -p; k < delta; ++k) {
const index = k + offset;
fp[index] = snake(k, A, B, fp[index - 1], fp[index + 1]);
}
for (let k = delta + p; k > delta; --k) {
const index = k + offset;
fp[index] = snake(k, A, B, fp[index - 1], fp[index + 1]);
}
const index = delta + offset;
fp[delta + offset] = snake(delta, A, B, fp[index - 1], fp[index + 1]);
currentFp = fp[delta + offset];
assertFp(currentFp);
}
return [...prefixCommon.map((value) => ({
type: "common",
value
})), ...backTrace(A, B, currentFp, swapped, routes, diffTypesPtrOffset)];
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__internal@1.0.8/node_modules/@jsr/std__internal/diff_str.js
/**
* Unescape invisible characters.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#escape_sequences}
*
* @param string String to unescape.
*
* @returns Unescaped string.
*
* @example Usage
* ```ts
* import { unescape } from "@std/internal/diff-str";
* import { assertEquals } from "@std/assert";
*
* assertEquals(unescape("Hello\nWorld"), "Hello\\n\nWorld");
* ```
*/ function unescape(string) {
return string.replaceAll("\\", "\\\\").replaceAll("\b", "\\b").replaceAll("\f", "\\f").replaceAll(" ", "\\t").replaceAll("\v", "\\v").replaceAll(/\r\n|\r|\n/g, (str) => str === "\r" ? "\\r" : str === "\n" ? "\\n\n" : "\\r\\n\r\n");
}
const WHITESPACE_SYMBOLS = /((?:\\[bftv]|[^\S\r\n])+|\\[rn\\]|[()[\]{}'"\r\n]|\b)/;
/**
* Tokenizes a string into an array of tokens.
*
* @param string The string to tokenize.
* @param wordDiff If true, performs word-based tokenization. Default is false.
*
* @returns An array of tokens.
*
* @example Usage
* ```ts
* import { tokenize } from "@std/internal/diff-str";
* import { assertEquals } from "@std/assert";
*
* assertEquals(tokenize("Hello\nWorld"), ["Hello\n", "World"]);
* ```
*/ function tokenize(string, wordDiff = false) {
if (wordDiff) return string.split(WHITESPACE_SYMBOLS).filter((token) => token);
const tokens = [];
const lines = string.split(/(\n|\r\n)/).filter((line) => line);
for (const [i, line] of lines.entries()) if (i % 2) tokens[tokens.length - 1] += line;
else tokens.push(line);
return tokens;
}
/**
* Create details by filtering relevant word-diff for current line and merge
* "space-diff" if surrounded by word-diff for cleaner displays.
*
* @param line Current line
* @param tokens Word-diff tokens
*
* @returns Array of diff results.
*
* @example Usage
* ```ts
* import { createDetails } from "@std/internal/diff-str";
* import { assertEquals } from "@std/assert";
*
* const tokens = [
* { type: "added", value: "a" },
* { type: "removed", value: "b" },
* { type: "common", value: "c" },
* ] as const;
* assertEquals(
* createDetails({ type: "added", value: "a" }, [...tokens]),
* [{ type: "added", value: "a" }, { type: "common", value: "c" }]
* );
* ```
*/ function createDetails(line, tokens) {
return tokens.filter(({ type }) => type === line.type || type === "common").map((result, i, t) => {
const token = t[i - 1];
if (result.type === "common" && token && token.type === t[i + 1]?.type && /\s+/.test(result.value)) return {
...result,
type: token.type
};
return result;
});
}
const NON_WHITESPACE_REGEXP = /\S/;
/**
* Renders the differences between the actual and expected strings. Partially
* inspired from {@link https://github.com/kpdecker/jsdiff}.
*
* @param A Actual string
* @param B Expected string
*
* @returns Array of diff results.
*
* @example Usage
* ```ts
* import { diffStr } from "@std/internal/diff-str";
* import { assertEquals } from "@std/assert";
*
* assertEquals(diffStr("Hello!", "Hello"), [
* {
* type: "removed",
* value: "Hello!\n",
* details: [
* { type: "common", value: "Hello" },
* { type: "removed", value: "!" },
* { type: "common", value: "\n" }
* ]
* },
* {
* type: "added",
* value: "Hello\n",
* details: [
* { type: "common", value: "Hello" },
* { type: "common", value: "\n" }
* ]
* }
* ]);
* ```
*/ function diffStr(A, B) {
const diffResult = diff(tokenize(`${unescape(A)}\n`), tokenize(`${unescape(B)}\n`));
const added = [];
const removed = [];
for (const result of diffResult) {
if (result.type === "added") added.push(result);
if (result.type === "removed") removed.push(result);
}
const hasMoreRemovedLines = added.length < removed.length;
const aLines = hasMoreRemovedLines ? added : removed;
const bLines = hasMoreRemovedLines ? removed : added;
for (const a of aLines) {
let tokens = [];
let b;
while (bLines.length) {
b = bLines.shift();
const tokenized = [tokenize(a.value, true), tokenize(b.value, true)];
if (hasMoreRemovedLines) tokenized.reverse();
tokens = diff(tokenized[0], tokenized[1]);
if (tokens.some(({ type, value }) => type === "common" && NON_WHITESPACE_REGEXP.test(value))) break;
}
a.details = createDetails(a, tokens);
if (b) b.details = createDetails(b, tokens);
}
return diffResult;
}
//#endregion
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_equals.js
/**
* Make an assertion that `actual` and `expected` are equal, deeply. If not
* deeply equal, then throw.
*
* Type parameter can be specified to ensure values under comparison have the
* same type.
*
* @example Usage
* ```ts no-eval
* import { assertEquals } from "@std/assert/assert-equals";
*
* assertEquals("world", "world"); // Doesn't throw
* assertEquals("hello", "world"); // Throws
* ```
*
* Note: formatter option is experimental and may be removed in the future.
*
* @typeParam T The type of the values to compare. This is usually inferred.
* @param actual The actual value to compare.
* @param expected The expected value to compare.
* @param msg The optional message to display if the assertion fails.
* @param options The optional object for the assertion.
*/ function assertEquals(actual, expected, msg) {
if (equal(actual, expected)) return;
let message = `Values are not equal${msg ? `: ${msg}` : "."}`;
const actualString = format(actual);
const expectedString = format(expected);
const stringDiff = typeof actual === "string" && typeof expected === "string";
const diffMsg = buildMessage(stringDiff ? diffStr(actual, expected) : diff(actualString.split("\n"), expectedString.split("\n")), { stringDiff }).join("\n");
message = `${message}\n${diffMsg}`;
throw new AssertionError(message);
}
//#endregion
export { red as a, equal as c, buildMessage as i, AssertionError as l, diffStr as n, stripAnsiCode as o, diff as r, format as s, assertEquals as t };