Permalink
Cannot retrieve contributors at this time
145 lines (136 sloc)
4.01 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/prettier-linter-helpers/index.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const diff = require('fast-diff'); | |
const LINE_ENDING_RE = /\r\n|[\r\n\u2028\u2029]/; | |
/** | |
* Converts invisible characters to a commonly recognizable visible form. | |
* @param {string} str - The string with invisibles to convert. | |
* @returns {string} The converted string. | |
*/ | |
function showInvisibles(str) { | |
let ret = ''; | |
for (let i = 0; i < str.length; i++) { | |
switch (str[i]) { | |
case ' ': | |
ret += '·'; // Middle Dot, \u00B7 | |
break; | |
case '\n': | |
ret += '⏎'; // Return Symbol, \u23ce | |
break; | |
case '\t': | |
ret += '↹'; // Left Arrow To Bar Over Right Arrow To Bar, \u21b9 | |
break; | |
case '\r': | |
ret += '␍'; // Carriage Return Symbol, \u240D | |
break; | |
default: | |
ret += str[i]; | |
break; | |
} | |
} | |
return ret; | |
} | |
/** | |
* Generate results for differences between source code and formatted version. | |
* | |
* @param {string} source - The original source. | |
* @param {string} prettierSource - The Prettier formatted source. | |
* @returns {Array} - An array containing { operation, offset, insertText, deleteText } | |
*/ | |
function generateDifferences(source, prettierSource) { | |
// fast-diff returns the differences between two texts as a series of | |
// INSERT, DELETE or EQUAL operations. The results occur only in these | |
// sequences: | |
// /-> INSERT -> EQUAL | |
// EQUAL | /-> EQUAL | |
// \-> DELETE | | |
// \-> INSERT -> EQUAL | |
// Instead of reporting issues at each INSERT or DELETE, certain sequences | |
// are batched together and are reported as a friendlier "replace" operation: | |
// - A DELETE immediately followed by an INSERT. | |
// - Any number of INSERTs and DELETEs where the joining EQUAL of one's end | |
// and another's beginning does not have line endings (i.e. issues that occur | |
// on contiguous lines). | |
const results = diff(source, prettierSource); | |
const differences = []; | |
const batch = []; | |
let offset = 0; // NOTE: INSERT never advances the offset. | |
while (results.length) { | |
const result = results.shift(); | |
const op = result[0]; | |
const text = result[1]; | |
switch (op) { | |
case diff.INSERT: | |
case diff.DELETE: | |
batch.push(result); | |
break; | |
case diff.EQUAL: | |
if (results.length) { | |
if (batch.length) { | |
if (LINE_ENDING_RE.test(text)) { | |
flush(); | |
offset += text.length; | |
} else { | |
batch.push(result); | |
} | |
} else { | |
offset += text.length; | |
} | |
} | |
break; | |
default: | |
throw new Error(`Unexpected fast-diff operation "${op}"`); | |
} | |
if (batch.length && !results.length) { | |
flush(); | |
} | |
} | |
return differences; | |
function flush() { | |
let aheadDeleteText = ''; | |
let aheadInsertText = ''; | |
while (batch.length) { | |
const next = batch.shift(); | |
const op = next[0]; | |
const text = next[1]; | |
switch (op) { | |
case diff.INSERT: | |
aheadInsertText += text; | |
break; | |
case diff.DELETE: | |
aheadDeleteText += text; | |
break; | |
case diff.EQUAL: | |
aheadDeleteText += text; | |
aheadInsertText += text; | |
break; | |
} | |
} | |
if (aheadDeleteText && aheadInsertText) { | |
differences.push({ | |
offset, | |
operation: generateDifferences.REPLACE, | |
insertText: aheadInsertText, | |
deleteText: aheadDeleteText, | |
}); | |
} else if (!aheadDeleteText && aheadInsertText) { | |
differences.push({ | |
offset, | |
operation: generateDifferences.INSERT, | |
insertText: aheadInsertText, | |
}); | |
} else if (aheadDeleteText && !aheadInsertText) { | |
differences.push({ | |
offset, | |
operation: generateDifferences.DELETE, | |
deleteText: aheadDeleteText, | |
}); | |
} | |
offset += aheadDeleteText.length; | |
} | |
} | |
generateDifferences.INSERT = 'insert'; | |
generateDifferences.DELETE = 'delete'; | |
generateDifferences.REPLACE = 'replace'; | |
module.exports = { | |
showInvisibles, | |
generateDifferences, | |
}; |