Spaces:
Sleeping
Sleeping
var debug = require('debug')('nodemon'); | |
var fs = require('fs'); | |
var path = require('path'); | |
var exists = fs.exists || path.exists; | |
var utils = require('../utils'); | |
var rules = require('../rules'); | |
var parse = require('../rules/parse'); | |
var exec = require('./exec'); | |
var defaults = require('./defaults'); | |
module.exports = load; | |
module.exports.mutateExecOptions = mutateExecOptions; | |
var existsSync = fs.existsSync || path.existsSync; | |
function findAppScript() { | |
// nodemon has been run alone, so try to read the package file | |
// or try to read the index.js file | |
if (existsSync('./index.js')) { | |
return 'index.js'; | |
} | |
} | |
/** | |
* Load the nodemon config, first reading the global root/nodemon.json, then | |
* the local nodemon.json to the exec and then overwriting using any user | |
* specified settings (i.e. from the cli) | |
* | |
* @param {Object} settings user defined settings | |
* @param {Function} ready callback that receives complete config | |
*/ | |
function load(settings, options, config, callback) { | |
config.loaded = []; | |
// first load the root nodemon.json | |
loadFile(options, config, utils.home, function (options) { | |
// then load the user's local configuration file | |
if (settings.configFile) { | |
options.configFile = path.resolve(settings.configFile); | |
} | |
loadFile(options, config, process.cwd(), function (options) { | |
// Then merge over with the user settings (parsed from the cli). | |
// Note that merge protects and favours existing values over new values, | |
// and thus command line arguments get priority | |
options = utils.merge(settings, options); | |
// legacy support | |
if (!Array.isArray(options.ignore)) { | |
options.ignore = [options.ignore]; | |
} | |
if (!options.ignoreRoot) { | |
options.ignoreRoot = defaults.ignoreRoot; | |
} | |
// blend the user ignore and the default ignore together | |
if (options.ignoreRoot && options.ignore) { | |
if (!Array.isArray(options.ignoreRoot)) { | |
options.ignoreRoot = [options.ignoreRoot]; | |
} | |
options.ignore = options.ignoreRoot.concat(options.ignore); | |
} else { | |
options.ignore = defaults.ignore.concat(options.ignore); | |
} | |
// add in any missing defaults | |
options = utils.merge(options, defaults); | |
if (!options.script && !options.exec) { | |
var found = findAppScript(); | |
if (found) { | |
if (!options.args) { | |
options.args = []; | |
} | |
// if the script is found as a result of not being on the command | |
// line, then we move any of the pre double-dash args in execArgs | |
const n = options.scriptPosition === null ? | |
options.args.length : options.scriptPosition; | |
options.execArgs = (options.execArgs || []) | |
.concat(options.args.splice(0, n)); | |
options.scriptPosition = null; | |
options.script = found; | |
} | |
} | |
mutateExecOptions(options); | |
if (options.quiet) { | |
utils.quiet(); | |
} | |
if (options.verbose) { | |
utils.debug = true; | |
} | |
// simplify the ready callback to be called after the rules are normalised | |
// from strings to regexp through the rules lib. Note that this gets | |
// created *after* options is overwritten twice in the lines above. | |
var ready = function (options) { | |
normaliseRules(options, callback); | |
}; | |
// if we didn't pick up a nodemon.json file & there's no cli ignores | |
// then try loading an old style .nodemonignore file | |
if (config.loaded.length === 0) { | |
var legacy = loadLegacyIgnore.bind(null, options, config, ready); | |
// first try .nodemonignore, if that doesn't exist, try nodemon-ignore | |
return legacy('.nodemonignore', function () { | |
legacy('nodemon-ignore', function (options) { | |
ready(options); | |
}); | |
}); | |
} | |
ready(options); | |
}); | |
}); | |
} | |
/** | |
* Loads the old style nodemonignore files which is a list of patterns | |
* in a file to ignore | |
* | |
* @param {Object} options nodemon user options | |
* @param {Function} success | |
* @param {String} filename ignore file (.nodemonignore or nodemon-ignore) | |
* @param {Function} fail (optional) failure callback | |
*/ | |
function loadLegacyIgnore(options, config, success, filename, fail) { | |
var ignoreFile = path.join(process.cwd(), filename); | |
exists(ignoreFile, function (exists) { | |
if (exists) { | |
config.loaded.push(ignoreFile); | |
return parse(ignoreFile, function (error, rules) { | |
options.ignore = rules.raw; | |
success(options); | |
}); | |
} | |
if (fail) { | |
fail(options); | |
} else { | |
success(options); | |
} | |
}); | |
} | |
function normaliseRules(options, ready) { | |
// convert ignore and watch options to rules/regexp | |
rules.watch.add(options.watch); | |
rules.ignore.add(options.ignore); | |
// normalise the watch and ignore arrays | |
options.watch = options.watch === false ? false : rules.rules.watch; | |
options.ignore = rules.rules.ignore; | |
ready(options); | |
} | |
/** | |
* Looks for a config in the current working directory, and a config in the | |
* user's home directory, merging the two together, giving priority to local | |
* config. This can then be overwritten later by command line arguments | |
* | |
* @param {Function} ready callback to pass loaded settings to | |
*/ | |
function loadFile(options, config, dir, ready) { | |
if (!ready) { | |
ready = function () { }; | |
} | |
var callback = function (settings) { | |
// prefer the local nodemon.json and fill in missing items using | |
// the global options | |
ready(utils.merge(settings, options)); | |
}; | |
if (!dir) { | |
return callback({}); | |
} | |
var filename = options.configFile || path.join(dir, 'nodemon.json'); | |
if (config.loaded.indexOf(filename) !== -1) { | |
// don't bother re-parsing the same config file | |
return callback({}); | |
} | |
fs.readFile(filename, 'utf8', function (err, data) { | |
if (err) { | |
if (err.code === 'ENOENT') { | |
if (!options.configFile && dir !== utils.home) { | |
// if no specified local config file and local nodemon.json | |
// doesn't exist, try the package.json | |
return loadPackageJSON(config, callback); | |
} | |
} | |
return callback({}); | |
} | |
var settings = {}; | |
try { | |
settings = JSON.parse(data.toString('utf8').replace(/^\uFEFF/, '')); | |
if (!filename.endsWith('package.json') || settings.nodemonConfig) { | |
config.loaded.push(filename); | |
} | |
} catch (e) { | |
utils.log.fail('Failed to parse config ' + filename); | |
console.error(e); | |
process.exit(1); | |
} | |
// options values will overwrite settings | |
callback(settings); | |
}); | |
} | |
function loadPackageJSON(config, ready) { | |
if (!ready) { | |
ready = () => { }; | |
} | |
const dir = process.cwd(); | |
const filename = path.join(dir, 'package.json'); | |
const packageLoadOptions = { configFile: filename }; | |
return loadFile(packageLoadOptions, config, dir, settings => { | |
ready(settings.nodemonConfig || {}); | |
}); | |
} | |
function mutateExecOptions(options) { | |
// work out the execOptions based on the final config we have | |
options.execOptions = exec({ | |
script: options.script, | |
exec: options.exec, | |
args: options.args, | |
scriptPosition: options.scriptPosition, | |
nodeArgs: options.nodeArgs, | |
execArgs: options.execArgs, | |
ext: options.ext, | |
env: options.env, | |
}, options.execMap); | |
// clean up values that we don't need at the top level | |
delete options.scriptPosition; | |
delete options.script; | |
delete options.args; | |
delete options.ext; | |
return options; | |
} | |