UNPKG

jspm

Version:

Registry and format agnostic JavaScript package manager

267 lines (231 loc) 8.46 kB
/* * Copyright 2014-2015 Guy Bedford (http://guybedford.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ exports.HOME = process.env.LOCALAPPDATA || process.env.HOME || process.env.HOMEPATH; // default newline to the appropriate value for the system exports.newLine = require('os').EOL; exports.tab = ' '; var ui = require('./ui'); var fs = require('graceful-fs'); var path = require('path'); var PackageConfig = require('./config/package'); var LoaderConfig = require('./config/loader'); var mkdirp = require('mkdirp'); var extend = require('./common').extend; var config = module.exports; var asp = require('rsvp').denodeify; var readJSON = require('./common').readJSON; var PackageName = require('./config/package-name'); // given a package.json file and an override // calculate the package.json file jspm will see exports.derivePackageConfig = function(pjson, override) { var dpjson = extend({}, pjson); // first derive the override if (override || pjson.jspm) dpjson.jspm = extend({}, pjson.jspm || {}); if (override) extend(dpjson.jspm, override); // then apply the override if (override || pjson.jspm) extend(dpjson, dpjson.jspm); return dpjson; }; // package and loader configuration objects that are created exports.pjson = null; exports.loader = null; var loadPromise; exports.loaded = false; exports.load = function(prompts) { if (loadPromise) return loadPromise; return (loadPromise = Promise.resolve() .then(function() { if (process.env.globalJspm === 'true') ui.log('warn', 'Running jspm globally, it is advisable to locally install jspm via %npm install jspm --save-dev%.'); if (!process.env.jspmConfigPath) return ui.confirm('Package.json file does not exist, create it?', true) .then(function(create) { if (!create) throw 'Operation aborted.'; }); }) .then(function() { config.pjsonPath = process.env.jspmConfigPath || path.resolve(process.cwd(), 'package.json'); config.pjson = new PackageConfig(config.pjsonPath); return config.pjson.read(prompts); }) .then(function(_prompts) { // package.json can indicate if we need to run config prompts for a new package prompts = prompts || _prompts; if (fs.existsSync(config.pjson.configFile)) return; return ui.confirm('Configuration file %' + path.relative(process.cwd(), config.pjson.configFile) + '% doesn\'t exist, create it?', true) .then(function(create) { if (!create) throw 'Operation aborted.'; // ensure config folder exists return asp(mkdirp)(path.dirname(config.pjson.configFile)); }); }) .then(function() { config.loader = new LoaderConfig(config.pjson.configFile); return config.loader.read(prompts); }) .then(function() { return readJSON(path.resolve(config.pjson.packages, '.dependencies.json')); }) .then(function(depsJSON) { config.deps = setSerializedDeps(depsJSON); config.loaded = true; })); }; exports.loadSync = function() { if (config.loaded) return; if (loadPromise) throw 'Configuration file is already loading.'; config.pjsonPath = process.env.jspmConfigPath || path.resolve(process.cwd(), 'package.json'); config.pjson = new PackageConfig(config.pjsonPath); config.pjson.read(false, true); if (!fs.existsSync(config.pjson.configFile)) throw 'No project configuration file not found. Looking for: ' + config.pjson.configFile; config.loader = new LoaderConfig(config.pjson.configFile); config.loader.read(false, true); var depsJSON; try { depsJSON = JSON.parse(fs.readFileSync(path.resolve(config.pjson.packages, '.dependencies.json'))); } catch(e) { if (e.code == 'ENOENT') depsJSON = {}; else throw e; } config.deps = setSerializedDeps(depsJSON); config.loaded = true; loadPromise = Promise.resolve(); }; function getSerializedDeps(deps) { var serializedDeps = {}; Object.keys(deps).forEach(function(dep) { var depMap = deps[dep]; var serializedDepMap = serializedDeps[dep] = {}; Object.keys(depMap).forEach(function(dep) { serializedDepMap[dep] = depMap[dep].exactName; }); }); return serializedDeps; } function setSerializedDeps(serializedDeps) { var deps = {}; Object.keys(serializedDeps).forEach(function(dep) { var depMap = deps[dep] = {}; var serializedDepMap = serializedDeps[dep]; Object.keys(serializedDepMap).forEach(function(dep) { if (typeof serializedDepMap[dep] == 'string') depMap[dep] = new PackageName(serializedDepMap[dep]); }); }); return deps; } var savePromise; exports.save = function() { if (savePromise) return savePromise.then(exports.save); return Promise.resolve() .then(function() { return config.loader.write(); }) .then(function() { return config.pjson.write(); }) .then(function() { return asp(mkdirp)(config.pjson.packages); }) .then(function() { return asp(fs.writeFile)(path.resolve(config.pjson.packages, '.dependencies.json'), JSON.stringify(getSerializedDeps(config.deps), null, 2)); }) .then(function() { savePromise = undefined; }); }; // checks to see if the package.json map config // is accurately reflected in the config file // - if the config file has a property not in the package.json, we set it in the package.json // - if the package.json has a property not in the config, we set it in the config // - where there is a conflict, we specifically ask which value to use /* function checkMapConfig() { var conflictPromises = []; if (config.map && hasProperties(config.map)) { var depMap; return Promise.resolve() .then(function() { if (!config.name) return ui.input('Enter project name to use contextual mappings', 'app') .then(function(name) { config.name = name; // if the lib directory is not in package.json, and we've given a name // then the new lib default is the name not 'lib' if (!pjsonCache.directories || !pjsonCache.directories.lib) config.lib = path.resolve(config.dir, config.name); }); }) .then(function() { depMap = config.depMap[config.name] = config.depMap[config.name] || {}; }) .then(function() { // check everything in package.json is reflected in config return Promise.all(Object.keys(config.map).map(function(d) { var curMap = config.map[d]; // ensure package-relative maps are relative and not named if (curMap.startsWith(config.name) && curMap.endsWith('/')) curMap = config.map[d] = '.' + curMap.substr(config.name.length); // maps are package-relative if (curMap.startsWith('./')) curMap = config.name + curMap.substr(1); if (depMap[d] && depMap[d].exactName !== curMap) { return ui.confirm('The config file has a mapping, `' + d + ' -> ' + depMap[d].exactName + '`, while in the %package.json% this is mapped to `' + curMap + '`. Update the package.json?') .then(function(override) { if (override) { var mapVal = depMap[d].exactName; if (mapVal.startsWith(config.name) && mapVal.endsWith('/')) mapVal = '.' + mapVal.substr(config.name.length); config.map[d] = mapVal; } else { depMap[d] = new PackageName(curMap); } }); } else if (!depMap[d]) { depMap[d] = new PackageName(curMap); } })) }) .then(function() { // check everything in config is reflected in package.json return Promise.all(Object.keys(depMap).map(function(d) { // we've handled all package.json now if (config.map[d]) return; config.map[d] = depMap[d].exactName; })); }); } return Promise.resolve(); } */