Update gitignore (sorry)

This commit is contained in:
olcxja 2026-05-10 14:02:17 +02:00
commit cca8b02fea
6604 changed files with 1219661 additions and 4 deletions

147
electron/node_modules/dir-compare/src/cli/dircompare.js generated vendored Executable file
View file

@ -0,0 +1,147 @@
#!/usr/bin/env node
var program = require('commander')
var dircompare = require('../index')
var fs = require('fs')
var util = require('util')
var print = require('./print')
var pjson = require('../../package.json')
program
.version(pjson.version)
.usage('[options] leftdir rightdir')
.option('-c, --compare-content', 'compare files by content')
.option('-D, --compare-date', 'compare files by date')
.option('--date-tolerance [type]', 'tolerance to be used in date comparison (milliseconds)')
.option('--compare-symlink', 'compare files and directories by symlink')
.option('-f, --filter [type]', 'file name filter', undefined)
.option('-x, --exclude [type]', 'file/directory name exclude filter', undefined)
.option('-S, --skip-subdirs', 'do not recurse into subdirectories')
.option('-L, --skip-symlinks', 'ignore symlinks')
.option('-i, --ignore-case', 'ignores case when comparing file names')
.option('-l, --show-left', 'report - show entries occurring in left dir')
.option('-r, --show-right', 'report - show entries occurring in right dir')
.option('-e, --show-equal', 'report - show identic entries occurring in both dirs')
.option('-d, --show-distinct', 'report - show distinct entries occurring in both dirs')
.option('-a, --show-all', 'report - show all entries')
.option('-w, --whole-report', 'report - include directories in detailed report')
.option('--reason', 'report - show reason when entries are distinct')
.option('--csv', 'report - print details as csv')
.option('--nocolors', 'don\'t use console colors')
.option('--async', 'Make use of multiple cores')
program.on('--help', function () {
console.log(' By default files are compared by size.')
console.log(' --date-tolerance defaults to 1000 ms. Two files are considered to have')
console.log(' the same date if the difference between their modification dates fits')
console.log(' within date tolerance.')
console.log()
console.log(' Exit codes:')
console.log(' 0 - entries are identical')
console.log(' 1 - entries are different')
console.log(' 2 - error occurred')
console.log()
console.log(' Examples:')
console.log(' compare by content dircompare -c dir1 dir2')
console.log(' show only different files dircompare -d dir1 dir2')
console.log()
console.log(' exclude filter dircompare -x ".git,node_modules" dir1 dir2')
console.log(' dircompare -x "/tests/expected" dir1 dir2')
console.log(' dircompare -x "**/expected" dir1 dir2')
console.log(' dircompare -x "**/tests/**/*.ts" dir1 dir2')
console.log()
console.log(' include filter dircompare -f "*.js,*.yml" dir1 dir2')
console.log(' dircompare -f "/tests/**/*.js" dir1 dir2')
console.log(' dircompare -f "**/tests/**/*.ts" dir1 dir2')
})
// Fix for https://github.com/tj/commander.js/issues/125
program.allowUnknownOption()
program.parse(process.argv)
var parsed = program.parseOptions(program.normalize(process.argv.slice(2)))
if (parsed.unknown.length > 0) {
console.error('Unknown options: ' + parsed.unknown)
process.exit(2)
}
var run = function () {
try {
if (program.args.length !== 2) {
program.outputHelp()
process.exit(2)
} else {
var options = {}
options.compareContent = program.compareContent
options.compareDate = program.compareDate
options.compareSymlink = program.compareSymlink
options.compareSize = true
options.skipSubdirs = program.skipSubdirs
options.skipSymlinks = program.skipSymlinks
options.ignoreCase = program.ignoreCase
options.includeFilter = program.filter
options.excludeFilter = program.exclude
options.noDiffSet = !(program.showAll || program.showEqual || program.showLeft || program.showRight || program.showDistinct)
options.dateTolerance = program.dateTolerance || 1000
var async = program.async
var path1 = program.args[0]
var path2 = program.args[1]
var abort = false
if (!isNumeric(options.dateTolerance)) {
console.error("Numeric value expected for --date-tolerance")
abort = true
}
if (!fs.existsSync(path1)) {
console.error(util.format("Path '%s' missing"), path1)
abort = true
}
if (!fs.existsSync(path2)) {
console.error(util.format("Path '%s' missing"), path2)
abort = true
}
if (!abort) {
// compare
var comparePromise
if (async) {
comparePromise = dircompare.compare(path1, path2, options)
} else {
comparePromise = new Promise(function (resolve, reject) {
resolve(dircompare.compareSync(path1, path2, options))
})
}
comparePromise.then(
function (res) {
// PRINT DETAILS
print(res, process.stdout, program)
if (res.same) {
process.exit(0)
} else {
process.exit(1)
}
},
function (error) {
console.error('Error occurred: ' + (error instanceof Error ? error.stack : error))
process.exit(2)
})
} else {
process.exit(2)
}
}
} catch (e) {
console.error(e.stack)
process.exit(2)
}
}
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
run()

192
electron/node_modules/dir-compare/src/cli/print.js generated vendored Normal file
View file

@ -0,0 +1,192 @@
var colors = require('colors')
var util = require('util')
var pathUtils = require('path')
var PATH_SEP = pathUtils.sep
// Prints dir compare results.
// 'program' represents display options and correspond to dircompare command line parameters.
// Example: 'dircompare --show-all --exclude *.js dir1 dir2' translates into
// program: {showAll: true, exclude: '*.js'}
//
var print = function (res, writer, program) {
var noColor = function (str) { return str }
var colorEqual = program.nocolors ? noColor : colors.green
var colorDistinct = program.nocolors ? noColor : colors.red
var colorLeft = noColor
var colorRight = noColor
var colorDir = noColor
var colorBrokenLinks = noColor
var colorMissing = program.nocolors ? noColor : colors.yellow
// calculate relative path length for pretty print
var relativePathMaxLength = 0, fileNameMaxLength = 0
if (!program.csv && res.diffSet) {
res.diffSet.forEach(function (diff) {
if (diff.relativePath.length > relativePathMaxLength) {
relativePathMaxLength = diff.relativePath.length
}
var len = getCompareFile(diff, '??', colorMissing).length
if (len > fileNameMaxLength) {
fileNameMaxLength = len
}
})
}
// csv header
if (program.csv) {
writer.write('path,name,state,type,size1,size2,date1,date2,reason\n')
}
if (res.diffSet) {
for (var i = 0; i < res.diffSet.length; i++) {
var detail = res.diffSet[i]
var color, show = true
if (!program.wholeReport) {
// show only files or broken links
var type = detail.type1 !== 'missing' ? detail.type1 : detail.type2
if (type !== 'file' && type !== 'broken-link') {
show = false
}
}
if (show) {
switch (detail.state) {
case 'equal':
color = colorEqual
show = program.showAll || program.showEqual ? true : false
break
case 'left':
color = colorLeft
show = program.showAll || program.showLeft ? true : false
break
case 'right':
color = colorRight
show = program.showAll || program.showRight ? true : false
break
case 'distinct':
color = colorDistinct
show = program.showAll || program.showDistinct ? true : false
break
default:
show = true
color = colors.gray
}
if (show) {
if (program.csv) {
printCsv(writer, detail, color)
} else {
printPretty(writer, program, detail, color, colorDir, colorMissing, relativePathMaxLength, fileNameMaxLength)
}
}
}
}
}
// PRINT STATISTICS
var statTotal, statEqual, statLeft, statRight, statDistinct
if (program.wholeReport) {
statTotal = res.total
statEqual = res.equal
statLeft = res.left
statRight = res.right
statDistinct = res.distinct
} else {
var brokenLInksStats = res.brokenLinks
statTotal = res.totalFiles + brokenLInksStats.totalBrokenLinks
statEqual = res.equalFiles
statLeft = res.leftFiles + brokenLInksStats.leftBrokenLinks
statRight = res.rightFiles + brokenLInksStats.rightBrokenLinks
statDistinct = res.distinctFiles + brokenLInksStats.distinctBrokenLinks
}
if (!program.noDiffIndicator) {
writer.write(res.same ? colorEqual('Entries are identical\n') : colorDistinct('Entries are different\n'))
}
var stats = util.format('total: %s, equal: %s, distinct: %s, only left: %s, only right: %s',
statTotal,
colorEqual(statEqual),
colorDistinct(statDistinct),
colorLeft(statLeft),
colorRight(statRight)
)
if (res.brokenLinks.totalBrokenLinks > 0) {
stats += util.format(', broken links: %s', colorBrokenLinks(res.brokenLinks.totalBrokenLinks))
}
stats += '\n'
writer.write(stats)
}
/**
* Print details for default view mode
*/
var printPretty = function (writer, program, detail, color, dirColor, missingColor, relativePathMaxLength, fileNameMaxLength) {
var path = detail.relativePath === '' ? PATH_SEP : detail.relativePath
var state
switch (detail.state) {
case 'equal':
state = '=='
break
case 'left':
state = '->'
break
case 'right':
state = '<-'
break
case 'distinct':
state = '<>'
break
default:
state = '?'
}
var type = ''
type = detail.type1 !== 'missing' ? detail.type1 : detail.type2
if (type === 'directory') {
type = dirColor(type)
}
var cmpEntry = getCompareFile(detail, color(state), missingColor)
var reason = ''
if (program.reason && detail.reason) {
reason = util.format(' <%s>', detail.reason)
}
if (program.wholeReport || type === 'broken-link') {
writer.write(util.format('[%s] %s (%s)%s\n', path, cmpEntry, type, reason))
} else {
writer.write(util.format('[%s] %s%s\n', path, cmpEntry, reason))
}
}
var getCompareFile = function (detail, state, missingcolor) {
p1 = detail.name1 ? detail.name1 : ''
p2 = detail.name2 ? detail.name2 : ''
var missing1 = detail.type1 === 'missing' ? missingcolor('missing') : ''
var missing2 = detail.type2 === 'missing' ? missingcolor('missing') : ''
return util.format('%s%s %s %s%s', missing1, p1, state, missing2, p2)
}
/**
* Print csv details.
*/
var printCsv = function (writer, detail, color) {
var size1 = '', size2 = ''
if (detail.type1 === 'file') {
size1 = detail.size1 !== undefined ? detail.size1 : ''
}
if (detail.type2 === 'file') {
size2 = detail.size2 !== undefined ? detail.size2 : ''
}
var date1 = '', date2 = ''
date1 = detail.date1 !== undefined ? detail.date1.toISOString() : ''
date2 = detail.date2 !== undefined ? detail.date2.toISOString() : ''
var type = ''
type = detail.type1 !== 'missing' ? detail.type1 : detail.type2
var path = detail.relativePath ? detail.relativePath : PATH_SEP
var name = (detail.name1 ? detail.name1 : detail.name2)
var reason = detail.reason || ''
writer.write(util.format('%s,%s,%s,%s,%s,%s,%s,%s,%s\n', path, name, color(detail.state), type, size1, size2, date1, date2, reason))
}
module.exports = print

