Atom eve seo

This commit is contained in:
2026-07-15 18:08:51 +02:00
parent 48e9e2992c
commit 7b81464a1d
665 changed files with 219503 additions and 894 deletions

257
.output/server/node_modules/diff/libesm/patch/apply.js generated vendored Normal file
View File

@@ -0,0 +1,257 @@
import { hasOnlyWinLineEndings, hasOnlyUnixLineEndings } from '../util/string.js';
import { isWin, isUnix, unixToWin, winToUnix } from './line-endings.js';
import { parsePatch } from './parse.js';
import distanceIterator from '../util/distance-iterator.js';
/**
* attempts to apply a unified diff patch.
*
* Hunks are applied first to last.
* `applyPatch` first tries to apply the first hunk at the line number specified in the hunk header, and with all context lines matching exactly.
* If that fails, it tries scanning backwards and forwards, one line at a time, to find a place to apply the hunk where the context lines match exactly.
* If that still fails, and `fuzzFactor` is greater than zero, it increments the maximum number of mismatches (missing, extra, or changed context lines) that there can be between the hunk context and a region where we are trying to apply the patch such that the hunk will still be considered to match.
* Regardless of `fuzzFactor`, lines to be deleted in the hunk *must* be present for a hunk to match, and the context lines *immediately* before and after an insertion must match exactly.
*
* Once a hunk is successfully fitted, the process begins again with the next hunk.
* Regardless of `fuzzFactor`, later hunks must be applied later in the file than earlier hunks.
*
* If a hunk cannot be successfully fitted *anywhere* with fewer than `fuzzFactor` mismatches, `applyPatch` fails and returns `false`.
*
* If a hunk is successfully fitted but not at the line number specified by the hunk header, all subsequent hunks have their target line number adjusted accordingly.
* (e.g. if the first hunk is applied 10 lines below where the hunk header said it should fit, `applyPatch` will *start* looking for somewhere to apply the second hunk 10 lines below where its hunk header says it goes.)
*
* If the patch was applied successfully, returns a string containing the patched text.
* If the patch could not be applied (because some hunks in the patch couldn't be fitted to the text in `source`), `applyPatch` returns false.
*
* @param patch a string diff or the output from the `parsePatch` or `structuredPatch` methods.
*/
export function applyPatch(source, patch, options = {}) {
let patches;
if (typeof patch === 'string') {
patches = parsePatch(patch);
}
else if (Array.isArray(patch)) {
patches = patch;
}
else {
patches = [patch];
}
if (patches.length > 1) {
throw new Error('applyPatch only works with a single input.');
}
return applyStructuredPatch(source, patches[0], options);
}
function applyStructuredPatch(source, patch, options = {}) {
if (options.autoConvertLineEndings || options.autoConvertLineEndings == null) {
if (hasOnlyWinLineEndings(source) && isUnix(patch)) {
patch = unixToWin(patch);
}
else if (hasOnlyUnixLineEndings(source) && isWin(patch)) {
patch = winToUnix(patch);
}
}
// Apply the diff to the input
const lines = source.split('\n'), hunks = patch.hunks, compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent), fuzzFactor = options.fuzzFactor || 0;
let minLine = 0;
if (fuzzFactor < 0 || !Number.isInteger(fuzzFactor)) {
throw new Error('fuzzFactor must be a non-negative integer');
}
// Special case for empty patch.
if (!hunks.length) {
return source;
}
// Before anything else, handle EOFNL insertion/removal. If the patch tells us to make a change
// to the EOFNL that is redundant/impossible - i.e. to remove a newline that's not there, or add a
// newline that already exists - then we either return false and fail to apply the patch (if
// fuzzFactor is 0) or simply ignore the problem and do nothing (if fuzzFactor is >0).
// If we do need to remove/add a newline at EOF, this will always be in the final hunk:
let prevLine = '', removeEOFNL = false, addEOFNL = false;
for (let i = 0; i < hunks[hunks.length - 1].lines.length; i++) {
const line = hunks[hunks.length - 1].lines[i];
if (line[0] == '\\') {
if (prevLine[0] == '+') {
removeEOFNL = true;
}
else if (prevLine[0] == '-') {
addEOFNL = true;
}
}
prevLine = line;
}
if (removeEOFNL) {
if (addEOFNL) {
// This means the final line gets changed but doesn't have a trailing newline in either the
// original or patched version. In that case, we do nothing if fuzzFactor > 0, and if
// fuzzFactor is 0, we simply validate that the source file has no trailing newline.
if (!fuzzFactor && lines[lines.length - 1] == '') {
return false;
}
}
else if (lines[lines.length - 1] == '') {
lines.pop();
}
else if (!fuzzFactor) {
return false;
}
}
else if (addEOFNL) {
if (lines[lines.length - 1] != '') {
lines.push('');
}
else if (!fuzzFactor) {
return false;
}
}
/**
* Checks if the hunk can be made to fit at the provided location with at most `maxErrors`
* insertions, substitutions, or deletions, while ensuring also that:
* - lines deleted in the hunk match exactly, and
* - wherever an insertion operation or block of insertion operations appears in the hunk, the
* immediately preceding and following lines of context match exactly
*
* `toPos` should be set such that lines[toPos] is meant to match hunkLines[0].
*
* If the hunk can be applied, returns an object with properties `oldLineLastI` and
* `replacementLines`. Otherwise, returns null.
*/
function applyHunk(hunkLines, toPos, maxErrors, hunkLinesI = 0, lastContextLineMatched = true, patchedLines = [], patchedLinesLength = 0) {
let nConsecutiveOldContextLines = 0;
let nextContextLineMustMatch = false;
for (; hunkLinesI < hunkLines.length; hunkLinesI++) {
const hunkLine = hunkLines[hunkLinesI], operation = (hunkLine.length > 0 ? hunkLine[0] : ' '), content = (hunkLine.length > 0 ? hunkLine.substr(1) : hunkLine);
if (operation === '-') {
if (compareLine(toPos + 1, lines[toPos], operation, content)) {
toPos++;
nConsecutiveOldContextLines = 0;
}
else {
if (!maxErrors || lines[toPos] == null) {
return null;
}
patchedLines[patchedLinesLength] = lines[toPos];
return applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1);
}
}
if (operation === '+') {
if (!lastContextLineMatched) {
return null;
}
patchedLines[patchedLinesLength] = content;
patchedLinesLength++;
nConsecutiveOldContextLines = 0;
nextContextLineMustMatch = true;
}
if (operation === ' ') {
nConsecutiveOldContextLines++;
patchedLines[patchedLinesLength] = lines[toPos];
if (compareLine(toPos + 1, lines[toPos], operation, content)) {
patchedLinesLength++;
lastContextLineMatched = true;
nextContextLineMustMatch = false;
toPos++;
}
else {
if (nextContextLineMustMatch || !maxErrors) {
return null;
}
// Consider 3 possibilities in sequence:
// 1. lines contains a *substitution* not included in the patch context, or
// 2. lines contains an *insertion* not included in the patch context, or
// 3. lines contains a *deletion* not included in the patch context
// The first two options are of course only possible if the line from lines is non-null -
// i.e. only option 3 is possible if we've overrun the end of the old file.
return (lines[toPos] && (applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength + 1) || applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1)) || applyHunk(hunkLines, toPos, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength));
}
}
}
// Before returning, trim any unmodified context lines off the end of patchedLines and reduce
// toPos (and thus oldLineLastI) accordingly. This allows later hunks to be applied to a region
// that starts in this hunk's trailing context.
patchedLinesLength -= nConsecutiveOldContextLines;
toPos -= nConsecutiveOldContextLines;
patchedLines.length = patchedLinesLength;
return {
patchedLines,
oldLineLastI: toPos - 1
};
}
const resultLines = [];
// Search best fit offsets for each hunk based on the previous ones
let prevHunkOffset = 0;
for (let i = 0; i < hunks.length; i++) {
const hunk = hunks[i];
let hunkResult;
const maxLine = lines.length - hunk.oldLines + fuzzFactor;
let toPos;
for (let maxErrors = 0; maxErrors <= fuzzFactor; maxErrors++) {
toPos = hunk.oldStart + prevHunkOffset - 1;
const iterator = distanceIterator(toPos, minLine, maxLine);
for (; toPos !== undefined; toPos = iterator()) {
hunkResult = applyHunk(hunk.lines, toPos, maxErrors);
if (hunkResult) {
break;
}
}
if (hunkResult) {
break;
}
}
if (!hunkResult) {
return false;
}
// Copy everything from the end of where we applied the last hunk to the start of this hunk
for (let i = minLine; i < toPos; i++) {
resultLines.push(lines[i]);
}
// Add the lines produced by applying the hunk:
for (let i = 0; i < hunkResult.patchedLines.length; i++) {
const line = hunkResult.patchedLines[i];
resultLines.push(line);
}
// Set lower text limit to end of the current hunk, so next ones don't try
// to fit over already patched text
minLine = hunkResult.oldLineLastI + 1;
// Note the offset between where the patch said the hunk should've applied and where we
// applied it, so we can adjust future hunks accordingly:
prevHunkOffset = toPos + 1 - hunk.oldStart;
}
// Copy over the rest of the lines from the old text
for (let i = minLine; i < lines.length; i++) {
resultLines.push(lines[i]);
}
return resultLines.join('\n');
}
/**
* applies one or more patches.
*
* `patch` may be either an array of structured patch objects, or a string representing a patch in unified diff format (which may patch one or more files).
*
* This method will iterate over the contents of the patch and apply to data provided through callbacks. The general flow for each patch index is:
*
* - `options.loadFile(index, callback)` is called. The caller should then load the contents of the file and then pass that to the `callback(err, data)` callback. Passing an `err` will terminate further patch execution.
* - `options.patched(index, content, callback)` is called once the patch has been applied. `content` will be the return value from `applyPatch`. When it's ready, the caller should call `callback(err)` callback. Passing an `err` will terminate further patch execution.
*
* Once all patches have been applied or an error occurs, the `options.complete(err)` callback is made.
*/
export function applyPatches(uniDiff, options) {
const spDiff = typeof uniDiff === 'string' ? parsePatch(uniDiff) : uniDiff;
let currentIndex = 0;
function processIndex() {
const index = spDiff[currentIndex++];
if (!index) {
return options.complete();
}
options.loadFile(index, function (err, data) {
if (err) {
return options.complete(err);
}
const updatedContent = applyPatch(data, index, options);
options.patched(index, updatedContent, function (err) {
if (err) {
return options.complete(err);
}
processIndex();
});
});
}
processIndex();
}

