Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 9 additions & 21 deletions src/js/internal/assert/assertion_error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { SafeSet } = require("internal/primordials");
const { inspect } = require("internal/util/inspect");
const colors = require("internal/util/colors");
const { validateObject } = require("internal/validators");
const { myersDiff, printMyersDiff, printSimpleMyersDiff } = require("internal/assert/myers_diff") as typeof Internal;
const { printMyersDiff, printSimpleMyersDiff } = require("internal/assert/myers_diff") as typeof Internal;

const ErrorCaptureStackTrace = Error.captureStackTrace;
const ObjectAssign = Object.assign;
Expand All @@ -19,21 +19,12 @@ const StringPrototypeSlice = String.prototype.slice;
const StringPrototypeSplit = String.prototype.split;

declare namespace Internal {
const enum Operation {
Insert = 0,
Delete = 1,
Equal = 2,
}
interface Diff {
kind: Operation;
value: string;
}

function myersDiff(actual: string, expected: string, checkCommaDisparity?: boolean, lines?: boolean): string;
// todo

function printMyersDiff(...args: any[]): any;
function printSimpleMyersDiff(...args: any[]): any;
function printSimpleMyersDiff(actual: string, expected: string): string;
function printMyersDiff(
actual: string,
expected: string,
checkCommaDisparity: boolean,
): { message: string; skipped: boolean };
}

const kReadableOperator = {
Expand Down Expand Up @@ -113,9 +104,7 @@ function getColoredMyersDiff(actual, expected) {
const header = `${colors.green}actual${colors.white} ${colors.red}expected${colors.white}`;
const skipped = false;

// const diff = myersDiff(StringPrototypeSplit.$call(actual, ""), StringPrototypeSplit.$call(expected, ""));
const diff = myersDiff(actual, expected, false, false);
let message = printSimpleMyersDiff(diff);
let message = printSimpleMyersDiff(actual, expected);

if (skipped) {
message += "...";
Expand Down Expand Up @@ -224,8 +213,7 @@ function createErrDiff(actual, expected, operator, customMessage, diffType = "si
const checkCommaDisparity = actual != null && typeof actual === "object";
let myersDiffMessage;
try {
const diff = myersDiff(inspectedActual, inspectedExpected, checkCommaDisparity, true);
myersDiffMessage = printMyersDiff(diff);
myersDiffMessage = printMyersDiff(inspectedActual, inspectedExpected, checkCommaDisparity);
} catch {
myersDiffMessage = undefined;
}
Expand Down
101 changes: 16 additions & 85 deletions src/js/internal/assert/myers_diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,95 +17,26 @@ interface Diff {
}

declare namespace Internal {
export function myersDiff(
actual: string[],
expected: string[],
checkCommaDisparity?: boolean,
lines?: boolean,
): Diff[];
export function myersDiff(actual: string, expected: string, checkCommaDisparity?: boolean, lines?: boolean): Diff[];
/** Diffs by char and renders the `printSimpleMyersDiff` string. */
export function printSimpleMyersDiff(actual: string, expected: string, colors: object): string;
/** Diffs by line and renders the `printMyersDiff` message, collapsing long unchanged runs. */
export function printMyersDiff(
actual: string,
expected: string,
checkCommaDisparity: boolean,
colors: object,
): { message: string; skipped: boolean };
}

const kNopLinesToCollapse = 5;
const native = $rust("node_assert_binding.rs", "generate") as typeof Internal;

const { myersDiff } = $rust("node_assert_binding.rs", "generate") as typeof Internal;

function printSimpleMyersDiff(diff: Diff[]) {
let message = "";

for (let diffIdx = diff.length - 1; diffIdx >= 0; diffIdx--) {
let { kind, value } = diff[diffIdx];
if (typeof value === "number") {
value = String.fromCharCode(value);
}
switch (kind) {
case Operation.Insert:
message += `${colors.green}${value}${colors.white}`;
break;
case Operation.Delete:
message += `${colors.red}${value}${colors.white}`;
break;
case Operation.Equal:
message += `${colors.white}${value}${colors.white}`;
break;
default:
throw new TypeError(`Invalid diff operation kind: ${kind}`); // should be unreachable
}
}

return `\n${message}`;
function printSimpleMyersDiff(actual: string, expected: string) {
return native.printSimpleMyersDiff(actual, expected, colors);
}

function printMyersDiff(diff: Diff[], _simple = false) {
let message = "";
let skipped = false;
let nopCount = 0;

for (let diffIdx = diff.length - 1; diffIdx >= 0; diffIdx--) {
const { kind, value } = diff[diffIdx];
$assert(
typeof value !== "number",
"printMyersDiff is only called for line diffs, which never return numeric char code values.",
);
const previousType = diffIdx < diff.length - 1 ? diff[diffIdx + 1].kind : null;
const typeChanged = previousType && kind !== previousType;

if (typeChanged && previousType === Operation.Equal) {
// Avoid grouping if only one line would have been grouped otherwise
if (nopCount === kNopLinesToCollapse + 1) {
message += `${colors.white} ${diff[diffIdx + 1].value}\n`;
} else if (nopCount === kNopLinesToCollapse + 2) {
message += `${colors.white} ${diff[diffIdx + 2].value}\n`;
message += `${colors.white} ${diff[diffIdx + 1].value}\n`;
}
if (nopCount >= kNopLinesToCollapse + 3) {
message += `${colors.blue}...${colors.white}\n`;
message += `${colors.white} ${diff[diffIdx + 1].value}\n`;
skipped = true;
}
nopCount = 0;
}

switch (kind) {
case Operation.Insert:
message += `${colors.green}+${colors.white} ${value}\n`;
break;
case Operation.Delete:
message += `${colors.red}-${colors.white} ${value}\n`;
break;
case Operation.Equal:
if (nopCount < kNopLinesToCollapse) {
message += `${colors.white} ${value}\n`;
}
nopCount++;
break;
default:
throw new TypeError(`Invalid diff operation kind: ${kind}`); // should be unreachable
}
}

message = message.trimEnd();

return { message: `\n${message}`, skipped };
function printMyersDiff(actual: string, expected: string, checkCommaDisparity: boolean) {
return native.printMyersDiff(actual, expected, checkCommaDisparity, colors);
}

export default { myersDiff, printMyersDiff, printSimpleMyersDiff };
export default { myersDiff: native.myersDiff, printMyersDiff, printSimpleMyersDiff };
Loading
Loading