UNPKG

9.47 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');
17
18var path = require('path');
19var nodeSemver = require('semver');
20var ui = require('./ui');
21var config = require('./config');
22var registry = require('./registry');
23var PackageName = require('./package-name');
24var fs = require('graceful-fs');
25var mkdirp = require('mkdirp');
26var rimraf = require('rimraf');
27var asp = require('bluebird').Promise.promisify;
28var System = require('systemjs');
29var api = require('../api');
30var HOME = require('./common').HOME;
31var Promise = require('bluebird');
32var getCanonicalName = require('systemjs-builder/lib/utils').getCanonicalName;
33var extend = require('./common').extend;
34
35var core = module.exports;
36
37// we always download the latest semver compatible version
38var systemVersion = require('../package.json').dependencies.systemjs;
39
40if (systemVersion.match(/^systemjs\/systemjs\#/))
41 systemVersion = systemVersion.substr(systemVersion.indexOf('#') + 1);
42
43exports.run = function(moduleName, view, production) {
44 return config.load(false, true)
45 .then(function() {
46 System.config(config.getLoaderConfig());
47 if (production || process.env.NODE_ENV === 'production')
48 System.config({ production: true });
49 return System.import(moduleName)
50 .then(function(m) {
51 if (view)
52 console.log(m);
53 });
54 })
55 .catch(function(e) {
56 ui.log('err', e.stack || e);
57 throw e;
58 });
59};
60
61// check and download module loader files
62exports.checkDlLoader = function() {
63 return config.load()
64 .then(function() {
65 return asp(fs.readFile)(path.resolve(config.pjson.packages, '.loaderversions'));
66 })
67 .catch(function(err) {
68 if (err.code === 'ENOENT')
69 return '';
70 throw err;
71 })
72 .then(function(cacheVersions) {
73 if (cacheVersions.toString() !== systemVersion)
74 return exports.dlLoader();
75
76 // even if version file is fresh, still check files exist
77 return asp(fs.readdir)(config.pjson.packages)
78 .catch(function(err) {
79 if (err.code === 'ENOENT')
80 return [];
81 throw err;
82 })
83 .then(function(files) {
84 if (files.indexOf('system.js') === -1)
85 return exports.dlLoader();
86 });
87 });
88};
89
90// mini registry API usage implementation
91var loaderFilesCacheDir = path.join(HOME, '.jspm', 'loader-files');
92
93function dl(name, repo, version) {
94 var pkg = new PackageName(repo);
95 var endpoint = registry.load(pkg.registry);
96 var vMatch, vMatchLookup;
97 var dlDir = path.resolve(loaderFilesCacheDir, name);
98
99 return endpoint.lookup(pkg.package)
100 .then(function(lookup) {
101 if (!(nodeSemver.validRange(version)))
102 vMatch = version;
103 else
104 vMatch = Object.keys(lookup.versions)
105 .filter(nodeSemver.valid)
106 .sort(nodeSemver.compare).reverse()
107 .filter(function(v) {
108 return nodeSemver.satisfies(v, version);
109 })[0];
110
111 vMatchLookup = lookup.versions[vMatch];
112
113 return asp(fs.readFile)(path.resolve(dlDir, '.hash'))
114 .then(function(_hash) {
115 return _hash.toString() === vMatchLookup.hash;
116 }, function (e) {
117 if (e.code === 'ENOENT')
118 return;
119 throw e;
120 });
121 })
122 .then(function(cached) {
123 if (cached)
124 return;
125
126 return endpoint.download(pkg.package, vMatch, vMatchLookup.hash, vMatchLookup.meta, dlDir)
127 .then(function() {
128 return fs.writeFile(path.resolve(dlDir, '.hash'), vMatchLookup.hash);
129 });
130 })
131 .then(function() {
132 return vMatch;
133 });
134}
135
136// file copy implementation
137function cp(file, name, transform) {
138 return asp(fs.readFile)(path.resolve(loaderFilesCacheDir, file)).then(function(source) {
139 if (transform)
140 source = transform(source.toString());
141 ui.log('info', ' `' + name + '`');
142 return asp(fs.writeFile)(path.resolve(config.pjson.packages, name), source);
143 });
144}
145
146exports.dlLoader = function(unminified, edge, latest) {
147 ui.log('info', 'Looking up loader files...');
148 var min = unminified ? '.src' : '';
149
150 var using = {};
151
152 return config.load()
153 .then(function() {
154 return asp(mkdirp)(config.pjson.packages);
155 })
156 .then(function() {
157 // delete old versions
158 return asp(fs.readdir)(config.pjson.packages);
159 })
160 .then(function(files) {
161 return Promise.all(files.filter(function(file) {
162 return file.match(/^(system-csp|system-csp-production|system|es6-module-loader|system-polyfills)/);
163 }).map(function(file) {
164 return asp(fs.unlink)(path.resolve(config.pjson.packages, file));
165 }));
166 })
167 .then(function() {
168 return dl('systemjs', 'github:systemjs/systemjs', !edge ? (!latest ? systemVersion : '^' + systemVersion) : 'master')
169 .then(function(version) {
170 using.system = version;
171 return Promise.all([
172 cp('systemjs/dist/system' + min + '.js', 'system.js'),
173 unminified || cp('systemjs/dist/system.src.js', 'system.src.js'),
174 unminified || cp('systemjs/dist/system.js.map', 'system.js.map'),
175 // cp('systemjs/dist/system-csp-production' + min + '.js', 'system-csp-production.js'),
176 // unminified || cp('systemjs/dist/system-csp-production.src.js', 'system-csp-production.src.js'),
177 // unminified || cp('systemjs/dist/system-csp-production.js.map', 'system-csp-production.js.map'),
178 // cp('systemjs/dist/system-polyfills' + min + '.js', 'system-polyfills.js'),
179 // unminified || cp('systemjs/dist/system-polyfills.src.js', 'system-polyfills.src.js'),
180 // unminified || cp('systemjs/dist/system-polyfills.js.map', 'system-polyfills.js.map')
181 ]);
182 });
183 })
184 .then(function() {
185 ui.log('info', '\nUsing loader versions:');
186 ui.log('info', ' `systemjs@' + using.system + '`');
187
188 return asp(fs.writeFile)(path.resolve(config.pjson.packages, '.loaderversions'), systemVersion);
189 })
190 .then(function() {
191 ui.log('ok', 'Loader files downloaded successfully');
192 }, function(err) {
193 ui.log('err', err);
194 ui.log('err', 'Error downloading loader files.');
195 throw err;
196 });
197};
198
199exports.normalize = function(moduleName, parentName, canonicalize, env) {
200 var loader = new api.Loader();
201
202 // set a custom environment for normalization
203 var envModule = extend(extend({}, loader.get('@system-env')), env);
204 loader.set('@system-env', loader.newModule(envModule));
205
206 // ensure the parent package is loaded first
207 return (parentName && loader.normalize(parentName) || Promise.resolve())
208 .then(function() {
209 return loader.normalize(moduleName, parentName && loader.normalizeSync(parentName));
210 })
211 .then(function(normalized) {
212 if (canonicalize)
213 return getCanonicalName(loader, normalized);
214 return normalized;
215 });
216};
217
218exports.init = function init(basePath) {
219 if (basePath)
220 process.env.jspmConfigPath = path.resolve(basePath, 'package.json');
221 var relBase = path.relative(process.cwd(), path.dirname(process.env.jspmConfigPath || ''));
222 if (relBase !== '')
223 ui.log('info', 'Initializing package at `' + relBase + '/`\nUse %jspm init .% to intialize into the current folder.');
224 return config.load(true)
225 .then(config.save)
226 .then(function() {
227 ui.log('info', '');
228 ui.log('ok', 'package.json at %' + path.relative(process.cwd(), config.pjsonPath) + '%\n' +
229 'Config at %' + path.relative(process.cwd(), config.pjson.configFile) + '%' +
230 (config.loader.devFile ? ', %' + path.relative(process.cwd(), config.pjson.configFileDev) + '%' : '') +
231 (config.loader.browserFile ? ', %' + path.relative(process.cwd(), config.pjson.configFileBrowser) + '%' : '') +
232 (config.loader.nodeFile ? ', %' + path.relative(process.cwd(), config.pjson.configFileNode) + '%' : ''));
233 })
234 .then(function() {
235 return core.checkDlLoader();
236 })
237 .catch(function(err) {
238 ui.log('err', err && err.stack || err);
239 });
240};
241
242exports.cacheClear = function() {
243 var jspmDir = path.resolve(HOME, '.jspm'),
244 packagesCacheDir = path.join(jspmDir, 'packages'),
245 loaderCacheDir = path.join(jspmDir, 'loader-files'),
246 files, filesLength, fileName, i;
247
248 // Clear loader files
249 if (fs.existsSync(loaderCacheDir))
250 rimraf.sync(loaderCacheDir);
251 ui.log('ok', 'Loader file cache cleared.');
252
253 // Clear packages cache folder
254 if (fs.existsSync(packagesCacheDir))
255 rimraf.sync(packagesCacheDir);
256 ui.log('ok', 'Package cache cleared.');
257
258 // Clear registry cache folders
259 files = fs.readdirSync(jspmDir);
260 filesLength = files.length;
261 for (i = 0; i < filesLength; i++) {
262 fileName = files[i];
263 if (fileName.endsWith('-cache')) {
264 rimraf.sync(path.join(jspmDir, fileName));
265 ui.log('ok', '%' + fileName.substr(0, fileName.length - '-cache'.length) + '% cache cleared.');
266 }
267 }
268
269 ui.log('warn', 'All caches cleared.');
270 ui.log('info', 'Please post an issue if you suspect the cache isn\'t invalidating properly.');
271 ui.log('info', '%jspm install -f% is equivalent to running a cache clear for that specific package tree.');
272};