Initial commit
[yaffs-website] / node_modules / fined / index.js
1 'use strict';
2
3 var fs = require('fs');
4 var path = require('path');
5
6 var isString = require('lodash.isstring');
7 var isPlainObject = require('lodash.isplainobject');
8 var isEmpty = require('lodash.isempty');
9 var pick = require('lodash.pick');
10 var assignWith = require('lodash.assignwith');
11
12 var expandTilde = require('expand-tilde');
13 var parsePath = require('parse-filepath');
14
15 function assignNullish(objValue, srcValue) {
16   return (srcValue == null ? objValue : srcValue);
17 }
18
19 function defaults(mainObj, defaultObj) {
20   return assignWith({}, defaultObj, mainObj, assignNullish);
21 }
22
23 function fined(pathObj, defaultObj) {
24   var expandedPath = expandPath(pathObj, defaultObj);
25   return expandedPath ? findWithExpandedPath(expandedPath) : null;
26 }
27
28 function expandPath(pathObj, defaultObj) {
29   if (!isPlainObject(defaultObj)) {
30     defaultObj = {};
31   }
32
33   if (isString(pathObj)) {
34     pathObj = { path: pathObj };
35   }
36
37   if (!isPlainObject(pathObj)) {
38     pathObj = {};
39   }
40
41   pathObj = defaults(pathObj, defaultObj);
42
43   var filePath;
44   if (!isString(pathObj.path)) {
45     return null;
46   }
47   // Execution of toString is for a String object.
48   if (isString(pathObj.name) && pathObj.name) {
49     if (pathObj.path) {
50       filePath = expandTilde(pathObj.path.toString());
51       filePath = path.join(filePath, pathObj.name.toString());
52     } else {
53       filePath = pathObj.name.toString();
54     }
55   } else {
56     filePath = expandTilde(pathObj.path.toString());
57   }
58
59   var extArr = createExtensionArray(pathObj.extensions);
60   var extMap = createExtensionMap(pathObj.extensions);
61
62   var basedir = isString(pathObj.cwd) ? pathObj.cwd.toString() : '.';
63   basedir = path.resolve(expandTilde(basedir));
64
65   var findUp = !!pathObj.findUp;
66
67   var parsed = parsePath(filePath);
68   if (parsed.isAbsolute) {
69     filePath = filePath.slice(parsed.root.length);
70     findUp = false;
71     basedir = parsed.root;
72   } else if (parsed.root) { // Expanded path has a drive letter on Windows.
73     filePath = filePath.slice(parsed.root.length);
74     basedir = path.resolve(parsed.root);
75   }
76
77   return {
78     path: filePath,
79     basedir: basedir,
80     findUp: findUp,
81     extArr: extArr,
82     extMap: extMap,
83   };
84 }
85
86 function findWithExpandedPath(expanded) {
87   var found = expanded.findUp ?
88     findUpFile(expanded.basedir, expanded.path, expanded.extArr) :
89     findFile(expanded.basedir, expanded.path, expanded.extArr);
90
91   if (!found) {
92     return null;
93   }
94
95   if (expanded.extMap) {
96     found.extension = pick(expanded.extMap, found.extension);
97   }
98   return found;
99 }
100
101 function findFile(basedir, relpath, extArr) {
102   var noExtPath = path.resolve(basedir, relpath);
103   for (var i = 0, n = extArr.length; i < n; i++) {
104     var filepath = noExtPath + extArr[i];
105     try {
106       fs.statSync(filepath);
107       return { path: filepath, extension: extArr[i] };
108     } catch (e) {}
109   }
110
111   return null;
112 }
113
114 function findUpFile(basedir, filepath, extArr) {
115   var lastdir;
116   do {
117     var found = findFile(basedir, filepath, extArr);
118     if (found) {
119       return found;
120     }
121
122     lastdir = basedir;
123     basedir = path.dirname(basedir);
124   } while (lastdir !== basedir);
125
126   return null;
127 }
128
129 function createExtensionArray(exts) {
130   if (isString(exts)) {
131     return [exts];
132   }
133
134   if (Array.isArray(exts)) {
135     exts = exts.filter(isString);
136     return (exts.length > 0) ? exts : [''];
137   }
138
139   if (isPlainObject(exts)) {
140     exts = Object.keys(exts);
141     return (exts.length > 0) ? exts : [''];
142   }
143
144   return [''];
145 }
146
147 function createExtensionMap(exts) {
148   if (!isPlainObject(exts)) {
149     return null;
150   }
151
152   if (isEmpty(exts)) {
153     return { '': null };
154   }
155
156   return exts;
157 }
158
159 module.exports = fined;