![Malicious npm Package Typosquats react-login-page to Deploy Keylogger](https://cdn.sanity.io/images/cgdhsj6q/production/007b21d9cf9e03ae0bb3f577d1bd59b9d715645a-1024x1024.webp?w=400&fit=max&auto=format)
Research
Security News
Malicious npm Package Typosquats react-login-page to Deploy Keylogger
Socket researchers unpack a typosquatting package with malicious code that logs keystrokes and exfiltrates sensitive data to a remote server.
diff-sequences
Advanced tools
Package description
The diff-sequences package is a utility for finding the longest common subsequence of items in two sequences (arrays). It is typically used for comparing sequences to determine the changes necessary to convert one sequence into another, which is useful in various applications such as diff tools, merging changes, and more.
Finding Longest Common Subsequence (LCS)
This feature allows you to find the longest common subsequence between two arrays. The provided code sample demonstrates how to use the package to compare two arrays and log the LCS.
const diff = require('diff-sequences');
const a = [1, 2, 3, 4, 5];
const b = [2, 3, 5];
const isCommon = (aIndex, bIndex) => a[aIndex] === b[bIndex];
let result = '';
const foundSubsequence = diff(a.length, b.length, isCommon, (nCommon, aCommon, bCommon) => {
for (let i = 0; i < nCommon; i++) {
result += a[aCommon + i];
}
});
console.log(result); // '235'
fast-diff is a JavaScript implementation of the O(ND) difference algorithm. It is used to quickly compute the difference between two strings and can return the result as an array of parts indicating if they are in the first string, second string, or both. It is similar to diff-sequences but is specifically optimized for string comparison rather than generic sequences.
jsdiff (also known as diff) is a library that provides several algorithms for string comparison, including character-by-character, word-by-word, and line-by-line diffs. It offers more features than diff-sequences, such as applying patches or computing diffs in different formats (e.g., JSON). It is more feature-rich but also larger and potentially slower for simple LCS computations.
google-diff-match-patch is a comprehensive library for performing operations required for synchronizing plain text. It includes algorithms for diff, match, and patch operations. It is more complex and feature-complete compared to diff-sequences, which is more focused on the specific task of finding the longest common subsequence.
Changelog
24.0.0
[jest-each]
[BREAKING] Add primitive pretty printing for interpolated titles (#7694)[jest-runtime]
Add jest.isolateModules
for scoped module initialization (#6701)[jest-diff]
[BREAKING] Support diffing numbers and booleans instead of returning null for different ones (#7605)[jest-diff]
[BREAKING] Replace diff
with diff-sequences
package (#6961)[jest-cli]
[BREAKING] Only set error process error codes when they are non-zero (#7363)[jest-config]
[BREAKING] Deprecate setupTestFrameworkScriptFile
in favor of new setupFilesAfterEnv
(#7119)[jest-worker]
[BREAKING] Add functionality to call a setup
method in the worker before the first call and a teardown
method when ending the farm (#7014)[jest-config]
[BREAKING] Set default notifyMode
to failure-change
(#7024)[jest-haste-map]
[BREAKING] Remove support for @providesModule
(#6104)[jest-haste-map]
[BREAKING] Replace internal data structures to improve performance (#6960)[jest-haste-map]
[BREAKING] Use relative paths to allow remote caching (#7020)[jest-haste-map]
[BREAKING] Remove name from hash in HasteMap.getCacheFilePath
(#7218)[babel-preset-jest]
[BREAKING] Export a function instead of an object for Babel 7 compatibility (#7203)[jest-haste-map]
[BREAKING] Expose relative paths when getting the file iterator (#7321)[jest-cli]
[BREAKING] Run code transforms over global{Setup,Teardown}
(#7562)[jest-haste-map]
Add hasteFS.getSize(path)
(#7580)[jest-cli]
Print version ending in -dev
when running a local Jest clone (#7582)[jest-cli]
Add Support for globalSetup
and globalTeardown
in projects (#6865)[jest-runtime]
Add extraGlobals
to config to load extra global variables into the execution vm (#7454)[jest-util]
Export specialChars
containing Unicode characters and ANSI escapes for console output (#7532)[jest-config]
Handle typescript (ts
and tsx
) by default (#7533)[jest-validate]
Add support for comments in package.json
using a "//"
key (#7295)[jest-config]
Add shorthand for watch plugins and runners (#7213)[jest-jasmine2/jest-circus/jest-cli]
Add test.todo (#6996)[pretty-format]
Option to not escape strings in diff messages (#5661)[jest-haste-map]
Add getFileIterator
to HasteFS
for faster file iteration (#7010)[jest-config]
Add readConfigs
function, previously in jest-cli
(#7096)[jest-snapshot]
Enable configurable snapshot paths (#6143)[pretty-format]
Support HTMLCollection and NodeList in DOMCollection plugin (#7125)[jest-runtime]
Pass the normalized configuration to script transformers (#7148)[expect]
Improve report when assertion fails, part 3 (#7152)[jest-runtime]
If require
fails without a file extension, print all files that match with one (#7160)[jest-haste-map]
Make ignorePattern
optional (#7166)[jest-haste-map]
Add getCacheFilePath
to get the path to the cache file for a HasteMap
instance (#7217)[jest-runtime]
Remove cacheDirectory
from ignorePattern
for HasteMap
if not necessary (#7166)[jest-validate]
Add syntax to validate multiple permitted types (#7207)[jest-config]
Accept an array as as well as a string for testRegex
(#7209)[expect/jest-matcher-utils]
Improve report when assertion fails, part 4 (#7241)[expect/jest-matcher-utils]
Improve report when assertion fails, part 5 (#7557)[expect]
Check constructor equality in .toStrictEqual() (#7005)[jest-util]
Add jest.getTimerCount()
to get the count of scheduled fake timers (#7285)[jest-config]
Add dependencyExtractor
option to use a custom module to extract dependencies from files (#7313, #7349, #7350, #7362)[jest-haste-map]
Accept a getCacheKey
method in hasteImplModulePath
modules to reset the cache when the logic changes (#7350)[jest-config]
Add haste.computeSha1
option to compute the sha-1 of the files in the haste map (#7345)[expect]
expect(Infinity).toBeCloseTo(Infinity)
Treats Infinity
as equal in toBeCloseTo matcher (#7405)[jest-worker]
Add node worker-thread support to jest-worker (#7408)[jest-config]
Allow bail
setting to be configured with a number allowing tests to abort after n
of failures (#7335)[jest-config]
Allow % based configuration of --max-workers
(#7494)[jest-runner]
Instantiate the test environment class with the current testPath
(#7442)[jest-config]
Always resolve jest-environment-jsdom from jest-config (#7476)[expect]
Improve report when assertion fails, part 6 (#7621)[jest-worker]
Add enableWorkerThreads
option to explicitly opt-in to worker_threads
if available (#7681)[expect]
Accept inherited properties in toHaveProperty
matcher (#7686)[jest-diff]
Do not claim that -0
and 0
have no visual difference (#7605)[jest-mock]
Fix automock for numeric function names (#7653)[jest-config]
Ensure existsSync
is only called with a string parameter (#7607)[expect]
toStrictEqual
considers sparseness of arrays. (#7591)[jest-cli]
Fix empty coverage data for untested files (#7388)[jest-cli]
[BREAKING] Do not use text-summary
coverage reporter by default if other reporters are configured (#7058)[jest-mock]
[BREAKING] Fix bugs with mock/spy result tracking of recursive functions (#6381)[jest-haste-map]
[BREAKING] Recover files correctly after haste name collisions are fixed (#7329)[pretty-format]
[BREAKING] Omit non-enumerable symbol properties (#7448)[*]
[BREAKING] Upgrade to Babel 7, dropping support for Babel 6 (#7016)[jest-cli]
Avoid watch mode causing bad terminal behavior in some cases (#7523)[jest-runner/jest-worker]
Fix missing console output in verbose mode (#6871)[expect]
Standardize file naming in expect
(#7306)[jest-each]
Add empty array validation check (#7249)[jest-cli]
Interrupt tests if interactive watch plugin key is pressed (#7222)[jest-each]
Add each array validation check (#7033)[jest-haste-map]
Do not visit again files with the same sha-1 (#6990)[jest-jasmine2]
Fix memory leak in Error objects hold by the framework (#6965)[jest-haste-map]
Fixed Haste whitelist generation for scoped modules on Windows (#6980)[jest-mock]
Fix inheritance of static properties and methods in mocks (#7003)[jest-mock]
Fix mocking objects without Object.prototype
in their prototype chain (#7003)[jest-mock]
Check _isMockFunction
is true rather than truthy on potential mocks (#7017)[jest-cli]
Update jest-cli to show git ref in message when using changedSince
(#7028)[jest-jasmine2
] Fix crash when test return Promise rejected with null (#7049)[jest-runtime]
Check _isMockFunction
is true rather than truthy on potential global mocks (#7017)[jest-jasmine]
Show proper error message from async assert
errors (#6821)[jest-jasmine2]
Better error message when a describe block is empty (#6372)[jest-jasmine2]
Pending calls inside async tests are reported as pending not failed (#6782)[jest-circus]
Better error message when a describe block is empty (#6372)[jest-jasmine2]
Add missing testLocationResults for xit
and fit
(#6482)[expect]
Return false from asymmetric matchers if received value isn’t string (#7107)[jest-cli]
Fix unhandled error when a bad revision is provided to changedSince
(#7115)[jest-config]
Moved dynamically assigned cwd
from jest-cli
to default configuration in jest-config
(#7146)[jest-config]
Fix getMaxWorkers
on termux (#7154)[jest-runtime]
Throw an explicit error if js
is missing from moduleFileExtensions
(#7160)[jest-runtime]
Fix missing coverage when using negative glob pattern in testMatch
(#7170)[*]
Ensure maxWorkers
is at least 1 (was 0 in some cases where there was only 1 CPU) (#7182)[jest-runtime]
Fix transform cache invalidation when requiring a test file from multiple projects (#7186)[jest-changed-files]
Return correctly the changed files when using lastCommit=true
on Mercurial repositories (#7228)[babel-jest]
Cache includes babel environment variables (#7239)[jest-config]
Use strings instead of RegExp
instances in normalized configuration (#7251)[jest-circus]
Make sure to display real duration even if time is mocked (#7264)[expect]
Improves the failing message for toStrictEqual
matcher. (#7224)[expect]
Improves the failing message for toEqual
matcher. (#7325)[jest-resolve]
Fix not being able to resolve path to mapped file with custom platform (#7312)[jest-message-util]
Improve parsing of error messages for unusually formatted stack traces (#7319)[jest-runtime]
Ensure error message text is not lost on errors with code frames (#7319)[jest-haste-map]
Fix to resolve path that is start with words same as rootDir (#7324)[expect]
Fix toMatchObject matcher when used with Object.create(null)
(#7334)[jest-haste-map]
Remove legacy condition for duplicate module detection (#7333)[jest-haste-map]
Fix require
detection with trailing commas and ignore import typeof
modules (#7385)[jest-cli]
Fix to set prettierPath via config file (#7412)[expect]
Test more precisely for class instance getters (#7477)[jest-cli]
Support dashed args (#7497)[jest-cli]
Fix to run in band tests if watch mode enable when runInBand arg used (#7518)[jest-runtime]
Fix mistake as test files when run coverage issue. (#7506)[jest-cli]
print info about passWithNoTests flag (#7309)[pretty-format]
Omit unnecessary symbol filter for object keys (#7457)[jest-runtime]
Fix requireActual
on node_modules with mock present (#7404)[jest-resolve]
Fix isBuiltinModule
to support versions of node without module.builtinModules
(#7565)[babel-jest]
Set cwd
to be resilient to it changing during the runtime of the tests (#7574)[jest-snapshot]
Write and read snapshots from disk even if fs
is mocked (#7080)[jest-config]
Normalize config.cwd
and config.rootDir
using `realpath (#7598)[jest-environment-node]
Fix buffer property is not ArrayBuffer issue. (#7626)[babel-plugin-jest-hoist]
Ignore TS type annotations when looking for out-of-scope references (#7641)[jest-config]
Add name to project if one does not exist to pick correct resolver (#5862)[jest-runtime]
Pass watchPathIgnorePatterns
to Haste instance (#7585)[jest-runtime]
Resolve mock files via Haste when using require.resolve
(#7687)[*]
[BREAKING] Require Node.js 6+ for all packages (#7258)[jest-util]
[BREAKING] Remove long-deprecated globals for fake timers (#7285)[*]
[BREAKING] Upgrade to Micromatch 3 (#6650)[*]
[BREAKING] Remove regenerator-runtime injection (#7595)[jest-worker]
Disable worker_threads
to avoid issues with libraries to ready for it (#7681)[docs]
Fix message property in custom matcher example to return a function instead of a constant. (#7426)[jest-circus]
Standardize file naming in jest-circus
(#7301)[docs]
Add synchronous test.each setup (#7150)[docs]
Add this.extend
to the Custom Matchers API reference (#7130)[docs]
Fix default value for coverageReporters
value in configuration docs (#7126)[docs]
Add link for jest-extended in expect docs (#7078)[jest-util]
Add ErrorWithStack class (#7067)[docs]
Document --runTestsByPath
CLI parameter (#7046)[docs]
Fix babel-core installation instructions (#6745)[docs]
Explain how to rewrite assertions to avoid large irrelevant diff (#6971)[examples]
add example using Babel 7 (#6983)[docs]
Replace shallow equality with referential identity in ExpectAPI.md
(#6991)[jest-changed-files]
Refactor to use execa
over child_process
(#6987)[*]
Bump dated dependencies (#6978)[scripts]
Don’t make empty sub-folders for ignored files in build folder (#7001)[docs]
Add missing export statement in puppeteer_environment.js
under docs/Puppeteer.md
(#7127)[docs]
Removed useless expect.assertions in TestingAsyncCode.md
(#7131)[docs]
Remove references to @providesModule
which isn't supported anymore (#7147)[docs]
Update setupFiles
documentation for clarity (#7187)[docs]
Change require.require*
to jest.require*
(#7210)[jest-circus]
Add readme.md (#7198)[jest-editor-support]
Remove from the repository (#7232)[jest-test-typescript-parser]
Remove from the repository (#7232)[tests]
Free tests from the dependency on value of FORCE_COLOR (#6585)[*]
Add babel plugin to make sure Jest is unaffected by fake Promise implementations (#7225)[docs]
Add correct default value for testUrl
config option (#7277)[docs]
Remove duplicate code in MockFunctions
(#7297)[*]
Add check for Facebook copyright headers on CI (#7370)[*]
Update Facebook copyright headers (#7589)[jest-haste-map]
Refactor dependencyExtractor
and tests (#7385)[docs]
Clearify conditional setting of NODE_ENV
(#7369)[docs]
Clarify conditional setting of NODE_ENV
(#7369)[*]
Standardize file names (#7316, #7266, #7238, #7314, #7467, #7464), #7471)[docs]
Add testPathIgnorePatterns
in CLI documentation (#7440)[docs]
Removed misleading text about describe()
grouping together tests into a test suite (#7434)[diff-sequences]
Add performance benchmark to package (#7603)[*]
Replace as many Object.assign
with object spread as possible (#7627)[ci]
Initial support for Azure Pipelines (#7556)[jest-mock]
Improve getType
function performance. (#7159)Readme
Compare items in two sequences to find a longest common subsequence.
The items not in common are the items to delete or insert in a shortest edit script.
To maximize flexibility and minimize memory, you write callback functions as configuration:
Input function isCommon(aIndex, bIndex)
compares items at indexes in the sequences and returns a truthy/falsey value. This package might call your function more than once for some pairs of indexes.
===
operator, Object.is
method, or other criterion.Output function foundSubsequence(nCommon, aCommon, bCommon)
receives the number of adjacent items and starting indexes of each common subsequence. If sequences do not have common items, then this package does not call your function.
If N is the sum of lengths of sequences and L is length of a longest common subsequence, then D = N – 2L is the number of differences in the corresponding shortest edit script.
An O(ND) Difference Algorithm and Its Variations by Eugene W. Myers is fast when sequences have few differences.
This package implements the linear space variation with optimizations so it is fast even when sequences have many differences.
To add this package as a dependency of a project, do either of the following:
npm install diff-sequences
yarn add diff-sequences
To use diff
as the name of the default export from this package, do either of the following:
var diff = require('diff-sequences'); // CommonJS modules
import diff from 'diff-sequences'; // ECMAScript modules
Call diff
with the lengths of sequences and your callback functions:
/* eslint-disable no-var */
var a = ['a', 'b', 'c', 'a', 'b', 'b', 'a'];
var b = ['c', 'b', 'a', 'b', 'a', 'c'];
function isCommon(aIndex, bIndex) {
return a[aIndex] === b[bIndex];
}
function foundSubsequence(nCommon, aCommon, bCommon) {
// see examples
}
diff(a.length, b.length, isCommon, foundSubsequence);
Some sequences (for example, a
and b
in the example of usage) have more than one longest common subsequence.
This package finds the following common items:
comparisons of common items | values | output arguments |
---|---|---|
a[2] === b[0] | 'c' | foundSubsequence(1, 2, 0) |
a[4] === b[1] | 'b' | foundSubsequence(1, 4, 1) |
a[5] === b[3] && a[6] === b[4] | 'b', 'a' | foundSubsequence(2, 5, 3) |
The “edit graph” analogy in the Myers paper shows the following common items:
comparisons of common items | values |
---|---|
a[2] === b[0] | 'c' |
a[3] === b[2] && a[4] === b[3] | 'a', 'b' |
a[6] === b[4] | 'a' |
Various packages which implement the Myers algorithm will always agree on the length of a longest common subsequence, but might sometimes disagree on which items are in it.
/* eslint-disable no-var */
// Return length of longest common subsequence according to === operator.
function countCommonItems(a, b) {
var n = 0;
function isCommon(aIndex, bIndex) {
return a[aIndex] === b[bIndex];
}
function foundSubsequence(nCommon) {
n += nCommon;
}
diff(a.length, b.length, isCommon, foundSubsequence);
return n;
}
var commonLength = countCommonItems(
['a', 'b', 'c', 'a', 'b', 'b', 'a'],
['c', 'b', 'a', 'b', 'a', 'c'],
);
category of items | expression | value |
---|---|---|
in common | commonLength | 4 |
to delete from a | a.length - commonLength | 3 |
to insert from b | b.length - commonLength | 2 |
If the length difference b.length - a.length
is:
a
b
a
and insert from b
a
and insert from b
In this example, 6 - 7
is:
1
is the minimum number of items to delete from a
2
is the number of additional items to delete from a
and insert from b
// Return array of items in longest common subsequence according to Object.is method.
const findCommonItems = (a, b) => {
const array = [];
diff(
a.length,
b.length,
(aIndex, bIndex) => Object.is(a[aIndex], b[bIndex]),
(nCommon, aCommon) => {
for (; nCommon !== 0; nCommon -= 1, aCommon += 1) {
array.push(a[aCommon]);
}
},
);
return array;
};
const commonItems = findCommonItems(
['a', 'b', 'c', 'a', 'b', 'b', 'a'],
['c', 'b', 'a', 'b', 'a', 'c'],
);
i | commonItems[i] | aIndex |
---|---|---|
0 | 'c' | 2 |
1 | 'b' | 4 |
2 | 'b' | 5 |
3 | 'a' | 6 |
Instead of slicing array-like objects, you can adjust indexes in your callback functions.
// Diff index intervals that are half open [start, end) like array slice method.
const diffIndexIntervals = (a, aStart, aEnd, b, bStart, bEnd) => {
// Validate: 0 <= aStart and aStart <= aEnd and aEnd <= a.length
// Validate: 0 <= bStart and bStart <= bEnd and bEnd <= b.length
diff(
aEnd - aStart,
bEnd - bStart,
(aIndex, bIndex) => Object.is(a[aStart + aIndex], b[bStart + bIndex]),
(nCommon, aCommon, bCommon) => {
// aStart + aCommon, bStart + bCommon
},
);
// After the last common subsequence, do any remaining work.
};
Linux or Unix has a diff
command to compare files line by line. Its output is a shortest edit script:
// Given zero-based half-open range [start, end) of array indexes,
// return one-based closed range [start + 1, end] as string.
const getRange = (start, end) =>
start + 1 === end ? `${start + 1}` : `${start + 1},${end}`;
// Given index intervals of lines to delete or insert, or both, or neither,
// push formatted diff lines onto array.
const pushDelIns = (aLines, aIndex, aEnd, bLines, bIndex, bEnd, array) => {
const deleteLines = aIndex !== aEnd;
const insertLines = bIndex !== bEnd;
const changeLines = deleteLines && insertLines;
if (changeLines) {
array.push(getRange(aIndex, aEnd) + 'c' + getRange(bIndex, bEnd));
} else if (deleteLines) {
array.push(getRange(aIndex, aEnd) + 'd' + String(bIndex));
} else if (insertLines) {
array.push(String(aIndex) + 'a' + getRange(bIndex, bEnd));
} else {
return;
}
for (; aIndex !== aEnd; aIndex += 1) {
array.push('< ' + aLines[aIndex]); // delete is less than
}
if (changeLines) {
array.push('---');
}
for (; bIndex !== bEnd; bIndex += 1) {
array.push('> ' + bLines[bIndex]); // insert is greater than
}
};
// Given content of two files, return emulated output of diff utility.
const findShortestEditScript = (a, b) => {
const aLines = a.split('\n');
const bLines = b.split('\n');
const aLength = aLines.length;
const bLength = bLines.length;
const isCommon = (aIndex, bIndex) => aLines[aIndex] === bLines[bIndex];
let aIndex = 0;
let bIndex = 0;
const array = [];
const foundSubsequence = (nCommon, aCommon, bCommon) => {
pushDelIns(aLines, aIndex, aCommon, bLines, bIndex, bCommon, array);
aIndex = aCommon + nCommon; // number of lines compared in a
bIndex = bCommon + nCommon; // number of lines compared in b
};
diff(aLength, bLength, isCommon, foundSubsequence);
// After the last common subsequence, push remaining change lines.
pushDelIns(aLines, aIndex, aLength, bLines, bIndex, bLength, array);
return array.length === 0 ? '' : array.join('\n') + '\n';
};
Here is simplified code to format changed and unchanged lines in expected and received values after a test fails in Jest:
// Format diff with minus or plus for change lines and space for common lines.
const formatDiffLines = (a, b) => {
// Jest depends on pretty-format package to serialize objects as strings.
// Unindented for comparison to avoid distracting differences:
const aLinesUn = format(a, {indent: 0 /*, other options*/}).split('\n');
const bLinesUn = format(b, {indent: 0 /*, other options*/}).split('\n');
// Indented to display changed and unchanged lines:
const aLinesIn = format(a, {indent: 2 /*, other options*/}).split('\n');
const bLinesIn = format(b, {indent: 2 /*, other options*/}).split('\n');
const aLength = aLinesIn.length; // Validate: aLinesUn.length === aLength
const bLength = bLinesIn.length; // Validate: bLinesUn.length === bLength
const isCommon = (aIndex, bIndex) => aLinesUn[aIndex] === bLinesUn[bIndex];
// Only because the GitHub Flavored Markdown doc collapses adjacent spaces,
// this example code and the following table represent spaces as middle dots.
let aIndex = 0;
let bIndex = 0;
const array = [];
const foundSubsequence = (nCommon, aCommon, bCommon) => {
for (; aIndex !== aCommon; aIndex += 1) {
array.push('-·' + aLinesIn[aIndex]); // delete is minus
}
for (; bIndex !== bCommon; bIndex += 1) {
array.push('+·' + bLinesIn[bIndex]); // insert is plus
}
for (; nCommon !== 0; nCommon -= 1, aIndex += 1, bIndex += 1) {
// For common lines, received indentation seems more intuitive.
array.push('··' + bLinesIn[bIndex]); // common is space
}
};
diff(aLength, bLength, isCommon, foundSubsequence);
// After the last common subsequence, push remaining change lines.
for (; aIndex !== aLength; aIndex += 1) {
array.push('-·' + aLinesIn[aIndex]);
}
for (; bIndex !== bLength; bIndex += 1) {
array.push('+·' + bLinesIn[bIndex]);
}
return array;
};
const expected = {
searching: '',
sorting: {
ascending: true,
fieldKey: 'what',
},
};
const received = {
searching: '',
sorting: [
{
descending: false,
fieldKey: 'what',
},
],
};
const diffLines = formatDiffLines(expected, received);
If N is the sum of lengths of sequences and L is length of a longest common subsequence, then N – L is length of an array of diff lines. In this example, N is 7 + 9, L is 5, and N – L is 11.
i | diffLines[i] | aIndex | bIndex |
---|---|---|---|
0 | '··Object {' | 0 | 0 |
1 | '····"searching": "",' | 1 | 1 |
2 | '-···"sorting": Object {' | 2 | |
3 | '-·····"ascending": true,' | 3 | |
4 | '+·····"sorting": Array [' | 2 | |
5 | '+·······Object {' | 3 | |
6 | '+·········"descending": false,' | 4 | |
7 | '··········"fieldKey": "what",' | 4 | 5 |
8 | '········},' | 5 | 6 |
9 | '+·····],' | 7 | |
10 | '··}' | 6 | 8 |
Here is simplified code to find changed and unchanged substrings within adjacent changed lines in expected and received values after a test fails in Jest:
// Return diff items for strings (compatible with diff-match-patch package).
const findDiffItems = (a, b) => {
const isCommon = (aIndex, bIndex) => a[aIndex] === b[bIndex];
let aIndex = 0;
let bIndex = 0;
const array = [];
const foundSubsequence = (nCommon, aCommon, bCommon) => {
if (aIndex !== aCommon) {
array.push([-1, a.slice(aIndex, aCommon)]); // delete is -1
}
if (bIndex !== bCommon) {
array.push([1, b.slice(bIndex, bCommon)]); // insert is 1
}
aIndex = aCommon + nCommon; // number of characters compared in a
bIndex = bCommon + nCommon; // number of characters compared in b
array.push([0, a.slice(aCommon, aIndex)]); // common is 0
};
diff(a.length, b.length, isCommon, foundSubsequence);
// After the last common subsequence, push remaining change items.
if (aIndex !== a.length) {
array.push([-1, a.slice(aIndex)]);
}
if (bIndex !== b.length) {
array.push([1, b.slice(bIndex)]);
}
return array;
};
const expectedDeleted = ['"sorting": Object {', '"ascending": true,'].join(
'\n',
);
const receivedInserted = [
'"sorting": Array [',
'Object {',
'"descending": false,',
].join('\n');
const diffItems = findDiffItems(expectedDeleted, receivedInserted);
i | diffItems[i][0] | diffItems[i][1] |
---|---|---|
0 | 0 | '"sorting": ' |
1 | 1 | 'Array [\n' |
2 | 0 | 'Object {\n"' |
3 | -1 | 'a' |
4 | 1 | 'de' |
5 | 0 | 'scending": ' |
6 | -1 | 'tru' |
7 | 1 | 'fals' |
8 | 0 | 'e,' |
The length difference b.length - a.length
is equal to the sum of diffItems[i][0]
values times diffItems[i][1]
lengths. In this example, the difference 48 - 38
is equal to the sum 10
.
category of diff item | [0] | [1] lengths | subtotal |
---|---|---|---|
in common | 0 | 11 + 10 + 11 + 2 | 0 |
to delete from a | –1 | 1 + 3 | -4 |
to insert from b | 1 | 8 + 2 + 4 | 14 |
Instead of formatting the changed substrings with escape codes for colors in the foundSubsequence
function to save memory, this example spends memory to gain flexibility before formatting, so a separate heuristic algorithm might modify the generic array of diff items to show changes more clearly:
i | diffItems[i][0] | diffItems[i][1] |
---|---|---|
6 | -1 | 'true' |
7 | 1 | 'false' |
8 | 0 | ',' |
For expected and received strings of serialized data, the result of finding changed lines, and then finding changed substrings within adjacent changed lines (as in the preceding two examples) sometimes displays the changes in a more intuitive way than the result of finding changed substrings, and then splitting them into changed and unchanged lines.
FAQs
Unknown package
The npm package diff-sequences receives a total of 22,849,201 weekly downloads. As such, diff-sequences popularity was classified as popular.
We found that diff-sequences demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers unpack a typosquatting package with malicious code that logs keystrokes and exfiltrates sensitive data to a remote server.
Security News
The JavaScript community has launched the e18e initiative to improve ecosystem performance by cleaning up dependency trees, speeding up critical parts of the ecosystem, and documenting lighter alternatives to established tools.
Product
Socket now supports four distinct alert actions instead of the previous two, and alert triaging allows users to override the actions taken for all individual alerts.