141
electron/node_modules/dir-compare/src/compareAsync.js generated vendored Normal file
View file

@ -0,0 +1,141 @@
var fs = require('fs')
var entryBuilder = require('./entry/entryBuilder')
var entryEquality = require('./entry/entryEquality')
var stats = require('./statistics/statisticsUpdate')
var pathUtils = require('path')
var fsPromise = require('./fs/fsPromise')
var loopDetector = require('./symlink/loopDetector')
var entryComparator = require('./entry/entryComparator')
var entryType = require('./entry/entryType')
/**
* Returns the sorted list of entries in a directory.
*/
var getEntries = function (rootEntry, relativePath, loopDetected, options) {
if (!rootEntry || loopDetected) {
return Promise.resolve([])
}
if (rootEntry.isDirectory) {
return fsPromise.readdir(rootEntry.absolutePath)
.then(function (entries) {
return entryBuilder.buildDirEntries(rootEntry, entries, relativePath, options)
})
}
return Promise.resolve([rootEntry])
}
/**
* Compares two directories asynchronously.
*/
var compare = function (rootEntry1, rootEntry2, level, relativePath, options, statistics, diffSet, symlinkCache) {
var loopDetected1 = loopDetector.detectLoop(rootEntry1, symlinkCache.dir1)
var loopDetected2 = loopDetector.detectLoop(rootEntry2, symlinkCache.dir2)
loopDetector.updateSymlinkCache(symlinkCache, rootEntry1, rootEntry2, loopDetected1, loopDetected2)
return Promise.all([getEntries(rootEntry1, relativePath, loopDetected1, options), getEntries(rootEntry2, relativePath, loopDetected2, options)]).then(
function (entriesResult) {
var entries1 = entriesResult[0]
var entries2 = entriesResult[1]
var i1 = 0, i2 = 0
var comparePromises = []
var compareFilePromises = []
var subDiffSet
while (i1 < entries1.length || i2 < entries2.length) {
var entry1 = entries1[i1]
var entry2 = entries2[i2]
var type1, type2
// compare entry name (-1, 0, 1)
var cmp
if (i1 < entries1.length && i2 < entries2.length) {
cmp = entryComparator.compareEntry(entry1, entry2, options)
type1 = entryType.getType(entry1)
type2 = entryType.getType(entry2)
} else if (i1 < entries1.length) {
type1 = entryType.getType(entry1)
type2 = entryType.getType(undefined)
cmp = -1
} else {
type1 = entryType.getType(undefined)
type2 = entryType.getType(entry2)
cmp = 1
}
// process entry
if (cmp === 0) {
// Both left/right exist and have the same name and type
var compareAsyncRes = entryEquality.isEntryEqualAsync(entry1, entry2, type1, diffSet, options)
var samePromise = compareAsyncRes.samePromise
var same = compareAsyncRes.same
if (same !== undefined) {
options.resultBuilder(entry1, entry2,
same ? 'equal' : 'distinct',
level, relativePath, options, statistics, diffSet,
compareAsyncRes.reason)
stats.updateStatisticsBoth(entry1, entry2, compareAsyncRes.same, compareAsyncRes.reason, type1, statistics, options)
} else {
compareFilePromises.push(samePromise)
}
i1++
i2++
if (!options.skipSubdirs && type1 === 'directory') {
if (!options.noDiffSet) {
subDiffSet = []
diffSet.push(subDiffSet)
}
comparePromises.push(compare(entry1, entry2, level + 1,
pathUtils.join(relativePath, entry1.name),
options, statistics, subDiffSet, loopDetector.cloneSymlinkCache(symlinkCache)))
}
} else if (cmp < 0) {
// Right missing
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet)
stats.updateStatisticsLeft(entry1, type1, statistics, options)
i1++
if (type1 === 'directory' && !options.skipSubdirs) {
if (!options.noDiffSet) {
subDiffSet = []
diffSet.push(subDiffSet)
}
comparePromises.push(compare(entry1, undefined,
level + 1,
pathUtils.join(relativePath, entry1.name), options, statistics, subDiffSet, loopDetector.cloneSymlinkCache(symlinkCache)))
}
} else {
// Left missing
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, diffSet)
stats.updateStatisticsRight(entry2, type2, statistics, options)
i2++
if (type2 === 'directory' && !options.skipSubdirs) {
if (!options.noDiffSet) {
subDiffSet = []
diffSet.push(subDiffSet)
}
comparePromises.push(compare(undefined, entry2,
level + 1,
pathUtils.join(relativePath, entry2.name), options, statistics, subDiffSet, loopDetector.cloneSymlinkCache(symlinkCache)))
}
}
}
return Promise.all(comparePromises).then(function () {
return Promise.all(compareFilePromises).then(function (sameResults) {
for (var i = 0; i < sameResults.length; i++) {
var sameResult = sameResults[i]
if (sameResult.error) {
return Promise.reject(sameResult.error)
} else {
options.resultBuilder(sameResult.entry1, sameResult.entry2,
sameResult.same ? 'equal' : 'distinct',
level, relativePath, options, statistics, sameResult.diffSet,
sameResult.reason)
stats.updateStatisticsBoth(sameResult.entries1, sameResult.entries2, sameResult.same, sameResult.reason, sameResult.type1, statistics, options)
}
}
})
})
})
}
module.exports = compare

90
electron/node_modules/dir-compare/src/compareSync.js generated vendored Normal file
View file