228
.output/server/node_modules/diff/libesm/patch/create.js generated vendored Normal file
View File

@@ -0,0 +1,228 @@
import { diffLines } from '../diff/line.js';
export const INCLUDE_HEADERS = {
includeIndex: true,
includeUnderline: true,
includeFileHeaders: true
};
export const FILE_HEADERS_ONLY = {
includeIndex: false,
includeUnderline: false,
includeFileHeaders: true
};
export const OMIT_HEADERS = {
includeIndex: false,
includeUnderline: false,
includeFileHeaders: false
};
export function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
let optionsObj;
if (!options) {
optionsObj = {};
}
else if (typeof options === 'function') {
optionsObj = { callback: options };
}
else {
optionsObj = options;
}
if (typeof optionsObj.context === 'undefined') {
optionsObj.context = 4;
}
// We copy this into its own variable to placate TypeScript, which thinks
// optionsObj.context might be undefined in the callbacks below.
const context = optionsObj.context;
// @ts-expect-error (runtime check for something that is correctly a static type error)
if (optionsObj.newlineIsToken) {
throw new Error('newlineIsToken may not be used with patch-generation functions, only with diffing functions');
}
if (!optionsObj.callback) {
return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
}
else {
const { callback } = optionsObj;
diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
const patch = diffLinesResultToPatch(diff);
// TypeScript is unhappy without the cast because it does not understand that `patch` may
// be undefined here only if `callback` is StructuredPatchCallbackAbortable:
callback(patch);
} }));
}
function diffLinesResultToPatch(diff) {
// STEP 1: Build up the patch with no "\ No newline at end of file" lines and with the arrays
// of lines containing trailing newline characters. We'll tidy up later...
if (!diff) {
return;
}
diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier
function contextLines(lines) {
return lines.map(function (entry) { return ' ' + entry; });
}
const hunks = [];
let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
for (let i = 0; i < diff.length; i++) {
const current = diff[i], lines = current.lines || splitLines(current.value);
current.lines = lines;
if (current.added || current.removed) {
// If we have previous context, start with that
if (!oldRangeStart) {
const prev = diff[i - 1];
oldRangeStart = oldLine;
newRangeStart = newLine;
if (prev) {
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
oldRangeStart -= curRange.length;
newRangeStart -= curRange.length;
}
}
// Output our changes
for (const line of lines) {
curRange.push((current.added ? '+' : '-') + line);
}
// Track the updated file position
if (current.added) {
newLine += lines.length;
}
else {
oldLine += lines.length;
}
}
else {
// Identical context lines. Track line changes
if (oldRangeStart) {
// Close out any changes that have been output (or join overlapping)
if (lines.length <= context * 2 && i < diff.length - 2) {
// Overlapping
for (const line of contextLines(lines)) {
curRange.push(line);
}
}
else {
// end the range and output
const contextSize = Math.min(lines.length, context);
for (const line of contextLines(lines.slice(0, contextSize))) {
curRange.push(line);
}
const hunk = {
oldStart: oldRangeStart,
oldLines: (oldLine - oldRangeStart + contextSize),
newStart: newRangeStart,
newLines: (newLine - newRangeStart + contextSize),
lines: curRange
};
hunks.push(hunk);
oldRangeStart = 0;
newRangeStart = 0;
curRange = [];
}
}
oldLine += lines.length;
newLine += lines.length;
}
}
// Step 2: eliminate the trailing `\n` from each line of each hunk, and, where needed, add
// "\ No newline at end of file".
for (const hunk of hunks) {
for (let i = 0; i < hunk.lines.length; i++) {
if (hunk.lines[i].endsWith('\n')) {
hunk.lines[i] = hunk.lines[i].slice(0, -1);
}
else {
hunk.lines.splice(i + 1, 0, '\\ No newline at end of file');
i++; // Skip the line we just added, then continue iterating
}
}
}
return {
oldFileName: oldFileName, newFileName: newFileName,
oldHeader: oldHeader, newHeader: newHeader,
hunks: hunks
};
}
}
/**
* creates a unified diff patch.
* @param patch either a single structured patch object (as returned by `structuredPatch`) or an array of them (as returned by `parsePatch`)
*/
export function formatPatch(patch, headerOptions) {
if (!headerOptions) {
headerOptions = INCLUDE_HEADERS;
}
if (Array.isArray(patch)) {
if (patch.length > 1 && !headerOptions.includeFileHeaders) {
throw new Error('Cannot omit file headers on a multi-file patch. '
+ '(The result would be unparseable; how would a tool trying to apply '
+ 'the patch know which changes are to which file?)');
}
return patch.map(p => formatPatch(p, headerOptions)).join('\n');
}
const ret = [];
if (headerOptions.includeIndex && patch.oldFileName == patch.newFileName) {
ret.push('Index: ' + patch.oldFileName);
}
if (headerOptions.includeUnderline) {
ret.push('===================================================================');
}
if (headerOptions.includeFileHeaders) {
ret.push('--- ' + patch.oldFileName + (typeof patch.oldHeader === 'undefined' ? '' : '\t' + patch.oldHeader));
ret.push('+++ ' + patch.newFileName + (typeof patch.newHeader === 'undefined' ? '' : '\t' + patch.newHeader));
}
for (let i = 0; i < patch.hunks.length; i++) {
const hunk = patch.hunks[i];
// Unified Diff Format quirk: If the chunk size is 0,
// the first number is one lower than one would expect.
// https://www.artima.com/weblogs/viewpost.jsp?thread=164293
if (hunk.oldLines === 0) {
hunk.oldStart -= 1;
}
if (hunk.newLines === 0) {
hunk.newStart -= 1;
}
ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines
+ ' +' + hunk.newStart + ',' + hunk.newLines
+ ' @@');
for (const line of hunk.lines) {
ret.push(line);
}
}
return ret.join('\n') + '\n';
}
export function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
if (typeof options === 'function') {
options = { callback: options };
}
if (!(options === null || options === void 0 ? void 0 : options.callback)) {
const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
if (!patchObj) {
return;
}
return formatPatch(patchObj, options === null || options === void 0 ? void 0 : options.headerOptions);
}
else {
const { callback } = options;
structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: patchObj => {
if (!patchObj) {
callback(undefined);
}
else {
callback(formatPatch(patchObj, options.headerOptions));
}
} }));
}
}
export function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {
return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options);
}
/**
* Split `text` into an array of lines, including the trailing newline character (where present)
*/
function splitLines(text) {
const hasTrailingNl = text.endsWith('\n');
const result = text.split('\n').map(line => line + '\n');
if (hasTrailingNl) {
result.pop();
}
else {
result.push(result.pop().slice(0, -1));
}
return result;
}

