Files
react-native-devtools-frontend/node_modules/karma/lib/file-list.js
T
Jack Franklin 8f8ec22bb3 Update karma to 6.4.0
No changes in the changelog
(https://github.com/karma-runner/karma/blob/master/CHANGELOG.md) to
concern ourselves about, but one useful change is they upgraded the
log4js dependency which was spitting out console messages on each test
run. This is fixed with this version of Karma.

Bug: none
Change-Id: Ic49618cbda7a079cacb9813f5129692a83508a92
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3745621
Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
Auto-Submit: Jack Franklin <jacktfranklin@chromium.org>
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
2022-07-05 10:46:37 +00:00

243 lines
6.7 KiB
JavaScript

'use strict'
const { promisify } = require('util')
const mm = require('minimatch')
const Glob = require('glob').Glob
const fs = require('graceful-fs')
const statAsync = promisify(fs.stat.bind(fs))
const pathLib = require('path')
const _ = require('lodash')
const File = require('./file')
const Url = require('./url')
const helper = require('./helper')
const log = require('./logger').create('filelist')
const createPatternObject = require('./config').createPatternObject
class FileList {
constructor (patterns, excludes, emitter, preprocess, autoWatchBatchDelay) {
this._patterns = patterns || []
this._excludes = excludes || []
this._emitter = emitter
this._preprocess = preprocess
this.buckets = new Map()
// A promise that is pending if and only if we are active in this.refresh_()
this._refreshing = null
const emit = () => {
this._emitter.emit('file_list_modified', this.files)
}
const debouncedEmit = _.debounce(emit, autoWatchBatchDelay)
this._emitModified = (immediate) => {
immediate ? emit() : debouncedEmit()
}
}
_findExcluded (path) {
return this._excludes.find((pattern) => mm(path, pattern))
}
_findIncluded (path) {
return this._patterns.find((pattern) => mm(path, pattern.pattern))
}
_findFile (path, pattern) {
if (!path || !pattern) return
return this._getFilesByPattern(pattern.pattern).find((file) => file.originalPath === path)
}
_exists (path) {
return !!this._patterns.find((pattern) => mm(path, pattern.pattern) && this._findFile(path, pattern))
}
_getFilesByPattern (pattern) {
return this.buckets.get(pattern) || []
}
_refresh () {
const matchedFiles = new Set()
let lastCompletedRefresh = this._refreshing
lastCompletedRefresh = Promise.all(
this._patterns.map(async ({ pattern, type, nocache, isBinary, integrity }) => {
if (helper.isUrlAbsolute(pattern)) {
this.buckets.set(pattern, [new Url(pattern, type, integrity)])
return
}
const mg = new Glob(pathLib.normalize(pattern), { cwd: '/', follow: true, nodir: true, sync: true })
const files = mg.found
.filter((path) => {
if (this._findExcluded(path)) {
log.debug(`Excluded file "${path}"`)
return false
} else if (matchedFiles.has(path)) {
return false
} else {
matchedFiles.add(path)
return true
}
})
.map((path) => new File(path, mg.statCache[path].mtime, nocache, type, isBinary))
if (nocache) {
log.debug(`Not preprocessing "${pattern}" due to nocache`)
} else {
await Promise.all(files.map((file) => this._preprocess(file)))
}
this.buckets.set(pattern, files)
if (_.isEmpty(mg.found)) {
log.warn(`Pattern "${pattern}" does not match any file.`)
} else if (_.isEmpty(files)) {
log.warn(`All files matched by "${pattern}" were excluded or matched by prior matchers.`)
}
})
)
.then(() => {
// When we return from this function the file processing chain will be
// complete. In the case of two fast refresh() calls, the second call
// will overwrite this._refreshing, and we want the status to reflect
// the second call and skip the modification event from the first call.
if (this._refreshing !== lastCompletedRefresh) {
return this._refreshing
}
this._emitModified(true)
return this.files
})
return lastCompletedRefresh
}
get files () {
const served = []
const included = {}
const lookup = {}
this._patterns.forEach((p) => {
// This needs to be here sadly, as plugins are modifiying
// the _patterns directly resulting in elements not being
// instantiated properly
if (p.constructor.name !== 'Pattern') {
p = createPatternObject(p)
}
const files = this._getFilesByPattern(p.pattern)
files.sort((a, b) => {
if (a.path > b.path) return 1
if (a.path < b.path) return -1
return 0
})
if (p.served) {
served.push(...files)
}
files.forEach((file) => {
if (lookup[file.path] && lookup[file.path].compare(p) < 0) return
lookup[file.path] = p
if (p.included) {
included[file.path] = file
} else {
delete included[file.path]
}
})
})
return {
served: _.uniq(served, 'path'),
included: _.values(included)
}
}
refresh () {
this._refreshing = this._refresh()
return this._refreshing
}
reload (patterns, excludes) {
this._patterns = patterns || []
this._excludes = excludes || []
return this.refresh()
}
async addFile (path) {
const excluded = this._findExcluded(path)
if (excluded) {
log.debug(`Add file "${path}" ignored. Excluded by "${excluded}".`)
return this.files
}
const pattern = this._findIncluded(path)
if (!pattern) {
log.debug(`Add file "${path}" ignored. Does not match any pattern.`)
return this.files
}
if (this._exists(path)) {
log.debug(`Add file "${path}" ignored. Already in the list.`)
return this.files
}
const file = new File(path)
this._getFilesByPattern(pattern.pattern).push(file)
const [stat] = await Promise.all([statAsync(path), this._refreshing])
file.mtime = stat.mtime
await this._preprocess(file)
log.info(`Added file "${path}".`)
this._emitModified()
return this.files
}
async changeFile (path, force) {
const pattern = this._findIncluded(path)
const file = this._findFile(path, pattern)
if (!file) {
log.debug(`Changed file "${path}" ignored. Does not match any file in the list.`)
return this.files
}
const [stat] = await Promise.all([statAsync(path), this._refreshing])
if (force || stat.mtime > file.mtime) {
file.mtime = stat.mtime
await this._preprocess(file)
log.info(`Changed file "${path}".`)
this._emitModified(force)
}
return this.files
}
async removeFile (path) {
const pattern = this._findIncluded(path)
const file = this._findFile(path, pattern)
if (file) {
helper.arrayRemove(this._getFilesByPattern(pattern.pattern), file)
log.info(`Removed file "${path}".`)
this._emitModified()
} else {
log.debug(`Removed file "${path}" ignored. Does not match any file in the list.`)
}
return this.files
}
}
FileList.factory = function (config, emitter, preprocess) {
return new FileList(config.files, config.exclude, emitter, preprocess, config.autoWatchBatchDelay)
}
FileList.factory.$inject = ['config', 'emitter', 'preprocess']
module.exports = FileList