@ -0,0 +1,90 @@
var fs = require('fs')
var pathUtils = require('path')
var entryBuilder = require('./entry/entryBuilder')
var entryEquality = require('./entry/entryEquality')
var stats = require('./statistics/statisticsUpdate')
var loopDetector = require('./symlink/loopDetector')
var entryComparator = require('./entry/entryComparator')
var entryType = require('./entry/entryType')
/**
* Returns the sorted list of entries in a directory.
*/
var getEntries = function (rootEntry, relativePath, loopDetected, options) {
if (!rootEntry || loopDetected) {
return []
}
if (rootEntry.isDirectory) {
var entries = fs.readdirSync(rootEntry.absolutePath)
return entryBuilder.buildDirEntries(rootEntry, entries, relativePath, options)
}
return [rootEntry]
}
/**
* Compares two directories synchronously.
*/
var compare = function (rootEntry1, rootEntry2, level, relativePath, options, statistics, diffSet, symlinkCache) {
var loopDetected1 = loopDetector.detectLoop(rootEntry1, symlinkCache.dir1)
var loopDetected2 = loopDetector.detectLoop(rootEntry2, symlinkCache.dir2)
loopDetector.updateSymlinkCache(symlinkCache, rootEntry1, rootEntry2, loopDetected1, loopDetected2)
var entries1 = getEntries(rootEntry1, relativePath, loopDetected1, options)
var entries2 = getEntries(rootEntry2, relativePath, loopDetected2, options)
var i1 = 0, i2 = 0
while (i1 < entries1.length || i2 < entries2.length) {
var entry1 = entries1[i1]
var entry2 = entries2[i2]
var type1, type2
// compare entry name (-1, 0, 1)
var cmp
if (i1 < entries1.length && i2 < entries2.length) {
cmp = entryComparator.compareEntry(entry1, entry2, options)
type1 = entryType.getType(entry1)
type2 = entryType.getType(entry2)
} else if (i1 < entries1.length) {
type1 = entryType.getType(entry1)
type2 = entryType.getType(undefined)
cmp = -1
} else {
type1 = entryType.getType(undefined)
type2 = entryType.getType(entry2)
cmp = 1
}
// process entry
if (cmp === 0) {
// Both left/right exist and have the same name and type
var compareEntryRes = entryEquality.isEntryEqualSync(entry1, entry2, type1, options)
options.resultBuilder(entry1, entry2,
compareEntryRes.same ? 'equal' : 'distinct',
level, relativePath, options, statistics, diffSet,
compareEntryRes.reason)
stats.updateStatisticsBoth(entry1, entry2, compareEntryRes.same, compareEntryRes.reason, type1, statistics, options)
i1++
i2++
if (!options.skipSubdirs && type1 === 'directory') {
compare(entry1, entry2, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, loopDetector.cloneSymlinkCache(symlinkCache))
}
} else if (cmp < 0) {
// Right missing
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet)
stats.updateStatisticsLeft(entry1, type1, statistics, options)
i1++
if (type1 === 'directory' && !options.skipSubdirs) {
compare(entry1, undefined, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, loopDetector.cloneSymlinkCache(symlinkCache))
}
} else {
// Left missing
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, diffSet)
stats.updateStatisticsRight(entry2, type2, statistics, options)
i2++
if (type2 === 'directory' && !options.skipSubdirs) {
compare(undefined, entry2, level + 1, pathUtils.join(relativePath, entry2.name), options, statistics, diffSet, loopDetector.cloneSymlinkCache(symlinkCache))
}
}
}
}
module.exports = compare

View file

@ -0,0 +1,102 @@
var fs = require('fs')
var minimatch = require('minimatch')
var pathUtils = require('path')
var entryComparator = require('./entryComparator')
var PATH_SEP = pathUtils.sep
module.exports = {
/**
* Returns the sorted list of entries in a directory.
*/
buildDirEntries: function (rootEntry, dirEntries, relativePath, options) {
var res = []
for (var i = 0; i < dirEntries.length; i++) {
var entryName = dirEntries[i]
var entryAbsolutePath = rootEntry.absolutePath + PATH_SEP + entryName
var entryPath = rootEntry.path + PATH_SEP + entryName
var entry = this.buildEntry(entryAbsolutePath, entryPath, entryName)
if (options.skipSymlinks && entry.isSymlink) {
entry.stat = undefined
}
if (filterEntry(entry, relativePath, options)) {
res.push(entry)
}
}
return res.sort((a, b) => entryComparator.compareEntry(a, b, options))
},
buildEntry: function (absolutePath, path, name) {
var stats = getStatIgnoreBrokenLink(absolutePath)
return {
name: name,
absolutePath: absolutePath,
path: path,
stat: stats.stat,
lstat: stats.lstat,
isSymlink: stats.lstat.isSymbolicLink(),
isBrokenLink: stats.isBrokenLink,
isDirectory: stats.stat.isDirectory()
}
},
}
function getStatIgnoreBrokenLink(absolutePath) {
var lstat = fs.lstatSync(absolutePath)
try {
return {
stat: fs.statSync(absolutePath),
lstat: lstat,
isBrokenLink: false
}
} catch (error) {
if (error.code === 'ENOENT') {
return {
stat: lstat,
lstat: lstat,
isBrokenLink: true
}
}
throw error
}
}
/**
* Filter entries by file name. Returns true if the file is to be processed.
*/
function filterEntry(entry, relativePath, options) {
if (entry.isSymlink && options.skipSymlinks) {
return false
}
var path = pathUtils.join(relativePath, entry.name)
if ((entry.stat.isFile() && options.includeFilter) && (!match(path, options.includeFilter))) {
return false
}
if ((options.excludeFilter) && (match(path, options.excludeFilter))) {
return false
}
return true
}
/**
* Matches path by pattern.
*/
function match(path, pattern) {
var patternArray = pattern.split(',')
for (var i = 0; i < patternArray.length; i++) {
var pat = patternArray[i]
if (minimatch(path, pat, { dot: true, matchBase: true })) { //nocase
return true
}
}
return false
}

View file

@ -0,0 +1,20 @@
/**
* Determines order criteria for sorting entries in a directory.
*/
module.exports = {
compareEntry: function (a, b, options) {
if (a.isBrokenLink && b.isBrokenLink) {
return options.compareNameHandler(a.name, b.name, options)
} else if (a.isBrokenLink) {
return -1
} else if (b.isBrokenLink) {
return 1
} else if (a.stat.isDirectory() && b.stat.isFile()) {
return -1
} else if (a.stat.isFile() && b.stat.isDirectory()) {
return 1
} else {
return options.compareNameHandler(a.name, b.name, options)
}
}
}

View file

@ -0,0 +1,135 @@
var fs = require('fs')
/**
* Compares two entries with identical name and type.
*/
module.exports = {
isEntryEqualSync: function (entry1, entry2, type, options) {
if (type === 'file') {
return isFileEqualSync(entry1, entry2, options)
}
if (type === 'directory') {
return isDirectoryEqual(entry1, entry2, options)
}
if (type === 'broken-link') {
return isBrokenLinkEqual()
}
throw new Error('Unexpected type ' + type)
},
isEntryEqualAsync: function (entry1, entry2, type, diffSet, options) {
if (type === 'file') {
return isFileEqualAsync(entry1, entry2, type, diffSet, options)
}
if (type === 'directory') {
return isDirectoryEqual(entry1, entry2, options)
}
if (type === 'broken-link') {
return isBrokenLinkEqual()
}
throw new Error('Unexpected type ' + type)
}
}
function isFileEqualSync(entry1, entry2, options) {
var p1 = entry1 ? entry1.absolutePath : undefined
var p2 = entry2 ? entry2.absolutePath : undefined
if (options.compareSymlink && !isSymlinkEqual(entry1, entry2)) {
return { same: false, reason: 'different-symlink' }
}
if (options.compareSize && entry1.stat.size !== entry2.stat.size) {
return { same: false, reason: 'different-size' }
}
if (options.compareDate && !isDateEqual(entry1.stat.mtime, entry2.stat.mtime, options.dateTolerance)) {
return { same: false, reason: 'different-date' }
}
if (options.compareContent && !options.compareFileSync(p1, entry1.stat, p2, entry2.stat, options)) {
return { same: false, reason: 'different-content' }
}
return { same: true }
}
function isFileEqualAsync(entry1, entry2, type, diffSet, options) {
var p1 = entry1 ? entry1.absolutePath : undefined
var p2 = entry2 ? entry2.absolutePath : undefined
if (options.compareSymlink && !isSymlinkEqual(entry1, entry2)) {
return { same: false, reason: 'different-symlink' }
}
if (options.compareSize && entry1.stat.size !== entry2.stat.size) {
return { same: false, samePromise: undefined, reason: 'different-size' }
}
if (options.compareDate && !isDateEqual(entry1.stat.mtime, entry2.stat.mtime, options.dateTolerance)) {
return { same: false, samePromise: undefined, reason: 'different-date' }
}
if (options.compareContent) {
var samePromise = undefined
var subDiffSet
if (!options.noDiffSet) {
subDiffSet = []
diffSet.push(subDiffSet)
}
samePromise = options.compareFileAsync(p1, entry1.stat, p2, entry2.stat, options)
.then(function (comparisonResult) {
var same, error
if (typeof (comparisonResult) === "boolean") {
same = comparisonResult
} else {
error = comparisonResult
}
return {
entry1: entry1, entry2: entry2, same: same,
error: error, type1: type, type2: type,
diffSet: subDiffSet,
reason: same ? undefined : 'different-content'
}
})
.catch(function (error) {
return {
error: error
}
})
return { same: undefined, samePromise: samePromise }
}
return { same: true, samePromise: undefined }
}
function isDirectoryEqual(entry1, entry2, options) {
if (options.compareSymlink && !isSymlinkEqual(entry1, entry2)) {
return { same: false, reason: 'different-symlink' }
}
return { same: true }
}
function isBrokenLinkEqual() {
return { same: false, reason: 'broken-link' } // broken links are never considered equal
}
/**
* Compares two dates and returns true/false depending on tolerance (milliseconds).
* Two dates are considered equal if the difference in milliseconds between them is less or equal than tolerance.
*/
function isDateEqual(date1, date2, tolerance) {
return Math.abs(date1.getTime() - date2.getTime()) <= tolerance ? true : false
}
/**
* Compares two entries for symlink equality.
*/
function isSymlinkEqual(entry1, entry2) {
if (!entry1.isSymlink && !entry2.isSymlink) {
return true
}
if (entry1.isSymlink && entry2.isSymlink && hasIdenticalLink(entry1.absolutePath, entry2.absolutePath)) {
return true
}
return false
}
function hasIdenticalLink(path1, path2) {
return fs.readlinkSync(path1) === fs.readlinkSync(path2)
}