View File

@@ -0,0 +1,44 @@
export function unixToWin(patch) {
if (Array.isArray(patch)) {
// It would be cleaner if instead of the line below we could just write
// return patch.map(unixToWin)
// but mysteriously TypeScript (v5.7.3 at the time of writing) does not like this and it will
// refuse to compile, thinking that unixToWin could then return StructuredPatch[][] and the
// result would be incompatible with the overload signatures.
// See bug report at https://github.com/microsoft/TypeScript/issues/61398.
return patch.map(p => unixToWin(p));
}
return Object.assign(Object.assign({}, patch), { hunks: patch.hunks.map(hunk => (Object.assign(Object.assign({}, hunk), { lines: hunk.lines.map((line, i) => {
var _a;
return (line.startsWith('\\') || line.endsWith('\r') || ((_a = hunk.lines[i + 1]) === null || _a === void 0 ? void 0 : _a.startsWith('\\')))
? line
: line + '\r';
}) }))) });
}
export function winToUnix(patch) {
if (Array.isArray(patch)) {
// (See comment above equivalent line in unixToWin)
return patch.map(p => winToUnix(p));
}
return Object.assign(Object.assign({}, patch), { hunks: patch.hunks.map(hunk => (Object.assign(Object.assign({}, hunk), { lines: hunk.lines.map(line => line.endsWith('\r') ? line.substring(0, line.length - 1) : line) }))) });
}
/**
* Returns true if the patch consistently uses Unix line endings (or only involves one line and has
* no line endings).
*/
export function isUnix(patch) {
if (!Array.isArray(patch)) {
patch = [patch];
}
return !patch.some(index => index.hunks.some(hunk => hunk.lines.some(line => !line.startsWith('\\') && line.endsWith('\r'))));
}
/**
* Returns true if the patch uses Windows line endings and only Windows line endings.
*/
export function isWin(patch) {
if (!Array.isArray(patch)) {
patch = [patch];
}
return patch.some(index => index.hunks.some(hunk => hunk.lines.some(line => line.endsWith('\r'))))
&& patch.every(index => index.hunks.every(hunk => hunk.lines.every((line, i) => { var _a; return line.startsWith('\\') || line.endsWith('\r') || ((_a = hunk.lines[i + 1]) === null || _a === void 0 ? void 0 : _a.startsWith('\\')); })));
}

