lib/linenumber.js
(function() {
// Decide what environment we're running in
var isNode = typeof module !== 'undefined' && this.module !== module;
/* istanbul ignore next */
var fs = isNode ? require('fs') : {};
var loader;
var defaults = {
sync: fs.readFileSync,
async: fs.readFile,
args: [{ encoding: 'utf8' }],
context: fs
};
var find = function(contents, query, file) {
// Create a regex for the query if it's not one already
var regex = query instanceof RegExp ? query : new RegExp(query, 'g');
// For performance, make sure the contents actual contain the pattern
// before we parse them.
if (!regex.test(contents)) {
return null;
} else {
// regex.test advances the search index, so we need to reset it
regex.lastIndex = 0;
var match;
var matches = [];
// Iterate over the matches
while ((match = regex.exec(contents)) !== null) {
// and construct an object of the matches that includes
// line and the string that matches, as well as the file
// name if there is one.
var matchObj = {
line: contents.substring(0, match.index).split('\n').length,
match: match[0]
};
if (file) {
matchObj.file = file;
}
matches.push(matchObj);
}
return matches;
}
};
var linenumber = function(file, query, cb) {
var process = function() {
var matches = find.apply(null, arguments);
if (cb && cb.length === 1) {
cb(matches);
} else if (cb) {
cb(null, matches);
} else {
return matches;
}
};
// If "file" looks like a filename
if (file.indexOf('\n') === -1 && file.indexOf('.') > -1) {
// If we have a callback and an async loading mechanism
if (cb && loader.async) {
// Invoke the loader with the supplied context and any additional args, but wrap the callback
loader.async.apply(loader.context, [file].concat(loader.args).concat(function(err, contents) {
// If the callback expects a single argument, that means "err"
// is not an error, but the actual file contents
if (cb.length === 1) {
cb(find(err, query, file));
}
// If the length is greater than 1, do normal node signature stuff
else if (err) {
cb(err);
} else {
cb(null, find(contents, query, file));
}
}));
} else {
var contents = loader.sync.apply(loader.context, [file].concat(loader.args));
return process(contents, query, file);
}
} else {
// "file" is actually the contents to parse
return process(file, query);
}
};
var _loader = function(fn, args, context) {
if (fn.constructor.name === 'Array') {
loader = {
sync: fn[0],
async: fn[1],
args: args,
context: context
};
} else if (fn.constructor.name === 'Object') {
loader = {
sync: fn.sync,
async: fn.async,
args: args,
context: context
};
}
};
linenumber.loader = function(fn) {
var args = [].slice.call(arguments, 1);
if (typeof fn === 'function') {
_loader({ async: fn }, args, this);
} else {
_loader(fn, args, this);
}
};
linenumber.loaderSync = function(fn) {
var args = [].slice.call(arguments, 1);
if (typeof fn === 'function') {
_loader({ sync: fn }, args, this);
} else {
_loader(fn, args, this);
}
};
linenumber.reset = function() {
loader = {
sync: defaults.sync,
async: defaults.async,
args: defaults.args,
context: defaults.context
};
};
// Initialize loader and args
linenumber.reset();
/* istanbul ignore else */
if (isNode) {
module.exports = linenumber;
} else {
window.linenumber = linenumber;
}
})();