View file

@ -0,0 +1,18 @@
module.exports = {
/**
* One of 'missing','file','directory','broken-link'
*/
getType: function (entry) {
if (!entry) {
return 'missing'
}
if (entry.isBrokenLink) {
return 'broken-link'
}
if (entry.isDirectory) {
return 'directory'
}
return 'file'
}
}

View file

@ -0,0 +1,28 @@
var fs = require('fs')
var closeFilesSync = function (fd1, fd2) {
if (fd1) {
fs.closeSync(fd1)
}
if (fd2) {
fs.closeSync(fd2)
}
}
var closeFilesAsync = function (fd1, fd2, fdQueue) {
if (fd1 && fd2) {
return fdQueue.promises.close(fd1).then(() => fdQueue.promises.close(fd2))
}
if (fd1) {
return fdQueue.promises.close(fd1)
}
if (fd2) {
return fdQueue.promises.close(fd2)
}
}
module.exports = {
closeFilesSync: closeFilesSync,
closeFilesAsync: closeFilesAsync
}

View file

@ -0,0 +1,113 @@
var fs = require('fs')
var bufferEqual = require('buffer-equal')
var FileDescriptorQueue = require('../fs/FileDescriptorQueue')
var closeFilesSync = require('./closeFile').closeFilesSync
var closeFilesAsync = require('./closeFile').closeFilesAsync
var fsPromise = require('../fs/fsPromise')
var BufferPool = require('../fs/BufferPool')
var MAX_CONCURRENT_FILE_COMPARE = 8
var BUF_SIZE = 100000
var fdQueue = new FileDescriptorQueue(MAX_CONCURRENT_FILE_COMPARE * 2)
var bufferPool = new BufferPool(BUF_SIZE, MAX_CONCURRENT_FILE_COMPARE); // fdQueue guarantees there will be no more than MAX_CONCURRENT_FILE_COMPARE async processes accessing the buffers concurrently
/**
* Compares two partial buffers.
*/
var compareBuffers = function (buf1, buf2, contentSize) {
return bufferEqual(buf1.slice(0, contentSize), buf2.slice(0, contentSize))
}
/**
* Compares two files by content.
*/
var compareSync = function (path1, stat1, path2, stat2, options) {
var fd1, fd2
if (stat1.size !== stat2.size) {
return false
}
var bufferPair = bufferPool.allocateBuffers()
try {
fd1 = fs.openSync(path1, 'r')
fd2 = fs.openSync(path2, 'r')
var buf1 = bufferPair.buf1
var buf2 = bufferPair.buf2
var progress = 0
while (true) {
var size1 = fs.readSync(fd1, buf1, 0, BUF_SIZE, null)
var size2 = fs.readSync(fd2, buf2, 0, BUF_SIZE, null)
if (size1 !== size2) {
return false
} else if (size1 === 0) {
// End of file reached
return true
} else if (!compareBuffers(buf1, buf2, size1)) {
return false
}
}
} finally {
closeFilesSync(fd1, fd2)
bufferPool.freeBuffers(bufferPair)
}
}
/**
* Compares two files by content
*/
var compareAsync = function (path1, stat1, path2, stat2, options) {
var fd1, fd2
var bufferPair
if (stat1.size !== stat2.size) {
return Promise.resolve(false)
}
return Promise.all([fdQueue.promises.open(path1, 'r'), fdQueue.promises.open(path2, 'r')])
.then(function (fds) {
bufferPair = bufferPool.allocateBuffers()
fd1 = fds[0]
fd2 = fds[1]
var buf1 = bufferPair.buf1
var buf2 = bufferPair.buf2
var progress = 0
var compareAsyncInternal = function () {
return Promise.all([
fsPromise.read(fd1, buf1, 0, BUF_SIZE, null),
fsPromise.read(fd2, buf2, 0, BUF_SIZE, null)
]).then(function (bufferSizes) {
var size1 = bufferSizes[0]
var size2 = bufferSizes[1]
if (size1 !== size2) {
return false
} else if (size1 === 0) {
// End of file reached
return true
} else if (!compareBuffers(buf1, buf2, size1)) {
return false
} else {
return compareAsyncInternal()
}
})
}
return compareAsyncInternal()
})
.then(
// 'finally' polyfill for node 8 and below
function (res) {
return finalizeAsync(fd1, fd2, bufferPair).then(() => res)
},
function (err) {
return finalizeAsync(fd1, fd2, bufferPair).then(() => { throw err; })
}
)
}
function finalizeAsync(fd1, fd2, bufferPair) {
bufferPool.freeBuffers(bufferPair)
return closeFilesAsync(fd1, fd2, fdQueue)
}
module.exports = {
compareSync: compareSync,
compareAsync: compareAsync
}

View file