147
.output/server/node_modules/diff/libesm/patch/parse.js generated vendored Normal file
View File

@@ -0,0 +1,147 @@
/**
* Parses a patch into structured data, in the same structure returned by `structuredPatch`.
*
* @return a JSON object representation of the a patch, suitable for use with the `applyPatch` method.
*/
export function parsePatch(uniDiff) {
const diffstr = uniDiff.split(/\n/), list = [];
let i = 0;
function parseIndex() {
const index = {};
list.push(index);
// Parse diff metadata
while (i < diffstr.length) {
const line = diffstr[i];
// File header found, end parsing diff metadata
if ((/^(---|\+\+\+|@@)\s/).test(line)) {
break;
}
// Try to parse the line as a diff header, like
// Index: README.md
// or
// diff -r 9117c6561b0b -r 273ce12ad8f1 .hgignore
// or
// Index: something with multiple words
// and extract the filename (or whatever else is used as an index name)
// from the end (i.e. 'README.md', '.hgignore', or
// 'something with multiple words' in the examples above).
//
// TODO: It seems awkward that we indiscriminately trim off trailing
// whitespace here. Theoretically, couldn't that be meaningful -
// e.g. if the patch represents a diff of a file whose name ends
// with a space? Seems wrong to nuke it.
// But this behaviour has been around since v2.2.1 in 2015, so if
// it's going to change, it should be done cautiously and in a new
// major release, for backwards-compat reasons.
// -- ExplodingCabbage
const headerMatch = (/^(?:Index:|diff(?: -r \w+)+)\s+/).exec(line);
if (headerMatch) {
index.index = line.substring(headerMatch[0].length).trim();
}
i++;
}
// Parse file headers if they are defined. Unified diff requires them, but
// there's no technical issues to have an isolated hunk without file header
parseFileHeader(index);
parseFileHeader(index);
// Parse hunks
index.hunks = [];
while (i < diffstr.length) {
const line = diffstr[i];
if ((/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/).test(line)) {
break;
}
else if ((/^@@/).test(line)) {
index.hunks.push(parseHunk());
}
else if (line) {
throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(line));
}
else {
i++;
}
}
}
// Parses the --- and +++ headers, if none are found, no lines
// are consumed.
function parseFileHeader(index) {
const fileHeaderMatch = (/^(---|\+\+\+)\s+/).exec(diffstr[i]);
if (fileHeaderMatch) {
const prefix = fileHeaderMatch[1], data = diffstr[i].substring(3).trim().split('\t', 2), header = (data[1] || '').trim();
let fileName = data[0].replace(/\\\\/g, '\\');
if (fileName.startsWith('"') && fileName.endsWith('"')) {
fileName = fileName.substr(1, fileName.length - 2);
}
if (prefix === '---') {
index.oldFileName = fileName;
index.oldHeader = header;
}
else {
index.newFileName = fileName;
index.newHeader = header;
}
i++;
}
}
// Parses a hunk
// This assumes that we are at the start of a hunk.
function parseHunk() {
var _a;
const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
const hunk = {
oldStart: +chunkHeader[1],
oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
newStart: +chunkHeader[3],
newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
lines: []
};
// Unified Diff Format quirk: If the chunk size is 0,
// the first number is one lower than one would expect.
// https://www.artima.com/weblogs/viewpost.jsp?thread=164293
if (hunk.oldLines === 0) {
hunk.oldStart += 1;
}
if (hunk.newLines === 0) {
hunk.newStart += 1;
}
let addCount = 0, removeCount = 0;
for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === void 0 ? void 0 : _a.startsWith('\\'))); i++) {
const operation = (diffstr[i].length == 0 && i != (diffstr.length - 1)) ? ' ' : diffstr[i][0];
if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
hunk.lines.push(diffstr[i]);
if (operation === '+') {
addCount++;
}
else if (operation === '-') {
removeCount++;
}
else if (operation === ' ') {
addCount++;
removeCount++;
}
}
else {
throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
}
}
// Handle the empty block count case
if (!addCount && hunk.newLines === 1) {
hunk.newLines = 0;
}
if (!removeCount && hunk.oldLines === 1) {
hunk.oldLines = 0;
}
// Perform sanity checking
if (addCount !== hunk.newLines) {
throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
}
if (removeCount !== hunk.oldLines) {
throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
}
return hunk;
}
while (i < diffstr.length) {
parseIndex();
}
return list;
}

View File

@@ -0,0 +1,23 @@
export function reversePatch(structuredPatch) {
if (Array.isArray(structuredPatch)) {
// (See comment in unixToWin for why we need the pointless-looking anonymous function here)
return structuredPatch.map(patch => reversePatch(patch)).reverse();
}
return Object.assign(Object.assign({}, structuredPatch), { oldFileName: structuredPatch.newFileName, oldHeader: structuredPatch.newHeader, newFileName: structuredPatch.oldFileName, newHeader: structuredPatch.oldHeader, hunks: structuredPatch.hunks.map(hunk => {
return {
oldLines: hunk.newLines,
oldStart: hunk.newStart,
newLines: hunk.oldLines,
newStart: hunk.oldStart,
lines: hunk.lines.map(l => {
if (l.startsWith('-')) {
return `+${l.slice(1)}`;
}
if (l.startsWith('+')) {
return `-${l.slice(1)}`;
}
return l;
})
};
}) });
}