UNPKG

ionic

Version:

A tool for creating and developing Ionic Framework mobile apps.

443 lines (419 loc) • 14.9 kB
var fs = require('fs'); var IonicProject = require('./project'); var Utils = require('./utils'); var request = require('request'); var Q = require('q'); var settings = require('./settings'); var cheerio = require('cheerio'); var log = require('./logging').logger; var IoConfig = module.exports; var CORE_FILE = './www/lib/ionic-platform-web-client/dist/ionic.io.bundle.js'; var CORE_FILE_MIN = './www/lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js'; var CONFIG_BACKUP = './.io-config.json'; var INDEX_FILE = './www/index.html'; var APP_FILE = './www/js/app.js'; var IO_COMPONENTS = { 'ionic-platform-web-client': { name: 'ionic.service.core', path: 'lib/ionic-platform-web-client/dist/ionic.io.bundle.js', minPath: 'lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js', config: [ { key: 'dev_push', value: 'true' } ] }, ngCordova: { name: 'ngCordova', path: 'lib/ngCordova/dist/ng-cordova.js', minPath: 'lib/ngCordova/dist/ng-cordova.js', config: [] } }; var ALLOWED_CONFIG = { app_id: { // eslint-disable-line camelcase type: 'string' }, api_key: { // eslint-disable-line camelcase type: 'string' }, disable_modifications: { // eslint-disable-line camelcase type: 'boolean' }, dev_push: { // eslint-disable-line camelcase type: 'boolean' }, gcm_key: { // eslint-disable-line camelcase type: 'string' }, io_api: { // eslint-disable-line camelcase type: 'string' }, push_api: { // eslint-disable-line camelcase type: 'string' } }; var SETTINGS_REPLACE_START = "\\\"IONIC_SETTINGS_STRING_START\\\";"; // eslint-disable-line quotes var SETTINGS_REPLACE_END = "\\\"IONIC_SETTINGS_STRING_END\\\""; // eslint-disable-line quotes var SETTINGS_REPLACEMENT = 'return { get: function(setting) { if (settings[setting]) {' + 'return settings[setting]; } return null; } };'; IoConfig.isCoreAvailable = function isCoreAvailable() { var deferred = Q.defer(); fs.exists(CORE_FILE, function(exists) { if (exists) { deferred.resolve(true); } else { deferred.resolve(false); } }); return deferred.promise; }; IoConfig.doesHaveKey = function doesHaveKey(key) { var deferred = Q.defer(); fs.readFile(CONFIG_BACKUP, function(err, data) { if (err) { deferred.reject(err); } if (data) { var jsonObj = JSON.parse(data); if (jsonObj[key]) { deferred.resolve(true); } else { deferred.resolve(false); } } else { deferred.resolve(false); } }); return deferred.promise; }; IoConfig.listConfig = function listConfig() { fs.readFile(CONFIG_BACKUP, function(err, data) { if (err) { if (!err.code === 'ENOENT') { log.error('Error reading config', err); } } else if (data) { var jsonObj = JSON.parse(data); var keys = [{ key: 'KEY:', value: ' VALUE:' }]; var longest = -1; for (var key in jsonObj) { if (jsonObj.hasOwnProperty(key)) { if (key.length + 1 > longest) { longest = key.length + 1; } keys.push({ key: key + ' ', value: '| ' + jsonObj[key] }); } } keys.forEach(function(item) { while (item.key.length < longest) { item.key += ' '; } log.info(item.key + item.value); }); } }); }; IoConfig.warnMissingData = function warnMissingData() { var deferred = Q.defer(); var jsonObj = {}; fs.readFile(CONFIG_BACKUP, function(err, data) { if (err && !err.code === 'ENOENT') { deferred.reject(new Error(err)); } else if (data) { jsonObj = JSON.parse(data); var safe = true; if (!jsonObj['app_id'] || !jsonObj['api_key']) { safe = false; } deferred.resolve(safe); } }); return deferred.promise; }; IoConfig.writeIoConfig = function writeIoConfig(key, val, set) { var deferred = Q.defer(); if (ALLOWED_CONFIG[key] || key === false) { var type = 'undefined'; if (!key === false) { type = ALLOWED_CONFIG[key].type; } fs.readFile(CONFIG_BACKUP, function(err, data) { var jsonObj = {}; if (err) { if (err.code === 'ENOENT') { if (key && set) { if (type === 'boolean') { if (val === 'true') { jsonObj[key] = true; } else { jsonObj[key] = false; } } else if (type === 'string') { jsonObj[key] = String(val); } else { jsonObj[key] = val; } } } else { deferred.reject(new Error(err)); } } else { jsonObj = JSON.parse(data); if (key) { if (set) { if (type === 'boolean') { if (val === 'true') { jsonObj[key] = true; } else { jsonObj[key] = false; } } else if (type === 'string') { jsonObj[key] = String(val); } else { jsonObj[key] = val; } } else if (!set && jsonObj[key]) { delete jsonObj[key]; } } } fs.writeFile(CONFIG_BACKUP, JSON.stringify(jsonObj), function(error) { if (error) { deferred.reject(new Error(error)); } else { if (key) { log.info('Saved ' + key + ', writing to ionic.io.bundle.min.js...'); } else { log.info('Building platform config...'); } IoConfig.isCoreAvailable().then(function(available) { if (available) { fs.readFile(CORE_FILE_MIN, function(er, content) { var jsMinFile = String(content); var replacementString = 'var settings = ' + JSON.stringify(jsonObj) + '; ' + SETTINGS_REPLACEMENT; jsMinFile = jsMinFile.replace(new RegExp('(' + SETTINGS_REPLACE_START + ')(.*?)(' + SETTINGS_REPLACE_END + ')', 'g'), '$1' + replacementString + '$3'); if (jsMinFile) { fs.writeFile(CORE_FILE_MIN, jsMinFile, function(e) { if (e) { deferred.reject(new Error(e)); } deferred.resolve(key); }); } else { log.error('Unable to build the config factory'); deferred.resolve(key); } }); fs.readFile(CORE_FILE, function(er, content) { var jsFile = String(content); var replacementString = 'var settings = ' + JSON.stringify(jsonObj) + '; ' + SETTINGS_REPLACEMENT; jsFile = jsFile.replace(new RegExp('(' + SETTINGS_REPLACE_START + ')(.*?)(' + SETTINGS_REPLACE_END + ';)', 'g'), '$1' + replacementString + '$3'); if (jsFile) { fs.writeFile(CORE_FILE, jsFile, function(e) { if (e) { deferred.reject(new Error(e)); } deferred.resolve(key); }); } else { log.error('Unable to build the config factory'); deferred.resolve(key); } }); } else { deferred.resolve(key); } }); } }); }); } else { log.error('Unauthorized configuration value'); deferred.reject('Unauthorized configuration value'); } return deferred.promise; }; IoConfig.getAppId = function getAppId() { return IonicProject.load('.').get().app_id; }; IoConfig.injectIoComponent = function injectIoComponent(set, component) { var self = this; var deferred = Q.defer(); if (IO_COMPONENTS[component]) { var name = IO_COMPONENTS[component].name; var ioMinPath = IO_COMPONENTS[component].minPath; var ioPath = IO_COMPONENTS[component].path; if (IO_COMPONENTS[component].config.length) { IO_COMPONENTS[component].config.forEach(function(item) { self.doesHaveKey(item.key).then(function(available) { if (!available) { self.writeIoConfig(item.key, item.value, true); } else if (!set) { self.writeIoConfig(item.key, item.value, false); } }); }); } fs.readFile(CONFIG_BACKUP, function(e, d) { var disable = false; if (d) { if (JSON.parse(d).disable_modifications) { disable = true; } } if (!disable) { fs.readFile(INDEX_FILE, function(err, data) { if (err) { log.error('ERROR: ', err); deferred.reject(new Error(err)); } else { var exists = false; var coreScript = false; var ionicBundle = false; var $ = cheerio.load(data); $('script').each(function() { if ($(this).attr('src') === 'lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js') { coreScript = this; // eslint-disable-line consistent-this } else if ($(this).attr('src') === 'lib/ionic/js/ionic.bundle.js') { ionicBundle = this; // eslint-disable-line consistent-this } if ($(this).attr('src') === 'cordova.js' && name === 'ionic.service.core' && set) { $(this).replaceWith('<!-- Cordova is bootstrapped by ionic-platform-web-client, ' + 'uncomment this if you remove ionic-platform-web-client... -->\n<!-- ' + $(this) + ' -->'); } else if (!set && $(this).attr('src') === ioPath) { log.info('Deleting component from index.html'); $(this).remove(); } else if (!set && $(this).attr('src') === ioMinPath) { log.info('Deleting component from index.html'); $(this).remove(); } else if (set && $(this).attr('src') === ioMinPath) { exists = true; } else if (set && $(this).attr('src') === ioPath) { exists = true; } }); if (set && !exists) { log.info('Adding component to index.html'); var newScript = "\n<script src='" + ioMinPath + "'></script>"; if (coreScript && name !== 'ionic.service.core') { $(coreScript).after(newScript); } else if (ionicBundle && name === 'ionic.service.core') { $(ionicBundle).after(newScript); } else { $('head').append(newScript); } } if (!set && name === 'ionic.service-deploy') { var nodes = $('head').contents(); for (var prop in nodes) { if (nodes.hasOwnProperty(prop) && nodes[prop].type === 'comment') { if (nodes[prop].data.indexOf('<script src="cordova.js"></script>') > -1) { $(nodes[prop]).replaceWith('<script src="cordova.js"></script>'); } } } } fs.writeFile(INDEX_FILE, $.html(), function(error) { if (err) { log.error('ERROR: ', error); deferred.reject(new Error(error)); } }); } }); fs.readFile(APP_FILE, function(err, data) { if (err) { log.error('ERROR: ', err); log.error("Is your app declaration contained in 'app.js'?"); deferred.reject(new Error(err)); } else { // Parse the file to string and remove existing references to the component var jsFile = String(data); jsFile = jsFile.replace("'" + name + "',", ''); jsFile = jsFile.replace('"' + name + '",', ''); if (set) { log.info('Injecting ' + name + ' into app.js'); if (name === 'ionic.service.core') { jsFile = jsFile.replace("'ionic',", "'ionic'," + "'" + name + "',"); jsFile = jsFile.replace('"ionic",', '"ionic",' + "'" + name + "',"); } else { jsFile = jsFile.replace("'ionic.service.core',", "'ionic.service.core'," + "'" + name + "',"); jsFile = jsFile.replace('"ionic.service.core",', '"ionic.service.core",' + "'" + name + "',"); } } else { log.info('Removing ' + name + ' from app.js'); } fs.writeFile(APP_FILE, jsFile, function(error) { if (err) { log.error('ERROR: ', error); deferred.reject(new Error(error)); } else { deferred.resolve(true); } }); } }); } else { log.warn('Automatic file manipulation disabled, please manually inject components.'); deferred.resolve(true); } }); } return deferred.promise; }; IoConfig.initIoPlatform = function initIoPlatform(appDirectory, jar) { log.info('Initializing app with ionic.io....'); var project = IonicProject.load(appDirectory); try { return IoConfig.dashInit(project, jar).then(function(key) { // Save App ID and API key to the io-config IoConfig.writeIoConfig('app_id', key.app_id, true).then(function() { if (key.api_key) { IoConfig.writeIoConfig('api_key', key.api_key, true).then(function() { IoConfig.warnMissingData(); }, function(error) { log.error('Error saving API key:', error); }); } }, function(error) { log.error('Error saving app ID:', error); }); // Set project vars project.set('app_id', key.app_id); project.save(); }) .catch(function(ex) { log.error('An error occurred initializing the app: %s', ex, {}); throw ex; }); } catch (ex) { log.error('Error initializing app: %s', ex, {}); } }; IoConfig.dashInit = function dashInit(project, jar) { var q = Q.defer(); log.debug('Getting app information from ', settings.IONIC_DASH); var csrftoken = Utils.retrieveCsrfToken(jar); request.post({ headers: { 'content-type' : 'application/json', cookie : jar.map(function(c) { return c.key + '=' + encodeURIComponent(c.value); }).join('; '), X_CSRFToken: csrftoken // eslint-disable-line camelcase }, url: settings.IONIC_DASH_API + 'app/init-io-app/' + project.get('app_id'), json: true, body: { name: project.get('name') } }, function(error, response) { if (error) { q.reject(error); } else { q.resolve(response.body); } }); return q.promise; };