repolinter
Version:
Lint open source repositories
142 lines (132 loc) • 4.37 kB
JavaScript
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
const Result = require('../lib/result')
// eslint-disable-next-line no-unused-vars
const FileSystem = require('../lib/file_system')
/**
* @type {any}
* @ignore
*/
const fetch = require('node-fetch')
/**
* Prepend or append text to a file
*
* @param {FileSystem} fs A filesystem object configured with filter paths and target directories
* @param {object} options The rule configuration
* @param {string[]} targets The files to modify (will be overridden by options if present)
* @param {boolean} dryRun If true, repolinter will report suggested fixes, but will make no disk modifications.
* @returns {Promise<Result>} The lint rule result
* @ignore
*/
async function fileModify(fs, options, targets, dryRun = false) {
const realTargets = options.files || targets
if (realTargets.length === 0) {
return new Result(
'No files to modify, did you configure this fix correctly?',
[],
false
)
}
// find all files matching the regular expressions specified
let files = await fs.findAllFiles(realTargets, options.nocase)
// skip files if necessary
if (options['skip-paths-matching']) {
let regexes = []
const extensions = options['skip-paths-matching'].extensions
if (extensions && extensions.length > 0) {
const extJoined = extensions.join('|')
// \.(svg|png|exe)$
regexes.push(new RegExp('.(' + extJoined + ')$', 'i')) // eslint-disable-line no-useless-escape
}
const patterns = options['skip-paths-matching'].patterns
if (patterns && patterns.length > 0) {
const filteredPatterns = patterns
.filter(p => typeof p === 'string' && p !== '')
.map(p => new RegExp(p, options['skip-paths-matching'].flags))
regexes = regexes.concat(filteredPatterns)
}
files = files.filter(file => !regexes.some(regex => file.match(regex)))
}
// read the text from the source, if necessary
let content
if (typeof options.text === 'string') {
content = options.text
} else if (typeof options.text === 'object') {
if (options.text.url) {
const req = await fetch(options.text.url)
if (!req.ok) {
return new Result(
`Could not fetch from ${options.text.url}, received status code ${req.status}`,
[],
false
)
}
content = await req.text()
} else if (options.text.file) {
const file = await fs.findFirstFile(
[options.text.file],
options.text.nocase === true
)
if (!file) {
return new Result(
`Could not find file matching pattern ${options.text.file} for file-modify.`,
[],
false
)
}
content = await fs.getFileContents(file)
}
}
if (!content) {
return new Result(
'Text was not specified for file-modify! Did you configure the ruleset correctly?',
[],
false
)
}
// write it to the file
const resTargets = await Promise.all(
files.map(async file => {
// do file operation
if (!dryRun) {
const startNewlines =
options.newlines && options.newlines.begin
? new Array(options.newlines.begin).fill('\n').join('')
: ''
const endNewlines =
options.newlines && options.newlines.end
? new Array(options.newlines.end).fill('\n').join('')
: ''
const fileContent = startNewlines + content + endNewlines
if (options.write_mode === 'prepend') {
await fs.setFileContents(
file,
fileContent + (await fs.getFileContents(file))
)
} else {
await fs.setFileContents(
file,
(await fs.getFileContents(file)) + fileContent
)
}
}
// return the target information
const message =
typeof options.text === 'object'
? `${options.write_mode} text from ${
options.text.file || options.text.url
} to file`
: `${options.write_mode} \`${JSON.stringify(content).slice(
1,
-1
)}\` to file`
return {
message,
passed: true,
path: file
}
})
)
return new Result('', resTargets, true)
}
module.exports = fileModify