You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
3.7 KiB
174 lines
3.7 KiB
'use strict'; |
|
|
|
var fs = require('fs'); |
|
var path = require('path'); |
|
|
|
var isPlainObject = require('is-plain-object'); |
|
var pick = require('object.pick'); |
|
var defaults = require('object.defaults/immutable'); |
|
var expandTilde = require('expand-tilde'); |
|
var parsePath = require('parse-filepath'); |
|
|
|
|
|
function fined(pathObj, defaultObj) { |
|
var expandedPath = expandPath(pathObj, defaultObj); |
|
return expandedPath ? findWithExpandedPath(expandedPath) : null; |
|
} |
|
|
|
function expandPath(pathObj, defaultObj) { |
|
if (!isPlainObject(defaultObj)) { |
|
defaultObj = {}; |
|
} |
|
|
|
if (isString(pathObj)) { |
|
pathObj = { path: pathObj }; |
|
} |
|
|
|
if (!isPlainObject(pathObj)) { |
|
pathObj = {}; |
|
} |
|
|
|
pathObj = defaults(pathObj, defaultObj); |
|
|
|
var filePath; |
|
if (!isString(pathObj.path)) { |
|
return null; |
|
} |
|
// Execution of toString is for a String object. |
|
if (isString(pathObj.name) && pathObj.name) { |
|
if (pathObj.path) { |
|
filePath = expandTilde(pathObj.path.toString()); |
|
filePath = path.join(filePath, pathObj.name.toString()); |
|
} else { |
|
filePath = pathObj.name.toString(); |
|
} |
|
} else { |
|
filePath = expandTilde(pathObj.path.toString()); |
|
} |
|
|
|
var extArr = createExtensionArray(pathObj.extensions); |
|
var extMap = createExtensionMap(pathObj.extensions); |
|
|
|
var basedir = isString(pathObj.cwd) ? pathObj.cwd.toString() : '.'; |
|
basedir = path.resolve(expandTilde(basedir)); |
|
|
|
var findUp = !!pathObj.findUp; |
|
|
|
var parsed = parsePath(filePath); |
|
if (parsed.isAbsolute) { |
|
filePath = filePath.slice(parsed.root.length); |
|
findUp = false; |
|
basedir = parsed.root; |
|
/* istanbul ignore if */ |
|
} else if (parsed.root) { // Expanded path has a drive letter on Windows. |
|
filePath = filePath.slice(parsed.root.length); |
|
basedir = path.resolve(parsed.root); |
|
} |
|
|
|
if (parsed.ext) { |
|
filePath = filePath.slice(0, -parsed.ext.length); |
|
// This ensures that only the original extension is matched. |
|
extArr = [parsed.ext]; |
|
} |
|
|
|
return { |
|
path: filePath, |
|
basedir: basedir, |
|
findUp: findUp, |
|
extArr: extArr, |
|
extMap: extMap, |
|
}; |
|
} |
|
|
|
function findWithExpandedPath(expanded) { |
|
var found = expanded.findUp ? |
|
findUpFile(expanded.basedir, expanded.path, expanded.extArr) : |
|
findFile(expanded.basedir, expanded.path, expanded.extArr); |
|
|
|
if (!found) { |
|
return null; |
|
} |
|
|
|
if (expanded.extMap) { |
|
found.extension = pick(expanded.extMap, found.extension); |
|
} |
|
return found; |
|
} |
|
|
|
function findFile(basedir, relpath, extArr) { |
|
var noExtPath = path.resolve(basedir, relpath); |
|
for (var i = 0, n = extArr.length; i < n; i++) { |
|
var filepath = noExtPath + extArr[i]; |
|
try { |
|
fs.statSync(filepath); |
|
return { path: filepath, extension: extArr[i] }; |
|
} catch (e) { |
|
// Ignore error |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
function findUpFile(basedir, filepath, extArr) { |
|
var lastdir; |
|
do { |
|
var found = findFile(basedir, filepath, extArr); |
|
if (found) { |
|
return found; |
|
} |
|
|
|
lastdir = basedir; |
|
basedir = path.dirname(basedir); |
|
} while (lastdir !== basedir); |
|
|
|
return null; |
|
} |
|
|
|
function createExtensionArray(exts) { |
|
if (isString(exts)) { |
|
return [exts]; |
|
} |
|
|
|
if (Array.isArray(exts)) { |
|
exts = exts.filter(isString); |
|
return (exts.length > 0) ? exts : ['']; |
|
} |
|
|
|
if (isPlainObject(exts)) { |
|
exts = Object.keys(exts); |
|
return (exts.length > 0) ? exts : ['']; |
|
} |
|
|
|
return ['']; |
|
} |
|
|
|
function createExtensionMap(exts) { |
|
if (!isPlainObject(exts)) { |
|
return null; |
|
} |
|
|
|
if (isEmpty(exts)) { |
|
return { '': null }; |
|
} |
|
|
|
return exts; |
|
} |
|
|
|
function isEmpty(object) { |
|
return !Object.keys(object).length; |
|
} |
|
|
|
function isString(value) { |
|
if (typeof value === 'string') { |
|
return true; |
|
} |
|
|
|
if (Object.prototype.toString.call(value) === '[object String]') { |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
module.exports = fined;
|
|
|