UNPKG

7.9 kBJavaScriptView Raw
1/*
2 * Copyright 2014-2016 Guy Bedford (http://guybedford.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16require('core-js/es6/string');
17var fs = require('graceful-fs');
18var path = require('path');
19var asp = require('bluebird').Promise.promisify;
20
21// SystemJS isPlain plain name detection function
22var absURLRegEx = /^[^\/]+:\/\//;
23exports.absURLRegEx = absURLRegEx;
24
25exports.isPlain = isPlain;
26function isPlain(name) {
27 return (name[0] != '.' || (!!name[1] && name[1] != '/' && name[1] != '.')) && name[0] != '/' && !name.match(absURLRegEx);
28}
29
30// the opposite of extend
31// useful for setting default config
32exports.dprepend = function dprepend(a, b) {
33 for (var p in b) {
34 var val = b[p];
35 if (val instanceof Array && !(p in a))
36 a[p] = val.concat([]);
37 if (typeof val === 'object')
38 dprepend(a[p] = typeof a[p] === 'object' ? a[p] : {}, val);
39 else if (!(p in a))
40 a[p] = val;
41 }
42 return a;
43};
44
45exports.prepend = prepend;
46function prepend(a, b) {
47 for (var p in b)
48 if (!(p in a))
49 a[p] = b[p];
50 return a;
51}
52
53exports.extend = extend;
54function extend(a, b) {
55 for (var p in b)
56 a[p] = b[p];
57 return a;
58}
59
60function dextend(a, b) {
61 for (var p in b) {
62 var val = b[p];
63 if (val instanceof Array)
64 a[p] = val.concat([]);
65 else if (typeof val === 'object')
66 dextend(a[p] = typeof a[p] === 'object' ? a[p] : {}, val);
67 else
68 a[p] = val;
69 }
70 return a;
71}
72exports.dextend = dextend;
73
74exports.inDir = inDir;
75function inDir(fileName, dir, strictlyWithin, sep) {
76 sep = sep || path.sep;
77 if (dir[dir.length - 1] != sep)
78 dir += sep;
79 return fileName.substr(0, dir.length) === dir && (strictlyWithin === false || fileName[dir.length - 1] === sep);
80}
81
82exports.readJSONSync = function(file) {
83 var pjson;
84 try {
85 pjson = fs.readFileSync(file).toString();
86 }
87 catch(e) {
88 if (e.code === 'ENOENT')
89 pjson = '{}';
90 else
91 throw e;
92 }
93 if (pjson.startsWith('\uFEFF'))
94 pjson = pjson.substr(1);
95 try {
96 return JSON.parse(pjson);
97 }
98 catch(e) {
99 throw 'Error parsing package.json file ' + file;
100 }
101 return pjson;
102};
103
104exports.HOME = process.env.JSPM_GLOBAL_PATH || process.env.LOCALAPPDATA || process.env.HOME || process.env.HOMEPATH;
105
106var isWin = process.platform.match(/^win/);
107exports.isWin = isWin;
108
109exports.toFileURL = function toFileURL(path) {
110 return 'file://' + (isWin ? '/' : '') + path.replace(/\\/g, '/');
111};
112
113exports.fromFileURL = function fromFileURL(path) {
114 if (path.substr(0, 7) == 'file://')
115 return path.substr(isWin ? 8 : 7).replace(path.sep, '/');
116 else
117 return path;
118};
119
120// given a deps object and registry
121// return the map of names to PackageName objects
122var PackageName = require('./package-name');
123exports.processDeps = processDeps;
124function processDeps(deps, registry, debugName) {
125 var outdeps = {};
126 if (!deps)
127 return outdeps;
128 Object.keys(deps).forEach(function(p) {
129 var dep = deps[p];
130
131 if (dep instanceof PackageName) {
132 outdeps[p] = dep;
133 return outdeps[p];
134 }
135
136 var outPackage;
137
138 // jquery: github:components/jquery
139 // jquery: jquery@1.5
140 // -> RHS is dep
141 if (dep.indexOf(':') !== -1)
142 outPackage = dep;
143
144 else if (!registry)
145 throw new TypeError('Install of %' + p + '% to `' + dep + '` within `' + debugName + '` has no registry property provided.');
146
147 // jquery: components/jquery@1.5
148 else if (dep.lastIndexOf('@') > 0)
149 outPackage = registry + ':' + dep;
150
151 // jquery: 1.5
152 else
153 outPackage = registry + ':' + p + '@' + dep;
154
155 outdeps[p] = new PackageName(outPackage, false);
156 });
157 return outdeps;
158}
159
160exports.hasProperties = function(obj) {
161 for (var p in obj) {
162 if (obj.hasOwnProperty(p))
163 return true;
164 }
165 return false;
166};
167
168exports.readJSON = function(file) {
169 return asp(fs.readFile)(file)
170 .then(function(pjson) {
171 pjson = pjson.toString();
172 // remove any byte order mark
173 if (pjson.startsWith('\uFEFF'))
174 pjson = pjson.substr(1);
175 try {
176 return JSON.parse(pjson);
177 }
178 catch(e) {
179 throw 'Error parsing JSON file ' + file;
180 }
181 }, function(err) {
182 if (err.code === 'ENOENT')
183 return {};
184 throw err;
185 });
186};
187
188exports.md5 = function(input) {
189 var crypto = require('crypto');
190 var md5Hash = crypto.createHash('md5');
191 md5Hash.update(input);
192 return md5Hash.digest('hex');
193};
194
195// given an object, create a new object with the properties ordered alphabetically
196exports.alphabetize = function(obj) {
197 var newObj = {};
198 Object.keys(obj).sort().forEach(function(p) {
199 newObj[p] = obj[p];
200 });
201 return newObj;
202};
203
204// default newline to the appropriate value for the system
205var newLine = require('os').EOL;
206exports.newLine = newLine;
207var tab = ' ';
208exports.stringify = function(subject, replacer) {
209 return JSON.stringify(subject, replacer, tab).replace(/\n/g, newLine);
210};
211
212/* Recursively remove directory, all those above it, if they are empty.
213 * Takes optional `stopDir` to terminate at. */
214 exports.cascadeDelete = cascadeDelete;
215function cascadeDelete(dir, stopDir) {
216 if (dir && dir !== stopDir) {
217 return asp(fs.rmdir)(dir)
218 .catch(function(err) {
219 // just continue if directory does not exist
220 if (err.code !== 'ENOENT')
221 throw err;
222 })
223 .then(function() {
224 return cascadeDelete(path.dirname(dir), stopDir);
225 })
226 .catch(function(err) {
227 // gracefully stop at first non-empty directory
228 if (err.code !== 'ENOTEMPTY')
229 throw err;
230 });
231 }
232}
233
234// meta first-level extends where:
235// array + array appends
236// object + object extends
237// other properties replace
238function extendMeta(a, b) {
239 for (var p in b) {
240 var val = b[p];
241 if (!(p in a))
242 a[p] = val;
243 else if (val instanceof Array && a[p] instanceof Array)
244 a[p] = a[p].concat(val);
245 else if (typeof val == 'object' && typeof a[p] == 'object')
246 a[p] = extend(a[p], val);
247 else
248 a[p] = val;
249 }
250}
251
252exports.extendSystemConfig = extendSystemConfig;
253function extendSystemConfig(configA, configB) {
254
255 Object.keys(configB).forEach(function(p) {
256 if (!(p in configA))
257 configA[p] = configB[p];
258
259 else if (['paths', 'bundles', 'depCache', 'map'].indexOf(p) != -1)
260 extend(configA[p], configB[p]);
261
262 else if (p == 'meta')
263 Object.keys(configB.meta).forEach(function(path) {
264 if (!(path in configA.meta))
265 configA.meta[path] = configB.meta[path];
266 else
267 extendMeta(configA.meta[path], configB.meta[path]);
268 });
269
270 else if (p == 'packages')
271 Object.keys(configB.packages).forEach(function(path) {
272 if (!(path in configA.packages))
273 configA.packages[path] = configB.packages[path];
274 else
275 Object.keys(configB.packages[path]).forEach(function(pkgCfg) {
276 if (!(pkgCfg in configA.packages[path]))
277 configA.packages[path][pkgCfg] = configB.packages[path][pkgCfg];
278 else if (pkgCfg == 'map')
279 extend(configA.packages[path].map, configB.packages[path].map);
280 else if (pkgCfg == 'modules')
281 extendMeta(configA.packages[path].modules, configB.packages[path].modules);
282 else
283 configA.packages[path][pkgCfg] = configB.packages[path][pkgCfg];
284 });
285 });
286
287 else
288 configA[p] = configB[p];
289 });
290
291 return configA;
292}