@ -0,0 +1,196 @@
/**
* Compare files line by line with options to ignore
* line endings and white space differencies.
*/
var fs = require('fs')
var FileDescriptorQueue = require('../fs/FileDescriptorQueue')
var closeFilesSync = require('./closeFile').closeFilesSync
var closeFilesAsync = require('./closeFile').closeFilesAsync
var fsPromise = require('../fs/fsPromise')
var BufferPool = require('../fs/BufferPool')
const LINE_TOKENIZER_REGEXP = /[^\n]+\n?|\n/g
const TRIM_LINE_ENDING_REGEXP = /\r\n$/g
const SPLIT_CONTENT_AND_LINE_ENDING_REGEXP = /([^\r\n]*)([\r\n]*)/
const TRIM_WHITE_SPACES_REGEXP = /^[ \f\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+|[ \f\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+$/g
var MAX_CONCURRENT_FILE_COMPARE = 8
var BUF_SIZE = 100000
var fdQueue = new FileDescriptorQueue(MAX_CONCURRENT_FILE_COMPARE * 2)
var bufferPool = new BufferPool(BUF_SIZE, MAX_CONCURRENT_FILE_COMPARE); // fdQueue guarantees there will be no more than MAX_CONCURRENT_FILE_COMPARE async processes accessing the buffers concurrently
function compareSync(path1, stat1, path2, stat2, options) {
var fd1, fd2
var bufferPair = bufferPool.allocateBuffers()
var bufferSize = options.lineBasedHandlerBufferSize || BUF_SIZE
try {
fd1 = fs.openSync(path1, 'r')
fd2 = fs.openSync(path2, 'r')
var buf1 = bufferPair.buf1
var buf2 = bufferPair.buf2
var nextPosition1 = 0, nextPosition2 = 0
while (true) {
var lines1 = readLinesSync(fd1, buf1, bufferSize, nextPosition1)
var lines2 = readLinesSync(fd2, buf2, bufferSize, nextPosition2)
if (lines1.length === 0 && lines2.length === 0) {
// End of file reached
return true
}
var equalLines = compareLines(lines1, lines2, options)
if (equalLines === 0) {
return false
}
nextPosition1 += calculateSize(lines1, equalLines)
nextPosition2 += calculateSize(lines2, equalLines)
}
} finally {
closeFilesSync(fd1, fd2)
bufferPool.freeBuffers(bufferPair)
}
}
async function compareAsync(path1, stat1, path2, stat2, options) {
var fd1, fd2
var bufferSize = options.lineBasedHandlerBufferSize || BUF_SIZE
var bufferPair
try {
var fds = await Promise.all([fdQueue.promises.open(path1, 'r'), fdQueue.promises.open(path2, 'r')])
bufferPair = bufferPool.allocateBuffers()
fd1 = fds[0]
fd2 = fds[1]
var buf1 = bufferPair.buf1
var buf2 = bufferPair.buf2
var nextPosition1 = 0, nextPosition2 = 0
while (true) {
var lines1 = await readLinesAsync(fd1, buf1, bufferSize, nextPosition1)
var lines2 = await readLinesAsync(fd2, buf2, bufferSize, nextPosition2)
if (lines1.length === 0 && lines2.length === 0) {
// End of file reached
return true
}
var equalLines = compareLines(lines1, lines2, options)
if (equalLines === 0) {
return false
}
nextPosition1 += calculateSize(lines1, equalLines)
nextPosition2 += calculateSize(lines2, equalLines)
}
} finally {
bufferPool.freeBuffers(bufferPair)
await closeFilesAsync(fd1, fd2, fdQueue)
}
}
/**
* Read lines from file starting with nextPosition.
* Returns 0 lines if eof is reached, otherwise returns at least one complete line.
*/
function readLinesSync(fd, buf, bufferSize, nextPosition) {
var lines = []
var chunk = ""
while (true) {
var size = fs.readSync(fd, buf, 0, bufferSize, nextPosition)
if (size === 0) {
// end of file
normalizeLastFileLine(lines)
return lines
}
chunk += buf.toString('utf8', 0, size)
lines = chunk.match(LINE_TOKENIZER_REGEXP)
if (lines.length > 1) {
return removeLastIncompleteLine(lines)
}
nextPosition += size
}
}
/**
* Read lines from file starting with nextPosition.
* Returns 0 lines if eof is reached, otherwise returns at least one complete line.
*/
async function readLinesAsync(fd, buf, bufferSize, nextPosition) {
var lines = []
var chunk = ""
while (true) {
var size = await fsPromise.read(fd, buf, 0, bufferSize, nextPosition)
if (size === 0) {
// end of file
normalizeLastFileLine(lines)
return lines
}
chunk += buf.toString('utf8', 0, size)
lines = chunk.match(LINE_TOKENIZER_REGEXP)
if (lines.length > 1) {
return removeLastIncompleteLine(lines)
}
nextPosition += size
}
}
function removeLastIncompleteLine(lines) {
const lastLine = lines[lines.length - 1]
if (!lastLine.endsWith('\n')) {
return lines.slice(0, lines.length - 1)
}
return lines
}
function normalizeLastFileLine(lines) {
if (lines.length === 0) {
return
}
const lastLine = lines[lines.length - 1]
if (!lastLine.endsWith('\n')) {
lines[lines.length - 1] = lastLine + '\n'
}
}
function calculateSize(lines, numberOfLines) {
var size = 0
for (var i = 0; i < numberOfLines; i++) {
var line = lines[i]
size += line.length
}
return size
}
function compareLines(lines1, lines2, options) {
var equalLines = 0
var len = lines1.length < lines2.length ? lines1.length : lines2.length
for (var i = 0; i < len; i++) {
var line1 = lines1[i]
var line2 = lines2[i]
if (options.ignoreLineEnding) {
line1 = trimLineEnding(line1)
line2 = trimLineEnding(line2)
}
if (options.ignoreWhiteSpaces) {
line1 = trimSpaces(line1)
line2 = trimSpaces(line2)
}
if (line1 !== line2) {
return equalLines
}
equalLines++
}
return equalLines
}
// Trims string like ' abc \n' into 'abc\n'
function trimSpaces(s) {
var matchResult = s.match(SPLIT_CONTENT_AND_LINE_ENDING_REGEXP);
var content = matchResult[1]
var lineEnding = matchResult[2]
var trimmed = content.replace(TRIM_WHITE_SPACES_REGEXP, '')
return trimmed + lineEnding
}
// Trims string like 'abc\r\n' into 'abc\n'
function trimLineEnding(s) {
return s.replace(TRIM_LINE_ENDING_REGEXP, '\n')
}
module.exports = {
compareSync: compareSync,
compareAsync: compareAsync
}

46
electron/node_modules/dir-compare/src/fs/BufferPool.js generated vendored Normal file
View file

@ -0,0 +1,46 @@
/**
* Collection of buffers to be shared between async processes.
* Avoids allocating buffers each time async process starts.
* bufSize - size of each buffer
* bufNo - number of buffers
* Caller has to make sure no more than bufNo async processes run simultaneously.
*/
function BufferPool(bufSize, bufNo) {
var bufferPool = []
for (var i = 0; i < bufNo; i++) {
bufferPool.push({
buf1: alloc(bufSize),
buf2: alloc(bufSize),
busy: false
})
}
var allocateBuffers = function () {
for (var j = 0; j < bufNo; j++) {
var bufferPair = bufferPool[j]
if (!bufferPair.busy) {
bufferPair.busy = true
return bufferPair
}
}
throw new Error('Async buffer limit reached')
}
return {
allocateBuffers: allocateBuffers,
freeBuffers: freeBuffers
}
function freeBuffers(bufferPair) {
bufferPair.busy = false
}
}
function alloc(bufSize) {
if (Buffer.alloc) {
return Buffer.alloc(bufSize)
}
return new Buffer(bufSize)
}
module.exports = BufferPool

View file

@ -0,0 +1,78 @@
'use strict'
var fs = require('fs')
var Queue = require('./Queue')
/**
* Limits the number of concurrent file handlers.
* Use it as a wrapper over fs.open() and fs.close().
* Example:
* var fdQueue = new FileDescriptorQueue(8)
* fdQueue.open(path, flags, (err, fd) =>{
* ...
* fdQueue.close(fd, (err) =>{
* ...
* })
* })
* As of node v7, calling fd.close without a callback is deprecated.
*/
var FileDescriptorQueue = function (maxFilesNo) {
var pendingJobs = new Queue()
var activeCount = 0
var open = function (path, flags, callback) {
pendingJobs.enqueue({
path: path,
flags: flags,
callback: callback
})
process()
}
var process = function () {
if (pendingJobs.getLength() > 0 && activeCount < maxFilesNo) {
var job = pendingJobs.dequeue()
activeCount++
fs.open(job.path, job.flags, job.callback)
}
}
var close = function (fd, callback) {
activeCount--
fs.close(fd, callback)
process()
}
var promises = {
open: function (path, flags) {
return new Promise(function (resolve, reject) {
open(path, flags, function (err, fd) {
if (err) {
reject(err)
} else {
resolve(fd)
}
})
})
},
close: function (fd) {
return new Promise(function (resolve, reject) {
close(fd, function (err) {
if (err) {
reject(err)
} else {
resolve()
}
})
})
}
}
return {
open: open,
close: close,
promises: promises
}
}
module.exports = FileDescriptorQueue

63
electron/node_modules/dir-compare/src/fs/Queue.js generated vendored Normal file
View file

@ -0,0 +1,63 @@
/*
Queue.js
A function to represent a queue
Created by Kate Morley - http://code.iamkate.com/ - and released under the terms
of the CC0 1.0 Universal legal code:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
*/
var MAX_UNUSED_ARRAY_SIZE = 10000
/* Creates a new queue. A queue is a first-in-first-out (FIFO) data structure -
* items are added to the end of the queue and removed from the front.
*/
function Queue() {
// initialise the queue and offset
var queue = []
var offset = 0
// Returns the length of the queue.
this.getLength = function () {
return (queue.length - offset)
}
/* Enqueues the specified item. The parameter is:
*
* item - the item to enqueue
*/
this.enqueue = function (item) {
queue.push(item)
}
/* Dequeues an item and returns it. If the queue is empty, the value
* 'undefined' is returned.
*/
this.dequeue = function () {
// if the queue is empty, return immediately
if (queue.length === 0) {
return undefined
}
// store the item at the front of the queue
var item = queue[offset]
// increment the offset and remove the free space if necessary
if (++offset > MAX_UNUSED_ARRAY_SIZE) {
queue = queue.slice(offset)
offset = 0
}
// return the dequeued item
return item
}
}
module.exports = Queue

26
electron/node_modules/dir-compare/src/fs/fsPromise.js generated vendored Normal file
View file

@ -0,0 +1,26 @@
var fs = require('fs')
module.exports = {
readdir: function (path) {
return new Promise(function (resolve, reject) {
fs.readdir(path, function (err, files) {
if (err) {
reject(err)
} else {
resolve(files)
}
})
})
},
read: function (fd, buffer, offset, length, position) {
return new Promise(function (resolve, reject) {
fs.read(fd, buffer, offset, length, position, function(err, bytesRead) {
if(err){
reject(err)
} else {
resolve(bytesRead)
}
})
})
},
}

476
electron/node_modules/dir-compare/src/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,476 @@
/// <reference types="node" />
import * as fs from "fs"
/**
* Synchronously compares given paths.
* @param path1 Left file or directory to be compared.
* @param path2 Right file or directory to be compared.
* @param options Comparison options.
*/
export function compareSync(path1: string, path2: string, options?: Options): Result
/**
* Asynchronously compares given paths.
* @param path1 Left file or directory to be compared.
* @param path2 Right file or directory to be compared.
* @param options Comparison options.
*/
export function compare(path1: string, path2: string, options?: Options): Promise<Result>
/**
* Comparison options.
*/
export interface Options {
/**
* Properties to be used in various extension points ie. result builder.
*/
[key: string]: any
/**
* Compares files by size. Defaults to 'false'.
*/
compareSize?: boolean
/**
* Compares files by date of modification (stat.mtime). Defaults to 'false'.
*/
compareDate?: boolean
/**
* Two files are considered to have the same date if the difference between their modification dates fits within date tolerance. Defaults to 1000 ms.
*/
dateTolerance?: number
/**
* Compares files by content. Defaults to 'false'.
*/
compareContent?: boolean
/**
* Compares entries by symlink. Defaults to 'false'.
*/
compareSymlink?: boolean
/**
* Skips sub directories. Defaults to 'false'.
*/
skipSubdirs?: boolean
/**
* Ignore symbolic links. Defaults to 'false'.
*/
skipSymlinks?: boolean
/**
* Ignores case when comparing names. Defaults to 'false'.
*/
ignoreCase?: boolean
/**
* Toggles presence of diffSet in output. If true, only statistics are provided. Use this when comparing large number of files to avoid out of memory situations. Defaults to 'false'.
*/
noDiffSet?: boolean
/**
* File name filter. Comma separated minimatch patterns. See [Glob patterns](https://github.com/gliviu/dir-compare#glob-patterns).
*/
includeFilter?: string
/**
* File/directory name exclude filter. Comma separated minimatch patterns. See [Glob patterns](https://github.com/gliviu/dir-compare#glob-patterns)
*/
excludeFilter?: string
/**
* Callback for constructing result. Called for each compared entry pair.
*
* Updates 'statistics' and 'diffSet'.
*
* See [Custom result builder](https://github.com/gliviu/dir-compare#custom-result-builder).
*/
resultBuilder?: ResultBuilder
/**
* File comparison handler. See [Custom file comparators](https://github.com/gliviu/dir-compare#custom-file-content-comparators).
*/
compareFileSync?: CompareFileSync
/**
* File comparison handler. See [Custom file comparators](https://github.com/gliviu/dir-compare#custom-file-content-comparators).
*/
compareFileAsync?: CompareFileAsync
/**
* Entry name comparison handler. See [Custom name comparators](https://github.com/gliviu/dir-compare#custom-name-comparators).
*/
compareNameHandler?: CompareNameHandler
}
/**
* Callback for constructing result. Called for each compared entry pair.
*
* Updates 'statistics' and 'diffSet'.
*/
export type ResultBuilder =
/**
* @param entry1 Left entry.
* @param entry2 Right entry.
* @param state See [[DifferenceState]].
* @param level Depth level relative to root dir.
* @param relativePath Path relative to root dir.
* @param statistics Statistics to be updated.
* @param diffSet Status per each entry to be appended.
* Do not append if [[Options.noDiffSet]] is false.
* @param reason See [[Reason]]. Not available if entries are equal.
*/
(
entry1: Entry | undefined,
entry2: Entry | undefined,
state: DifferenceState,
level: number,
relativePath: string,
options: Options,
statistics: Statistics,
diffSet: Array<Difference> | undefined,
reason: Reason | undefined
) => void
export interface Entry {
name: string
absolutePath: string
path: string
stat: fs.Stats
lstat: fs.Stats
symlink: boolean
}
/**
* Comparison result.
*/
export interface Result extends Statistics {
/**
* List of changes (present if [[Options.noDiffSet]] is false).
*/
diffSet?: Array<Difference>
}
export interface Statistics {
/**
* Any property is allowed if default result builder is not used.
*/
[key: string]: any
/**
* True if directories are identical.
*/
same: boolean
/**
* Number of distinct entries.
*/
distinct: number
/**
* Number of equal entries.
*/
equal: number
/**
* Number of entries only in path1.
*/
left: number
/**
* Number of entries only in path2.
*/
right: number
/**
* Total number of differences (distinct+left+right).
*/
differences: number
/**
* Total number of entries (differences+equal).
*/
total: number
/**
* Number of distinct files.
*/
distinctFiles: number
/**
* Number of equal files.
*/
equalFiles: number
/**
* Number of files only in path1.
*/
leftFiles: number
/**
* Number of files only in path2
*/
rightFiles: number
/**
* Total number of different files (distinctFiles+leftFiles+rightFiles).
*/
differencesFiles: number
/**
* Total number of files (differencesFiles+equalFiles).
*/
totalFiles: number
/**
* Number of distinct directories.
*/
distinctDirs: number
/**
* Number of equal directories.
*/
equalDirs: number
/**
* Number of directories only in path1.
*/
leftDirs: number
/**
* Number of directories only in path2.
*/
rightDirs: number
/**
* Total number of different directories (distinctDirs+leftDirs+rightDirs).
*/
differencesDirs: number
/**
* Total number of directories (differencesDirs+equalDirs).
*/
totalDirs: number
/**
* Stats about broken links.
*/
brokenLinks: BrokenLinksStatistics
/**
* Statistics available if 'compareSymlink' options is used.
*/
symlinks?: SymlinkStatistics
}
export interface BrokenLinksStatistics {
/**
* Number of broken links only in path1
*/
leftBrokenLinks: number
/**
* Number of broken links only in path2
*/
rightBrokenLinks: number
/**
* Number of broken links with same name appearing in both path1 and path2 (leftBrokenLinks+rightBrokenLinks+distinctBrokenLinks)
*/
distinctBrokenLinks: number
/**
* Total number of broken links
*/
totalBrokenLinks: number
}
export interface SymlinkStatistics {
/**
* Number of distinct links.
*/
distinctSymlinks: number
/**
* Number of equal links.
*/
equalSymlinks: number
/**
* Number of links only in path1.
*/
leftSymlinks: number
/**
* Number of links only in path2
*/
rightSymlinks: number
/**
* Total number of different links (distinctSymlinks+leftSymlinks+rightSymlinks).
*/
differencesSymlinks: number
/**
* Total number of links (differencesSymlinks+equalSymlinks).
*/
totalSymlinks: number
}
/**
* State of left/right entries relative to each other.
*/
export type DifferenceState = "equal" | "left" | "right" | "distinct"
/**
* Type of entry.
*/
export type DifferenceType = "missing" | "file" | "directory" | "broken-link"
/**
* Provides reason when two identically named entries are distinct.
*/
export type Reason = "different-size" | "different-date" | "different-content" | "broken-link" | 'different-symlink'
export interface Difference {
/**
* Any property is allowed if default result builder is not used.
*/
[key: string]: any
/**
* Path not including file/directory name; can be relative or absolute depending on call to compare().
*/
path1?: string
/**
* Path not including file/directory name; can be relative or absolute depending on call to compare().
*/
path2?: string
/**
* Path relative to root dir.
*/
relativePath: string
/**
* Left file/directory name.
*/
name1?: string
/**
* Right file/directory name.
*/
name2?: string
/**
* See [[DifferenceState]]
*/
state: DifferenceState
/**
* Type of left entry.
*/
type1: DifferenceType
/**
* Type of right entry.
*/
type2: DifferenceType
/**
* Left file size.
*/
size1?: number
/**
* Right file size.
*/
size2?: number
/**
* Left entry modification date (stat.mtime).
*/
date1?: number
/**
* Right entry modification date (stat.mtime).
*/
date2?: number
/**
* Depth level relative to root dir.
*/
level: number
/**
* See [[Reason]].
* Not available if entries are equal.
*/
reason?: Reason
}
/**
* Synchronous file content comparison handler.
*/
export type CompareFileSync = (
path1: string,
stat1: fs.Stats,
path2: string,
stat2: fs.Stats,
options: Options
) => boolean
/**
* Asynchronous file content comparison handler.
*/
export type CompareFileAsync = (
path1: string,
stat1: fs.Stats,
path2: string,
stat2: fs.Stats,
options: Options
) => Promise<boolean>
export interface CompareFileHandler {
compareSync: CompareFileSync,
compareAsync: CompareFileAsync
}
/**
* Available file content comparison handlers.
* These handlers are used when [[Options.compareContent]] is set.
*/
export const fileCompareHandlers: {
/**
* Default file content comparison handlers, used if [[Options.compareFileAsync]] or [[Options.compareFileSync]] are not specified.
*
* Performs binary comparison.
*/
defaultFileCompare: CompareFileHandler,
/**
* Compares files line by line.
*
* Options:
* * ignoreLineEnding - tru/false (default: false)
* * ignoreWhiteSpaces - tru/false (default: false)
*/
lineBasedFileCompare: CompareFileHandler
}
/**
* Compares the names of two entries.
* The comparison should be dependent on received options (ie. case sensitive, ...).
* Returns 0 if names are identical, -1 if name1<name2, 1 if name1>name2.
*/
export type CompareNameHandler = (
name1: string,
name2: string,
options: Options
) => 0 | 1 | -1

204
electron/node_modules/dir-compare/src/index.js generated vendored Normal file
View file

@ -0,0 +1,204 @@
var util = require('util')
var pathUtils = require('path')
var fs = require('fs')
var compareSyncInternal = require('./compareSync')
var compareAsyncInternal = require('./compareAsync')
var defaultResultBuilderCallback = require('./resultBuilder/defaultResultBuilderCallback')
var defaultFileCompare = require('./fileCompareHandler/defaultFileCompare')
var lineBasedFileCompare = require('./fileCompareHandler/lineBasedFileCompare')
var defaultNameCompare = require('./nameCompare/defaultNameCompare')
var entryBuilder = require('./entry/entryBuilder')
var statsLifecycle = require('./statistics/statisticsLifecycle')
var loopDetector = require('./symlink/loopDetector')
var ROOT_PATH = pathUtils.sep
var compareSync = function (path1, path2, options) {
'use strict'
// realpathSync() is necessary for loop detection to work properly
var absolutePath1 = pathUtils.normalize(pathUtils.resolve(fs.realpathSync(path1)))
var absolutePath2 = pathUtils.normalize(pathUtils.resolve(fs.realpathSync(path2)))
var diffSet
options = prepareOptions(options)
if (!options.noDiffSet) {
diffSet = []
}
var statistics = statsLifecycle.initStats(options)
compareSyncInternal(
entryBuilder.buildEntry(absolutePath1, path1, pathUtils.basename(absolutePath1)),
entryBuilder.buildEntry(absolutePath2, path2, pathUtils.basename(absolutePath2)),
0, ROOT_PATH, options, statistics, diffSet, loopDetector.initSymlinkCache())
statsLifecycle.completeStatistics(statistics, options)
statistics.diffSet = diffSet
return statistics
}
var wrapper = {
realPath: function(path, options) {
return new Promise(function (resolve, reject) {
fs.realpath(path, options, function(err, resolvedPath) {
if(err){
reject(err)
} else {
resolve(resolvedPath)
}
})
})
}
}
var compareAsync = function (path1, path2, options) {
'use strict'
var absolutePath1, absolutePath2
return Promise.resolve()
.then(function () {
return Promise.all([wrapper.realPath(path1), wrapper.realPath(path2)])
})
.then(function (realPaths) {
var realPath1 = realPaths[0]
var realPath2 = realPaths[1]
// realpath() is necessary for loop detection to work properly
absolutePath1 = pathUtils.normalize(pathUtils.resolve(realPath1))
absolutePath2 = pathUtils.normalize(pathUtils.resolve(realPath2))
})
.then(function () {
options = prepareOptions(options)
var asyncDiffSet
if (!options.noDiffSet) {
asyncDiffSet = []
}
var statistics = statsLifecycle.initStats(options)
return compareAsyncInternal(
entryBuilder.buildEntry(absolutePath1, path1, pathUtils.basename(path1)),
entryBuilder.buildEntry(absolutePath2, path2, pathUtils.basename(path2)),
0, ROOT_PATH, options, statistics, asyncDiffSet, loopDetector.initSymlinkCache()).then(
function () {
statsLifecycle.completeStatistics(statistics, options)
if (!options.noDiffSet) {
var diffSet = []
rebuildAsyncDiffSet(statistics, asyncDiffSet, diffSet)
statistics.diffSet = diffSet
}
return statistics
})
})
}
var prepareOptions = function (options) {
options = options || {}
var clone = JSON.parse(JSON.stringify(options))
clone.resultBuilder = options.resultBuilder
clone.compareFileSync = options.compareFileSync
clone.compareFileAsync = options.compareFileAsync
clone.compareNameHandler = options.compareNameHandler
if (!clone.resultBuilder) {
clone.resultBuilder = defaultResultBuilderCallback
}
if (!clone.compareFileSync) {
clone.compareFileSync = defaultFileCompare.compareSync
}
if (!clone.compareFileAsync) {
clone.compareFileAsync = defaultFileCompare.compareAsync
}
if(!clone.compareNameHandler) {
clone.compareNameHandler = defaultNameCompare
}
clone.dateTolerance = clone.dateTolerance || 1000
clone.dateTolerance = Number(clone.dateTolerance)
if (isNaN(clone.dateTolerance)) {
throw new Error('Date tolerance is not a number')
}
return clone
}
// Async diffsets are kept into recursive structures.
// This method transforms them into one dimensional arrays.
var rebuildAsyncDiffSet = function (statistics, asyncDiffSet, diffSet) {
asyncDiffSet.forEach(function (rawDiff) {
if (!Array.isArray(rawDiff)) {
diffSet.push(rawDiff)
} else {
rebuildAsyncDiffSet(statistics, rawDiff, diffSet)
}
})
}
/**
* Options:
* compareSize: true/false - Compares files by size. Defaults to 'false'.
* compareDate: true/false - Compares files by date of modification (stat.mtime). Defaults to 'false'.
* dateTolerance: milliseconds - Two files are considered to have the same date if the difference between their modification dates fits within date tolerance. Defaults to 1000 ms.
* compareContent: true/false - Compares files by content. Defaults to 'false'.
* compareSymlink: true/false - Compares entries by symlink. Defaults to 'false'.
* skipSubdirs: true/false - Skips sub directories. Defaults to 'false'.
* skipSymlinks: true/false - Skips symbolic links. Defaults to 'false'.
* ignoreCase: true/false - Ignores case when comparing names. Defaults to 'false'.
* noDiffSet: true/false - Toggles presence of diffSet in output. If true, only statistics are provided. Use this when comparing large number of files to avoid out of memory situations. Defaults to 'false'.
* includeFilter: File name filter. Comma separated [minimatch](https://www.npmjs.com/package/minimatch) patterns.
* excludeFilter: File/directory name exclude filter. Comma separated [minimatch](https://www.npmjs.com/package/minimatch) patterns.
* resultBuilder: Callback for constructing result.
* function (entry1, entry2, state, level, relativePath, options, statistics, diffSet). Called for each compared entry pair. Updates 'statistics' and 'diffSet'.
* compareFileSync, compareFileAsync: Callbacks for file comparison.
* compareNameHandler: Callback for name comparison
*
* Result:
* same: true if directories are identical
* distinct: number of distinct entries
* equal: number of equal entries
* left: number of entries only in path1
* right: number of entries only in path2
* differences: total number of differences (distinct+left+right)
* total: total number of entries (differences+equal)
* distinctFiles: number of distinct files
* equalFiles: number of equal files
* leftFiles: number of files only in path1
* rightFiles: number of files only in path2
* differencesFiles: total number of different files (distinctFiles+leftFiles+rightFiles)
* totalFiles: total number of files (differencesFiles+equalFiles)
* distinctDirs: number of distinct directories
* equalDirs: number of equal directories
* leftDirs: number of directories only in path1
* rightDirs: number of directories only in path2
* differencesDirs: total number of different directories (distinctDirs+leftDirs+rightDirs)
* totalDirs: total number of directories (differencesDirs+equalDirs)
* brokenLinks:
* leftBrokenLinks: number of broken links only in path1
* rightBrokenLinks: number of broken links only in path2
* distinctBrokenLinks: number of broken links with same name appearing in both path1 and path2
* totalBrokenLinks: total number of broken links (leftBrokenLinks+rightBrokenLinks+distinctBrokenLinks)
* symlinks: Statistics available if 'compareSymlink' options is used
* distinctSymlinks: number of distinct links
* equalSymlinks: number of equal links
* leftSymlinks: number of links only in path1
* rightSymlinks: number of links only in path2
* differencesSymlinks: total number of different links (distinctSymlinks+leftSymlinks+rightSymlinks)
* totalSymlinks: total number of links (differencesSymlinks+equalSymlinks)
* diffSet - List of changes (present if Options.noDiffSet is false)
* path1: absolute path not including file/directory name,
* path2: absolute path not including file/directory name,
* relativePath: common path relative to root,
* name1: file/directory name
* name2: file/directory name
* state: one of equal, left, right, distinct,
* type1: one of missing, file, directory, broken-link
* type2: one of missing, file, directory, broken-link
* size1: file size
* size2: file size
* date1: modification date (stat.mtime)
* date2: modification date (stat.mtime)
* level: depth
* reason: Provides reason when two identically named entries are distinct
* Not available if entries are equal
* One of "different-size", "different-date", "different-content", "broken-link", "different-symlink"
*/
module.exports = {
compareSync: compareSync,
compare: compareAsync,
fileCompareHandlers: {
defaultFileCompare: defaultFileCompare,
lineBasedFileCompare: lineBasedFileCompare
}
}

View file

@ -0,0 +1,12 @@
module.exports = function compareName(name1, name2, options) {
if (options.ignoreCase) {
name1 = name1.toLowerCase()
name2 = name2.toLowerCase()
}
return strcmp(name1, name2)
}
function strcmp(str1, str2) {
return ((str1 === str2) ? 0 : ((str1 > str2) ? 1 : -1))
}

View file

@ -0,0 +1,27 @@
'use strict'
var pathUtils = require('path')
var common = require('../entry/entryBuilder')
var entryType = require('../entry/entryType')
module.exports = function (entry1, entry2, state, level, relativePath, options, statistics, diffSet, reason) {
if (options.noDiffSet) {
return
}
diffSet.push({
path1: entry1 ? pathUtils.dirname(entry1.path) : undefined,
path2: entry2 ? pathUtils.dirname(entry2.path) : undefined,
relativePath: relativePath,
name1: entry1 ? entry1.name : undefined,
name2: entry2 ? entry2.name : undefined,
state: state,
type1: entryType.getType(entry1),
type2: entryType.getType(entry2),
level: level,
size1: entry1 ? entry1.stat.size : undefined,
size2: entry2 ? entry2.stat.size : undefined,
date1: entry1 ? entry1.stat.mtime : undefined,
date2: entry2 ? entry2.stat.mtime : undefined,
reason: reason
})
}

View file

@ -0,0 +1,59 @@
/**
* Controls creation/completion of global statistics object.
*/
module.exports = {
initStats(options) {
var symlinkStatistics = undefined
if (options.compareSymlink) {
symlinkStatistics = {
distinctSymlinks: 0,
equalSymlinks: 0,
leftSymlinks: 0,
rightSymlinks: 0,
differencesSymlinks: 0,
totalSymlinks: 0,
}
}
var brokenLinksStatistics = {
leftBrokenLinks: 0,
rightBrokenLinks: 0,
distinctBrokenLinks: 0,
}
return {
distinct: 0,
equal: 0,
left: 0,
right: 0,
distinctFiles: 0,
equalFiles: 0,
leftFiles: 0,
rightFiles: 0,
distinctDirs: 0,
equalDirs: 0,
leftDirs: 0,
rightDirs: 0,
brokenLinks: brokenLinksStatistics,
symlinks: symlinkStatistics,
same: undefined
}
},
completeStatistics(statistics, options) {
statistics.differences = statistics.distinct + statistics.left + statistics.right
statistics.differencesFiles = statistics.distinctFiles + statistics.leftFiles + statistics.rightFiles
statistics.differencesDirs = statistics.distinctDirs + statistics.leftDirs + statistics.rightDirs
statistics.total = statistics.equal + statistics.differences
statistics.totalFiles = statistics.equalFiles + statistics.differencesFiles
statistics.totalDirs = statistics.equalDirs + statistics.differencesDirs
var brokenLInksStats = statistics.brokenLinks
brokenLInksStats.totalBrokenLinks = brokenLInksStats.leftBrokenLinks + brokenLInksStats.rightBrokenLinks + brokenLInksStats.distinctBrokenLinks
statistics.same = statistics.differences ? false : true
if (options.compareSymlink) {
statistics.symlinks.differencesSymlinks = statistics.symlinks.distinctSymlinks +
statistics.symlinks.leftSymlinks + statistics.symlinks.rightSymlinks
statistics.symlinks.totalSymlinks = statistics.symlinks.differencesSymlinks + statistics.symlinks.equalSymlinks
}
}
}

View file

@ -0,0 +1,62 @@
/**
* Calculates comparison statistics.
*/
module.exports = {
updateStatisticsBoth: function (entry1, entry2, same, reason, type, statistics, options) {
same ? statistics.equal++ : statistics.distinct++
if (type === 'file') {
same ? statistics.equalFiles++ : statistics.distinctFiles++
} else if (type === 'directory') {
same ? statistics.equalDirs++ : statistics.distinctDirs++
} else if (type === 'broken-link') {
statistics.brokenLinks.distinctBrokenLinks++
} else {
throw new Error('Unexpected type ' + type)
}
var isSymlink1 = entry1 ? entry1.isSymlink : false
var isSymlink2 = entry2 ? entry2.isSymlink : false
var isSymlink = isSymlink1 || isSymlink2
if (options.compareSymlink && isSymlink) {
var symlinks = statistics.symlinks
if (reason === 'different-symlink') {
symlinks.distinctSymlinks++
} else {
symlinks.equalSymlinks++
}
}
},
updateStatisticsLeft: function (entry1, type, statistics, options) {
statistics.left++
if (type === 'file') {
statistics.leftFiles++
} else if (type === 'directory') {
statistics.leftDirs++
} else if (type === 'broken-link') {
statistics.brokenLinks.leftBrokenLinks++
} else {
throw new Error('Unexpected type ' + type)
}
if (options.compareSymlink && entry1.isSymlink) {
statistics.symlinks.leftSymlinks++
}
},
updateStatisticsRight: function (entry2, type, statistics, options) {
statistics.right++
if (type === 'file') {
statistics.rightFiles++
} else if (type === 'directory') {
statistics.rightDirs++
} else if (type === 'broken-link') {
statistics.brokenLinks.rightBrokenLinks++
} else {
throw new Error('Unexpected type ' + type)
}
if (options.compareSymlink && entry2.isSymlink) {
statistics.symlinks.rightSymlinks++
}
},
}

View file

@ -0,0 +1,51 @@
var fs = require('fs')
/**
* Provides symlink loop detection to directory traversal algorithm.
*/
module.exports = {
detectLoop: function (entry, symlinkCache) {
if (entry && entry.isSymlink) {
var realPath = fs.realpathSync(entry.absolutePath)
if (symlinkCache[realPath]) {
return true
}
}
return false
},
initSymlinkCache: function() {
return {
dir1: {},
dir2: {}
}
},
updateSymlinkCache: function(symlinkCache, rootEntry1, rootEntry2, loopDetected1, loopDetected2) {
var symlinkCachePath1, symlinkCachePath2
if (rootEntry1 && !loopDetected1) {
symlinkCachePath1 = rootEntry1.isSymlink ? fs.realpathSync(rootEntry1.absolutePath) : rootEntry1.absolutePath
symlinkCache.dir1[symlinkCachePath1] = true
}
if (rootEntry2 && !loopDetected2) {
symlinkCachePath2 = rootEntry2.isSymlink ? fs.realpathSync(rootEntry2.absolutePath) : rootEntry2.absolutePath
symlinkCache.dir2[symlinkCachePath2] = true
}
},
cloneSymlinkCache: function (symlinkCache) {
return {
dir1: shallowClone(symlinkCache.dir1),
dir2: shallowClone(symlinkCache.dir2)
}
},
}
function shallowClone(obj) {
var cloned = {}
Object.keys(obj).forEach(function (key) {
cloned[key] = obj[key]
})
return cloned
}