diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-08-31 23:07:20 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-08-31 23:07:20 +0200 |
| commit | 22721a013bdd10d5eb395ba18453585f5f3f1f7f (patch) | |
| tree | 5a920e31d6026ed5dc55265e5fd057febccc50e3 /StoneIsland/platforms/ios/cordova | |
| parent | d22d51a1ae49680015326857360eb699f31efced (diff) | |
rebuild the ios platform and the plugins
Diffstat (limited to 'StoneIsland/platforms/ios/cordova')
46 files changed, 2112 insertions, 4630 deletions
diff --git a/StoneIsland/platforms/ios/cordova/Api.js b/StoneIsland/platforms/ios/cordova/Api.js index dd50d11f..a7b62b68 100755..100644 --- a/StoneIsland/platforms/ios/cordova/Api.js +++ b/StoneIsland/platforms/ios/cordova/Api.js @@ -19,17 +19,27 @@ /* jslint node: true */ -var fs = require('fs'); -var path = require('path'); -var unorm = require('unorm'); -var projectFile = require('./lib/projectFile'); -var check_reqs = require('./lib/check_reqs'); -var CordovaError = require('cordova-common').CordovaError; -var CordovaLogger = require('cordova-common').CordovaLogger; -var events = require('cordova-common').events; -var PluginManager = require('cordova-common').PluginManager; -var Q = require('q'); -var util = require('util'); +/** + * @todo update coho to update this line. + * @todo use `package.json` instead but first + * figure out how this fit in with the platform-centered workflow structure. + * This workflow would not have the `package.json` file. + */ +// Coho updates this line +const VERSION = '6.1.1'; + +const fs = require('fs-extra'); +const path = require('path'); +const unorm = require('unorm'); +const projectFile = require('./lib/projectFile'); +const check_reqs = require('./lib/check_reqs'); +const CordovaError = require('cordova-common').CordovaError; +const CordovaLogger = require('cordova-common').CordovaLogger; +const events = require('cordova-common').events; +const PluginManager = require('cordova-common').PluginManager; +const util = require('util'); +const xcode = require('xcode'); +const ConfigParser = require('cordova-common').ConfigParser; function setupEvents (externalEventEmitter) { if (externalEventEmitter) { @@ -42,6 +52,10 @@ function setupEvents (externalEventEmitter) { } } +function getVariableSpec (spec, options) { + return spec.includes('$') ? options.cli_variables[spec.replace('$', '')] : spec; +} + /** * Creates a new PlatformApi instance. * @@ -60,19 +74,28 @@ function Api (platform, platformRootDir, events) { setupEvents(events); - var xcodeProjDir; - var xcodeCordovaProj; + let xcodeProjDir; + let xcodeCordovaProj; try { - xcodeProjDir = fs.readdirSync(this.root).filter(function (e) { return e.match(/\.xcodeproj$/i); })[0]; + const xcodeProjDir_array = fs.readdirSync(this.root).filter(e => e.match(/\.xcodeproj$/i)); + if (xcodeProjDir_array.length > 1) { + for (let x = 0; x < xcodeProjDir_array.length; x++) { + if (xcodeProjDir_array[x].substring(0, 2) === '._') { + xcodeProjDir_array.splice(x, 1); + } + } + } + xcodeProjDir = xcodeProjDir_array[0]; + if (!xcodeProjDir) { - throw new CordovaError('The provided path "' + this.root + '" is not a Cordova iOS project.'); + throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`); } - var cordovaProjName = xcodeProjDir.substring(xcodeProjDir.lastIndexOf(path.sep) + 1, xcodeProjDir.indexOf('.xcodeproj')); + const cordovaProjName = xcodeProjDir.substring(xcodeProjDir.lastIndexOf(path.sep) + 1, xcodeProjDir.indexOf('.xcodeproj')); xcodeCordovaProj = path.join(this.root, cordovaProjName); } catch (e) { - throw new CordovaError('The provided path "' + this.root + '" is not a Cordova iOS project.'); + throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`); } this.locations = { @@ -83,11 +106,7 @@ function Api (platform, platformRootDir, events) { defaultConfigXml: path.join(this.root, 'cordova/defaults.xml'), pbxproj: path.join(this.root, xcodeProjDir, 'project.pbxproj'), xcodeProjDir: path.join(this.root, xcodeProjDir), - xcodeCordovaProj: xcodeCordovaProj, - // NOTE: this is required by browserify logic. - // As per platformApi spec we return relative to template root paths here - cordovaJs: 'bin/CordovaLib/cordova.js', - cordovaJsSrc: 'bin/cordova-js-src' + xcodeCordovaProj }; } @@ -95,7 +114,7 @@ function Api (platform, platformRootDir, events) { * Creates platform in a specified directory. * * @param {String} destination Destination directory, where install platform to - * @param {ConfigParser} [config] ConfgiParser instance, used to retrieve + * @param {ConfigParser} [config] ConfigParser instance, used to retrieve * project creation options, such as package id and project name. * @param {Object} [options] An options object. The most common options are: * @param {String} [options.customTemplate] A path to custom template, that @@ -109,26 +128,26 @@ function Api (platform, platformRootDir, events) { * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi * instance or rejected with CordovaError. */ -Api.createPlatform = function (destination, config, options, events) { +Api.createPlatform = (destination, config, options, events) => { setupEvents(events); // CB-6992 it is necessary to normalize characters // because node and shell scripts handles unicode symbols differently // We need to normalize the name to NFD form since iOS uses NFD unicode form - var name = unorm.nfd(config.name()); - var result; + const name = unorm.nfd(config.name()); + let result; try { result = require('../../../lib/create') - .createProject(destination, config.packageName(), name, options) - .then(function () { + .createProject(destination, config.getAttribute('ios-CFBundleIdentifier') || config.packageName(), name, options, config) + .then(() => { // after platform is created we return Api instance based on new Api.js location // This is required to correctly resolve paths in the future api calls - var PlatformApi = require(path.resolve(destination, 'cordova/Api')); + const PlatformApi = require(path.resolve(destination, 'cordova/Api')); return new PlatformApi('ios', destination, events); }); } catch (e) { events.emit('error', 'createPlatform is not callable from the iOS project API.'); - throw (e); + throw e; } return result; }; @@ -149,20 +168,20 @@ Api.createPlatform = function (destination, config, options, events) { * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi * instance or rejected with CordovaError. */ -Api.updatePlatform = function (destination, options, events) { +Api.updatePlatform = (destination, options, events) => { setupEvents(events); - var result; + let result; try { result = require('../../../lib/create') .updateProject(destination, options) - .then(function () { - var PlatformApi = require(path.resolve(destination, 'cordova/Api')); + .then(() => { + const PlatformApi = require(path.resolve(destination, 'cordova/Api')); return new PlatformApi('ios', destination, events); }); } catch (e) { events.emit('error', 'updatePlatform is not callable from the iOS project API, you will need to do this manually.'); - throw (e); + throw e; } return result; }; @@ -174,12 +193,12 @@ Api.updatePlatform = function (destination, options, events) { * platform's file structure and other properties of platform. */ Api.prototype.getPlatformInfo = function () { - var result = {}; + const result = {}; result.locations = this.locations; result.root = this.root; result.name = this.platform; - result.version = require('./version'); - result.projectConfig = this._config; + result.version = Api.version(); + result.projectConfig = new ConfigParser(this.locations.configXml); return result; }; @@ -199,6 +218,8 @@ Api.prototype.getPlatformInfo = function () { * CordovaError instance. */ Api.prototype.prepare = function (cordovaProject) { + cordovaProject.projectConfig = new ConfigParser(cordovaProject.locations.rootConfigXml || cordovaProject.projectConfig.path); + return require('./lib/prepare').prepare.call(this, cordovaProject); }; @@ -220,8 +241,7 @@ Api.prototype.prepare = function (cordovaProject) { * CordovaError instance. */ Api.prototype.addPlugin = function (plugin, installOptions) { - var xcodeproj = projectFile.parse(this.locations); - var self = this; + const xcodeproj = projectFile.parse(this.locations); installOptions = installOptions || {}; installOptions.variables = installOptions.variables || {}; @@ -230,70 +250,36 @@ Api.prototype.addPlugin = function (plugin, installOptions) { installOptions.variables.PACKAGE_NAME = xcodeproj.getPackageName(); } - return PluginManager.get(self.platform, self.locations, xcodeproj) + return PluginManager.get(this.platform, this.locations, xcodeproj) .addPlugin(plugin, installOptions) - .then(function () { - var frameworkTags = plugin.getFrameworks(self.platform); - var frameworkPods = frameworkTags.filter(function (obj) { - return (obj.type === 'podspec'); - }); - - return Q.resolve(frameworkPods); - }) - .then(function (frameworkPods) { - if (!(frameworkPods.length)) { - return Q.resolve(); - } - - var project_dir = self.locations.root; - var project_name = self.locations.xcodeCordovaProj.split('/').pop(); - - var Podfile = require('./lib/Podfile').Podfile; - var PodsJson = require('./lib/PodsJson').PodsJson; - - events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type="podspec"'); - - var podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME)); - var podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name); - - frameworkPods.forEach(function (obj) { - var podJson = { - name: obj.src, - type: obj.type, - spec: obj.spec - }; - - var val = podsjsonFile.get(podJson.name); - if (val) { // found - if (podJson.spec !== val.spec) { // exists, different spec, print warning - events.emit('warn', plugin.id + ' depends on ' + podJson.name + '@' + podJson.spec + ', which conflicts with another plugin. ' + podJson.name + '@' + val.spec + ' is already installed and was not overwritten.'); - } - // increment count, but don't add in Podfile because it already exists - podsjsonFile.increment(podJson.name); - } else { // not found, write new - podJson.count = 1; - podsjsonFile.setJson(podJson.name, podJson); - // add to Podfile - podfileFile.addSpec(podJson.name, podJson.spec); + .then(() => { + if (plugin != null) { + const headerTags = plugin.getHeaderFiles(this.platform); + const bridgingHeaders = headerTags.filter(obj => obj.type === 'BridgingHeader'); + if (bridgingHeaders.length > 0) { + const project_dir = this.locations.root; + const project_name = this.locations.xcodeCordovaProj.split('/').pop(); + const BridgingHeader = require('./lib/BridgingHeader').BridgingHeader; + const bridgingHeaderFile = new BridgingHeader(path.join(project_dir, project_name, 'Bridging-Header.h')); + events.emit('verbose', 'Adding Bridging-Headers since the plugin contained <header-file> with type="BridgingHeader"'); + bridgingHeaders.forEach(obj => { + const bridgingHeaderPath = path.basename(obj.src); + bridgingHeaderFile.addHeader(plugin.id, bridgingHeaderPath); + }); + bridgingHeaderFile.write(); } - }); - - // now that all the pods have been processed, write to pods.json - podsjsonFile.write(); - - // only write and pod install if the Podfile changed - if (podfileFile.isDirty()) { - podfileFile.write(); - events.emit('verbose', 'Running `pod install` (to install plugins)'); - - return podfileFile.install(check_reqs.check_cocoapods); - } else { - events.emit('verbose', 'Podfile unchanged, skipping `pod install`'); } }) - // CB-11022 return non-falsy value to indicate - // that there is no need to run prepare after - .thenResolve(true); + .then(() => { + if (plugin != null) { + const podSpecs = plugin.getPodSpecs ? plugin.getPodSpecs(this.platform) : []; + const frameworkTags = plugin.getFrameworks(this.platform); + const frameworkPods = frameworkTags.filter(obj => obj.type === 'podspec'); + return this.addPodSpecs(plugin, podSpecs, frameworkPods, installOptions); + } + }) + // CB-11022 Return truthy value to prevent running prepare after + .then(() => true); }; /** @@ -310,69 +296,321 @@ Api.prototype.addPlugin = function (plugin, installOptions) { * CordovaError instance. */ Api.prototype.removePlugin = function (plugin, uninstallOptions) { - var xcodeproj = projectFile.parse(this.locations); - var self = this; + const xcodeproj = projectFile.parse(this.locations); - return PluginManager.get(self.platform, self.locations, xcodeproj) + return PluginManager.get(this.platform, this.locations, xcodeproj) .removePlugin(plugin, uninstallOptions) - .then(function () { - var frameworkTags = plugin.getFrameworks(self.platform); - var frameworkPods = frameworkTags.filter(function (obj) { - return (obj.type === 'podspec'); + .then(() => { + if (plugin != null) { + const headerTags = plugin.getHeaderFiles(this.platform); + const bridgingHeaders = headerTags.filter(obj => obj.type === 'BridgingHeader'); + if (bridgingHeaders.length > 0) { + const project_dir = this.locations.root; + const project_name = this.locations.xcodeCordovaProj.split('/').pop(); + const BridgingHeader = require('./lib/BridgingHeader').BridgingHeader; + const bridgingHeaderFile = new BridgingHeader(path.join(project_dir, project_name, 'Bridging-Header.h')); + events.emit('verbose', 'Removing Bridging-Headers since the plugin contained <header-file> with type="BridgingHeader"'); + bridgingHeaders.forEach(obj => { + const bridgingHeaderPath = path.basename(obj.src); + bridgingHeaderFile.removeHeader(plugin.id, bridgingHeaderPath); + }); + bridgingHeaderFile.write(); + } + } + }) + .then(() => { + if (plugin != null) { + const podSpecs = plugin.getPodSpecs ? plugin.getPodSpecs(this.platform) : []; + const frameworkTags = plugin.getFrameworks(this.platform); + const frameworkPods = frameworkTags.filter(obj => obj.type === 'podspec'); + return this.removePodSpecs(plugin, podSpecs, frameworkPods, uninstallOptions); + } + }) + // CB-11022 Return truthy value to prevent running prepare after + .then(() => true); +}; + +/** + * adding CocoaPods libraries + * + * @param {PluginInfo} plugin A PluginInfo instance that represents plugin + * that will be installed. + * @param {Object} podSpecs: the return value of plugin.getPodSpecs(this.platform) + * @param {Object} frameworkPods: framework tags object with type === 'podspec' + * @return {Promise} Return a promise + */ + +Api.prototype.addPodSpecs = function (plugin, podSpecs, frameworkPods, installOptions) { + const project_dir = this.locations.root; + const project_name = this.locations.xcodeCordovaProj.split('/').pop(); + const minDeploymentTarget = this.getPlatformInfo().projectConfig.getPreference('deployment-target', 'ios'); + + const Podfile = require('./lib/Podfile').Podfile; + const PodsJson = require('./lib/PodsJson').PodsJson; + const podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME)); + const podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name, minDeploymentTarget); + + if (podSpecs.length) { + events.emit('verbose', 'Adding pods since the plugin contained <podspecs>'); + podSpecs.forEach(obj => { + // declarations + Object.keys(obj.declarations).forEach(key => { + if (obj.declarations[key] === 'true') { + const declaration = Podfile.proofDeclaration(key); + const podJson = { + declaration + }; + const val = podsjsonFile.getDeclaration(declaration); + if (val) { + podsjsonFile.incrementDeclaration(declaration); + } else { + podJson.count = 1; + podsjsonFile.setJsonDeclaration(declaration, podJson); + podfileFile.addDeclaration(podJson.declaration); + } + } }); + // sources + Object.keys(obj.sources).forEach(key => { + const podJson = { + source: obj.sources[key].source + }; + const val = podsjsonFile.getSource(key); + if (val) { + podsjsonFile.incrementSource(key); + } else { + podJson.count = 1; + podsjsonFile.setJsonSource(key, podJson); + podfileFile.addSource(podJson.source); + } + }); + // libraries + Object.keys(obj.libraries).forEach(key => { + const podJson = Object.assign({}, obj.libraries[key]); + if (podJson.spec) { + podJson.spec = getVariableSpec(podJson.spec, installOptions); + } + const val = podsjsonFile.getLibrary(key); + if (val) { + events.emit('warn', `${plugin.id} depends on ${podJson.name}, which may conflict with another plugin. ${podJson.name}@${val.spec} is already installed and was not overwritten.`); + podsjsonFile.incrementLibrary(key); + } else { + podJson.count = 1; + podsjsonFile.setJsonLibrary(key, podJson); + podfileFile.addSpec(podJson.name, podJson); + } + }); + }); + } - return Q.resolve(frameworkPods); - }) - .then(function (frameworkPods) { - if (!(frameworkPods.length)) { - return Q.resolve(); + if (frameworkPods.length) { + events.emit('warn', '"framework" tag with type "podspec" is deprecated and will be removed. Please use the "podspec" tag.'); + events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type="podspec"'); + frameworkPods.forEach(obj => { + const spec = getVariableSpec(obj.spec, installOptions); + const podJson = { + name: obj.src, + type: obj.type, + spec + }; + + const val = podsjsonFile.getLibrary(podJson.name); + if (val) { // found + if (podJson.spec !== val.spec) { // exists, different spec, print warning + events.emit('warn', `${plugin.id} depends on ${podJson.name}@${podJson.spec}, which conflicts with another plugin. ${podJson.name}@${val.spec} is already installed and was not overwritten.`); + } + // increment count, but don't add in Podfile because it already exists + podsjsonFile.incrementLibrary(podJson.name); + } else { // not found, write new + podJson.count = 1; + podsjsonFile.setJsonLibrary(podJson.name, podJson); + // add to Podfile + podfileFile.addSpec(podJson.name, podJson.spec); } + }); + } + + if (podSpecs.length > 0 || frameworkPods.length > 0) { + // now that all the pods have been processed, write to pods.json + podsjsonFile.write(); - var project_dir = self.locations.root; - var project_name = self.locations.xcodeCordovaProj.split('/').pop(); + // only write and pod install if the Podfile changed + if (podfileFile.isDirty()) { + podfileFile.write(); + events.emit('verbose', 'Running `pod install` (to install plugins)'); + projectFile.purgeProjectFileCache(this.locations.root); - var Podfile = require('./lib/Podfile').Podfile; - var PodsJson = require('./lib/PodsJson').PodsJson; + return podfileFile.install(check_reqs.check_cocoapods) + .then(() => this.setSwiftVersionForCocoaPodsLibraries(podsjsonFile)); + } else { + events.emit('verbose', 'Podfile unchanged, skipping `pod install`'); + } + } + return Promise.resolve(); +}; + +/** + * removing CocoaPods libraries + * + * @param {PluginInfo} plugin A PluginInfo instance that represents plugin + * that will be installed. + * @param {Object} podSpecs: the return value of plugin.getPodSpecs(this.platform) + * @param {Object} frameworkPods: framework tags object with type === 'podspec' + * @return {Promise} Return a promise + */ - events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type=\"podspec\"'); /* eslint no-useless-escape : 0 */ +Api.prototype.removePodSpecs = function (plugin, podSpecs, frameworkPods, uninstallOptions) { + const project_dir = this.locations.root; + const project_name = this.locations.xcodeCordovaProj.split('/').pop(); - var podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME)); - var podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name); + const Podfile = require('./lib/Podfile').Podfile; + const PodsJson = require('./lib/PodsJson').PodsJson; + const podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME)); + const podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name); - frameworkPods.forEach(function (obj) { - var podJson = { - name: obj.src, - type: obj.type, - spec: obj.spec + if (podSpecs.length) { + events.emit('verbose', 'Adding pods since the plugin contained <podspecs>'); + podSpecs.forEach(obj => { + // declarations + Object.keys(obj.declarations).forEach(key => { + if (obj.declarations[key] === 'true') { + const declaration = Podfile.proofDeclaration(key); + const podJson = { + declaration + }; + const val = podsjsonFile.getDeclaration(declaration); + if (val) { + podsjsonFile.decrementDeclaration(declaration); + } else { + const message = util.format('plugin \"%s\" declaration \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.declaration); /* eslint no-useless-escape : 0 */ + events.emit('verbose', message); + } + if (!val || val.count === 0) { + podfileFile.removeDeclaration(podJson.declaration); + } + } + }); + // sources + Object.keys(obj.sources).forEach(key => { + const podJson = { + source: obj.sources[key].source }; - - var val = podsjsonFile.get(podJson.name); - if (val) { // found, decrement count - podsjsonFile.decrement(podJson.name); - } else { // not found (perhaps a sync error) - var message = util.format('plugin \"%s\" podspec \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.name); /* eslint no-useless-escape : 0 */ + const val = podsjsonFile.getSource(key); + if (val) { + podsjsonFile.decrementSource(key); + } else { + const message = util.format('plugin \"%s\" source \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.source); /* eslint no-useless-escape : 0 */ events.emit('verbose', message); } - - // always remove from the Podfile - podfileFile.removeSpec(podJson.name); + if (!val || val.count === 0) { + podfileFile.removeSource(podJson.source); + } + }); + // libraries + Object.keys(obj.libraries).forEach(key => { + const podJson = Object.assign({}, obj.libraries[key]); + if (podJson.spec) { + podJson.spec = getVariableSpec(podJson.spec, uninstallOptions); + } + const val = podsjsonFile.getLibrary(key); + if (val) { + podsjsonFile.decrementLibrary(key); + } else { + const message = util.format('plugin \"%s\" podspec \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.name); /* eslint no-useless-escape : 0 */ + events.emit('verbose', message); + } + if (!val || val.count === 0) { + podfileFile.removeSpec(podJson.name); + } }); + }); + } + + if (frameworkPods.length) { + events.emit('warn', '"framework" tag with type "podspec" is deprecated and will be removed. Please use the "podspec" tag.'); + events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type=\"podspec\"'); /* eslint no-useless-escape : 0 */ + frameworkPods.forEach(obj => { + const spec = getVariableSpec(obj.spec, uninstallOptions); + const podJson = { + name: obj.src, + type: obj.type, + spec + }; + + const val = podsjsonFile.getLibrary(podJson.name); + if (val) { // found, decrement count + podsjsonFile.decrementLibrary(podJson.name); + } else { // not found (perhaps a sync error) + const message = util.format('plugin \"%s\" podspec \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.name); /* eslint no-useless-escape : 0 */ + events.emit('verbose', message); + } + + // always remove from the Podfile + podfileFile.removeSpec(podJson.name); + }); + } - // now that all the pods have been processed, write to pods.json - podsjsonFile.write(); + if (podSpecs.length > 0 || frameworkPods.length > 0) { + // now that all the pods have been processed, write to pods.json + podsjsonFile.write(); - if (podfileFile.isDirty()) { - podfileFile.write(); - events.emit('verbose', 'Running `pod install` (to uninstall pods)'); + if (podfileFile.isDirty()) { + podfileFile.write(); + events.emit('verbose', 'Running `pod install` (to uninstall pods)'); - return podfileFile.install(check_reqs.check_cocoapods); - } else { - events.emit('verbose', 'Podfile unchanged, skipping `pod install`'); + return podfileFile.install(check_reqs.check_cocoapods) + .then(() => this.setSwiftVersionForCocoaPodsLibraries(podsjsonFile)); + } else { + events.emit('verbose', 'Podfile unchanged, skipping `pod install`'); + } + } + return Promise.resolve(); +}; + +/** + * set Swift Version for all CocoaPods libraries + * + * @param {PodsJson} podsjsonFile A PodsJson instance that represents pods.json + */ + +Api.prototype.setSwiftVersionForCocoaPodsLibraries = function (podsjsonFile) { + let __dirty = false; + return check_reqs.check_cocoapods().then(toolOptions => { + if (toolOptions.ignore) { + events.emit('verbose', '=== skip Swift Version Settings For Cocoapods Libraries'); + } else { + const podPbxPath = path.join(this.root, 'Pods', 'Pods.xcodeproj', 'project.pbxproj'); + const podXcodeproj = xcode.project(podPbxPath); + podXcodeproj.parseSync(); + const podTargets = podXcodeproj.pbxNativeTargetSection(); + const podConfigurationList = podXcodeproj.pbxXCConfigurationList(); + const podConfigs = podXcodeproj.pbxXCBuildConfigurationSection(); + + const libraries = podsjsonFile.getLibraries(); + Object.keys(libraries).forEach(key => { + const podJson = libraries[key]; + const name = podJson.name; + const swiftVersion = podJson['swift-version']; + if (swiftVersion) { + __dirty = true; + Object.keys(podTargets) + .filter(targetKey => podTargets[targetKey].productName === name) + .map(targetKey => podTargets[targetKey].buildConfigurationList) + .map(buildConfigurationListId => podConfigurationList[buildConfigurationListId]) + .map(buildConfigurationList => buildConfigurationList.buildConfigurations) + .reduce((acc, buildConfigurations) => acc.concat(buildConfigurations), []) + .map(buildConfiguration => buildConfiguration.value) + .forEach(buildId => { + __dirty = true; + podConfigs[buildId].buildSettings.SWIFT_VERSION = swiftVersion; + }); + } + }); + if (__dirty) { + fs.writeFileSync(podPbxPath, podXcodeproj.writeSync(), 'utf-8'); } - }) - // CB-11022 return non-falsy value to indicate - // that there is no need to run prepare after - .thenResolve(true); + } + }); }; /** @@ -408,11 +646,8 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { * CordovaError instance. */ Api.prototype.build = function (buildOptions) { - var self = this; return check_reqs.run() - .then(function () { - return require('./lib/build').run.call(self, buildOptions); - }); + .then(() => require('./lib/build').run.call(this, buildOptions)); }; /** @@ -428,11 +663,8 @@ Api.prototype.build = function (buildOptions) { * successfully, or rejected with CordovaError. */ Api.prototype.run = function (runOptions) { - var self = this; return check_reqs.run() - .then(function () { - return require('./lib/run').run.call(self, runOptions); - }); + .then(() => require('./lib/run').run.call(this, runOptions)); }; /** @@ -442,14 +674,9 @@ Api.prototype.run = function (runOptions) { * CordovaError. */ Api.prototype.clean = function (cleanOptions) { - var self = this; return check_reqs.run() - .then(function () { - return require('./lib/clean').run.call(self, cleanOptions); - }) - .then(function () { - return require('./lib/prepare').clean.call(self, cleanOptions); - }); + .then(() => require('./lib/clean').run.call(this, cleanOptions)) + .then(() => require('./lib/prepare').clean.call(this, cleanOptions)); }; /** @@ -464,4 +691,8 @@ Api.prototype.requirements = function () { return check_reqs.check_all(); }; +Api.version = function () { + return VERSION; +}; + module.exports = Api; diff --git a/StoneIsland/platforms/ios/cordova/apple_ios_version b/StoneIsland/platforms/ios/cordova/apple_ios_version index d397bb6b..5fee9e85 100755 --- a/StoneIsland/platforms/ios/cordova/apple_ios_version +++ b/StoneIsland/platforms/ios/cordova/apple_ios_version @@ -21,7 +21,7 @@ var versions = require('./lib/versions.js'); -versions.get_apple_ios_version().done(null, function(err) { +versions.get_apple_ios_version().catch(err => { console.log(err); process.exit(2); }); diff --git a/StoneIsland/platforms/ios/cordova/apple_osx_version b/StoneIsland/platforms/ios/cordova/apple_osx_version index 6e697add..062d8b7f 100755 --- a/StoneIsland/platforms/ios/cordova/apple_osx_version +++ b/StoneIsland/platforms/ios/cordova/apple_osx_version @@ -21,7 +21,7 @@ var versions = require('./lib/versions.js'); -versions.get_apple_osx_version().done(null, function(err) { +versions.get_apple_osx_version().catch(err => { console.log(err); process.exit(2); }); diff --git a/StoneIsland/platforms/ios/cordova/apple_xcode_version b/StoneIsland/platforms/ios/cordova/apple_xcode_version index 112eba32..4656e385 100755 --- a/StoneIsland/platforms/ios/cordova/apple_xcode_version +++ b/StoneIsland/platforms/ios/cordova/apple_xcode_version @@ -21,9 +21,12 @@ var versions = require('./lib/versions.js'); -versions.get_apple_xcode_version().done(function (version) { - console.log(version); -}, function(err) { - console.error(err); - process.exit(2); -}); +versions.get_apple_xcode_version().then( + version => { + console.log(version); + }, + err => { + console.error(err); + process.exit(2); + } +); diff --git a/StoneIsland/platforms/ios/cordova/build b/StoneIsland/platforms/ios/cordova/build index 61d26cca..f4b0d9a0 100755 --- a/StoneIsland/platforms/ios/cordova/build +++ b/StoneIsland/platforms/ios/cordova/build @@ -19,45 +19,48 @@ under the License. */ -var args = process.argv; +var args = process.argv; var Api = require('./Api'); var nopt = require('nopt'); -var path = require('path'); // Support basic help commands -if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { +if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { require('./lib/build').help(); process.exit(0); } // Parse arguments var buildOpts = nopt({ - 'verbose' : Boolean, - 'silent' : Boolean, - 'archs': String, - 'debug': Boolean, - 'release': Boolean, - 'device': Boolean, - 'emulator': Boolean, - 'codeSignIdentity': String, - 'codeSignResourceRules': String, - 'provisioningProfile': String, - 'developmentTeam': String, - 'packageType': String, - 'buildConfig' : String, - 'buildFlag' : [String, Array], - 'noSign' : Boolean -}, { '-r': '--release', 'd' : '--verbose' }, args); + verbose: Boolean, + silent: Boolean, + archs: String, + debug: Boolean, + release: Boolean, + device: Boolean, + emulator: Boolean, + codeSignIdentity: String, + codeSignResourceRules: String, + provisioningProfile: String, + automaticProvisioning: Boolean, + developmentTeam: String, + packageType: String, + buildConfig: String, + buildFlag: [String, Array], + noSign: Boolean +}, { '-r': '--release', d: '--verbose' }, args); // Make buildOptions compatible with PlatformApi build method spec buildOpts.argv = buildOpts.argv.remain; require('./loggingHelper').adjustLoggerLevel(buildOpts); -new Api().build(buildOpts).done(function() { +new Api().build(buildOpts).then( + () => { console.log('** BUILD SUCCEEDED **'); - }, function(err) { + }, + err => { var errorMessage = (err && err.stack) ? err.stack : err; console.error(errorMessage); process.exit(2); - }); + } +); diff --git a/StoneIsland/platforms/ios/cordova/build-debug.xcconfig b/StoneIsland/platforms/ios/cordova/build-debug.xcconfig index 3f4767d2..7e7985bb 100755..100644 --- a/StoneIsland/platforms/ios/cordova/build-debug.xcconfig +++ b/StoneIsland/platforms/ios/cordova/build-debug.xcconfig @@ -23,7 +23,7 @@ #include "build.xcconfig" -GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 #include "build-extras.xcconfig" diff --git a/StoneIsland/platforms/ios/cordova/build-extras.xcconfig b/StoneIsland/platforms/ios/cordova/build-extras.xcconfig index e69de29b..e69de29b 100755..100644 --- a/StoneIsland/platforms/ios/cordova/build-extras.xcconfig +++ b/StoneIsland/platforms/ios/cordova/build-extras.xcconfig diff --git a/StoneIsland/platforms/ios/cordova/build-release.xcconfig b/StoneIsland/platforms/ios/cordova/build-release.xcconfig index 70b0f073..70b0f073 100755..100644 --- a/StoneIsland/platforms/ios/cordova/build-release.xcconfig +++ b/StoneIsland/platforms/ios/cordova/build-release.xcconfig diff --git a/StoneIsland/platforms/ios/cordova/build.xcconfig b/StoneIsland/platforms/ios/cordova/build.xcconfig index cc78c73e..3c8b9307 100755..100644 --- a/StoneIsland/platforms/ios/cordova/build.xcconfig +++ b/StoneIsland/platforms/ios/cordova/build.xcconfig @@ -36,8 +36,10 @@ ENABLE_BITCODE = NO // (CB-9719) Set CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES to YES in build.xcconfig CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES -// (CB-10072) +// (CB-10072) SWIFT_OBJC_BRIDGING_HEADER = $(PROJECT_DIR)/$(PROJECT_NAME)/Bridging-Header.h // (CB-11854) CODE_SIGN_ENTITLEMENTS = $(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-$(CONFIGURATION).plist + +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) WK_WEB_VIEW_ONLY=$(WK_WEB_VIEW_ONLY) diff --git a/StoneIsland/platforms/ios/cordova/check_reqs b/StoneIsland/platforms/ios/cordova/check_reqs index d101ccd1..e46db6c8 100755 --- a/StoneIsland/platforms/ios/cordova/check_reqs +++ b/StoneIsland/platforms/ios/cordova/check_reqs @@ -25,8 +25,8 @@ var check_reqs = require('./lib/check_reqs'); if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) > -1) { console.log('Usage: check_reqs or node check_reqs'); } else { - check_reqs.run().done(null, function (err) { - console.error('Failed to check requirements due to ' + err); - process.exit(2); - }); + check_reqs.run().catch(err => { + console.error('Failed to check requirements due to ' + err); + process.exit(2); + }); } diff --git a/StoneIsland/platforms/ios/cordova/clean b/StoneIsland/platforms/ios/cordova/clean index 56665c48..f36a648e 100755 --- a/StoneIsland/platforms/ios/cordova/clean +++ b/StoneIsland/platforms/ios/cordova/clean @@ -20,19 +20,18 @@ */ var Api = require('./Api'); -var path = require('path'); var nopt = require('nopt'); -if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { +if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { console.log('Cleans the project directory.'); process.exit(0); } // Do some basic argument parsing var opts = nopt({ - 'verbose' : Boolean, - 'silent' : Boolean -}, { 'd' : '--verbose' }); + verbose: Boolean, + silent: Boolean +}, { d: '--verbose' }); // Make buildOptions compatible with PlatformApi clean method spec opts.argv = opts.argv.original; @@ -42,9 +41,12 @@ opts.noPrepare = true; require('./loggingHelper').adjustLoggerLevel(opts); -new Api().clean(opts).done(function() { - console.log('** CLEAN SUCCEEDED **'); -}, function(err) { - console.error(err); - process.exit(2); -}); +new Api().clean(opts).then( + () => { + console.log('** CLEAN SUCCEEDED **'); + }, + err => { + console.error(err); + process.exit(2); + } +); diff --git a/StoneIsland/platforms/ios/cordova/defaults.xml b/StoneIsland/platforms/ios/cordova/defaults.xml index 77a0a0b3..8733ce39 100755..100644 --- a/StoneIsland/platforms/ios/cordova/defaults.xml +++ b/StoneIsland/platforms/ios/cordova/defaults.xml @@ -27,7 +27,7 @@ <preference name="DisallowOverscroll" value="false" /> <preference name="EnableViewportScale" value="false" /> <preference name="KeyboardDisplayRequiresUserAction" value="true" /> - <preference name="MediaPlaybackRequiresUserAction" value="false" /> + <preference name="MediaTypesRequiringUserActionForPlayback" value="none" /> <preference name="SuppressesIncrementalRendering" value="false" /> <preference name="SuppressesLongPressGesture" value="false" /> <preference name="Suppresses3DTouchGesture" value="false" /> @@ -36,6 +36,12 @@ <preference name="PaginationBreakingMode" value="page" /> <!-- page, column --> <preference name="PaginationMode" value="unpaginated" /> <!-- unpaginated, leftToRight, topToBottom, bottomToTop, rightToLeft --> + <feature name="CDVWebViewEngine"> + <param name="ios-package" value="CDVWebViewEngine" /> + </feature> + <feature name="LaunchScreen"> + <param name="ios-package" value="CDVLaunchScreen"/> + </feature> <feature name="LocalStorage"> <param name="ios-package" value="CDVLocalStorage"/> </feature> diff --git a/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js b/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js new file mode 100644 index 00000000..9e200b50 --- /dev/null +++ b/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js @@ -0,0 +1,123 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ +'use strict'; + +const fs = require('fs-extra'); +const CordovaError = require('cordova-common').CordovaError; + +function BridgingHeader (bridgingHeaderPath) { + this.path = bridgingHeaderPath; + this.bridgingHeaders = null; + if (!fs.existsSync(this.path)) { + throw new CordovaError('BridgingHeader.h is not found.'); + } + this.bridgingHeaders = this.__parseForBridgingHeader(fs.readFileSync(this.path, 'utf8')); +} + +BridgingHeader.prototype.addHeader = function (plugin_id, header_path) { + this.bridgingHeaders.push({ type: 'code', code: `#import "${header_path}"\n` }); +}; + +BridgingHeader.prototype.removeHeader = function (plugin_id, header_path) { + this.bridgingHeaders = this.bridgingHeaders.filter(function (line) { + if (this.found) { + return true; + } + if (line.type === 'code') { + const re = new RegExp(`#import\\s+"${preg_quote(header_path)}"(\\s*|\\s.+)(\\n|$)`); + if (re.test(line.code)) { + this.found = true; + return false; + } + } + return true; + }, { found: false }); +}; + +BridgingHeader.prototype.write = function () { + const text = this.__stringifyForBridgingHeader(this.bridgingHeaders); + fs.writeFileSync(this.path, text, 'utf8'); +}; + +BridgingHeader.prototype.__stringifyForBridgingHeader = function (bridgingHeaders) { + return bridgingHeaders.map(obj => obj.code).join(''); +}; + +BridgingHeader.prototype.__parseForBridgingHeader = function (text) { + let i = 0; + const list = []; + let type = 'code'; + let start = 0; + while (i < text.length) { + switch (type) { + case 'comment': + if (i + 1 < text.length && text[i] === '*' && text[i + 1] === '/') { + i += 2; + list.push({ type, code: text.slice(start, i) }); + type = 'code'; + start = i; + } else { + i += 1; + } + break; + case 'line-comment': + if (i < text.length && text[i] === '\n') { + i += 1; + list.push({ type, code: text.slice(start, i) }); + type = 'code'; + start = i; + } else { + i += 1; + } + break; + case 'code': + default: + if (i + 1 < text.length && text[i] === '/' && text[i + 1] === '*') { // comment + if (start < i) { + list.push({ type, code: text.slice(start, i) }); + } + type = 'comment'; + start = i; + } else if (i + 1 < text.length && text[i] === '/' && text[i + 1] === '/') { // line comment + if (start < i) { + list.push({ type, code: text.slice(start, i) }); + } + type = 'line-comment'; + start = i; + } else if (i < text.length && text[i] === '\n') { + i += 1; + list.push({ type, code: text.slice(start, i) }); + start = i; + } else { + i += 1; + } + break; + } + } + if (start < i) { + list.push({ type, code: text.slice(start, i) }); + } + return list; +}; + +function preg_quote (str, delimiter) { + return (`${str}`).replace(new RegExp(`[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\${delimiter || ''}-]`, 'g'), '\\$&'); +} + +module.exports.BridgingHeader = BridgingHeader; diff --git a/StoneIsland/platforms/ios/cordova/lib/Podfile.js b/StoneIsland/platforms/ios/cordova/lib/Podfile.js index 49173c4c..f1672974 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/Podfile.js +++ b/StoneIsland/platforms/ios/cordova/lib/Podfile.js @@ -18,27 +18,37 @@ */ 'use strict'; -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var events = require('cordova-common').events; -var Q = require('q'); -var superspawn = require('cordova-common').superspawn; -var CordovaError = require('cordova-common').CordovaError; +const fs = require('fs-extra'); +const path = require('path'); +const util = require('util'); +const { + CordovaError, + events, + superspawn: { spawn } +} = require('cordova-common'); Podfile.FILENAME = 'Podfile'; +Podfile.declarationRegexpMap = { + 'use_frameworks!': 'use[-_]frameworks!?', + 'inhibit_all_warnings!': 'inhibit[-_]all[-_]warnings!?' +}; -function Podfile (podFilePath, projectName) { +function Podfile (podFilePath, projectName, minDeploymentTarget) { + this.declarationToken = '##INSERT_DECLARATION##'; + this.sourceToken = '##INSERT_SOURCE##'; this.podToken = '##INSERT_POD##'; this.path = podFilePath; this.projectName = projectName; + this.minDeploymentTarget = minDeploymentTarget || '11.0'; this.contents = null; + this.sources = null; + this.declarations = null; this.pods = null; this.__dirty = false; // check whether it is named Podfile - var filename = this.path.split(path.sep).pop(); + const filename = this.path.split(path.sep).pop(); if (filename !== Podfile.FILENAME) { throw new CordovaError(util.format('Podfile: The file at %s is not `%s`.', this.path, Podfile.FILENAME)); } @@ -55,33 +65,101 @@ function Podfile (podFilePath, projectName) { } else { events.emit('verbose', 'Podfile found in platforms/ios'); // parse for pods - this.pods = this.__parseForPods(fs.readFileSync(this.path, 'utf8')); + const fileText = fs.readFileSync(this.path, 'utf8'); + this.declarations = this.__parseForDeclarations(fileText); + this.sources = this.__parseForSources(fileText); + this.pods = this.__parseForPods(fileText); } } +Podfile.prototype.__parseForDeclarations = function (text) { + // split by \n + const arr = text.split('\n'); + + // getting lines between "platform :ios, '11.0'"" and "target 'HelloCordova'" do + const declarationsPreRE = new RegExp('platform :ios,\\s+\'[^\']+\''); + const declarationsPostRE = new RegExp('target\\s+\'[^\']+\'\\s+do'); + const declarationRE = new RegExp('^\\s*[^#]'); + + return arr.reduce((acc, line) => { + switch (acc.state) { + case 0: + if (declarationsPreRE.exec(line)) { + acc.state = 1; // Start to read + } + break; + case 1: + if (declarationsPostRE.exec(line)) { + acc.state = 2; // Finish to read + } else { + acc.lines.push(line); + } + break; + case 2: + default: + // do nothing; + } + return acc; + }, { state: 0, lines: [] }) + .lines + .filter(line => declarationRE.exec(line)) + .reduce((obj, line) => { + obj[line] = line; + return obj; + }, {}); +}; + +Podfile.prototype.__parseForSources = function (text) { + // split by \n + const arr = text.split('\n'); + + const sourceRE = new RegExp('source \'(.*)\''); + return arr.filter(line => { + const m = sourceRE.exec(line); + + return (m !== null); + }) + .reduce((obj, line) => { + const m = sourceRE.exec(line); + if (m !== null) { + const source = m[1]; + obj[source] = source; + } + return obj; + }, {}); +}; + Podfile.prototype.__parseForPods = function (text) { // split by \n - var arr = text.split('\n'); + const arr = text.split('\n'); // aim is to match (space insignificant around the comma, comma optional): // pod 'Foobar', '1.2' // pod 'Foobar', 'abc 123 1.2' // pod 'PonyDebugger', :configurations => ['Debug', 'Beta'] - var podRE = new RegExp('pod \'([^\']*)\'\\s*,?\\s*(.*)'); + // var podRE = new RegExp('pod \'([^\']*)\'\\s*,?\\s*(.*)'); + const podRE = new RegExp('pod \'([^\']*)\'\\s*(?:,\\s*\'([^\']*)\'\\s*)?,?\\s*(.*)'); // only grab lines that don't have the pod spec' - return arr.filter(function (line) { - var m = podRE.exec(line); + return arr.filter(line => { + const m = podRE.exec(line); return (m !== null); }) - .reduce(function (obj, line) { - var m = podRE.exec(line); + .reduce((obj, line) => { + const m = podRE.exec(line); if (m !== null) { - // strip out any single quotes around the value m[2] - var podSpec = m[2].replace(/^\'|\'$/g, ''); /* eslint no-useless-escape : 0 */ - obj[m[1]] = podSpec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'} + const podspec = { + name: m[1] + }; + if (m[2]) { + podspec.spec = m[2]; + } + if (m[3]) { + podspec.options = m[3]; + } + obj[m[1]] = podspec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'} } return obj; @@ -89,20 +167,22 @@ Podfile.prototype.__parseForPods = function (text) { }; Podfile.prototype.escapeSingleQuotes = function (string) { - return string.replace('\'', '\\\''); + return string.replace(/'/g, '\\\''); }; Podfile.prototype.getTemplate = function () { // Escaping possible ' in the project name - var projectName = this.escapeSingleQuotes(this.projectName); + const projectName = this.escapeSingleQuotes(this.projectName); return util.format( '# DO NOT MODIFY -- auto-generated by Apache Cordova\n' + - 'platform :ios, \'8.0\'\n' + + '%s\n' + + 'platform :ios, \'%s\'\n' + + '%s\n' + 'target \'%s\' do\n' + '\tproject \'%s.xcodeproj\'\n' + '%s\n' + 'end\n', - projectName, projectName, this.podToken); + this.sourceToken, this.minDeploymentTarget, this.declarationToken, projectName, projectName, this.podToken); }; Podfile.prototype.addSpec = function (name, spec) { @@ -114,6 +194,14 @@ Podfile.prototype.addSpec = function (name, spec) { throw new CordovaError('Podfile addSpec: name is not specified.'); } + if (typeof spec === 'string') { + if (spec.startsWith(':')) { + spec = { name, options: spec }; + } else { + spec = { name, spec }; + } + } + this.pods[name] = spec; this.__dirty = true; @@ -137,7 +225,60 @@ Podfile.prototype.existsSpec = function (name) { return (name in this.pods); }; +Podfile.prototype.addSource = function (src) { + this.sources[src] = src; + this.__dirty = true; + + events.emit('verbose', util.format('Added source line for `%s`', src)); +}; + +Podfile.prototype.removeSource = function (src) { + if (this.existsSource(src)) { + delete this.sources[src]; + this.__dirty = true; + } + + events.emit('verbose', util.format('Removed source line for `%s`', src)); +}; + +Podfile.prototype.existsSource = function (src) { + return (src in this.sources); +}; + +Podfile.prototype.addDeclaration = function (declaration) { + this.declarations[declaration] = declaration; + this.__dirty = true; + + events.emit('verbose', util.format('Added declaration line for `%s`', declaration)); +}; + +Podfile.prototype.removeDeclaration = function (declaration) { + if (this.existsDeclaration(declaration)) { + delete this.declarations[declaration]; + this.__dirty = true; + } + + events.emit('verbose', util.format('Removed source line for `%s`', declaration)); +}; + +Podfile.proofDeclaration = declaration => { + const list = Object.keys(Podfile.declarationRegexpMap).filter(key => { + const regexp = new RegExp(Podfile.declarationRegexpMap[key]); + return regexp.test(declaration); + }); + if (list.length > 0) { + return list[0]; + } + return declaration; +}; + +Podfile.prototype.existsDeclaration = function (declaration) { + return (declaration in this.declarations); +}; + Podfile.prototype.clear = function () { + this.sources = {}; + this.declarations = {}; this.pods = {}; this.__dirty = true; }; @@ -148,28 +289,65 @@ Podfile.prototype.destroy = function () { }; Podfile.prototype.write = function () { - var text = this.getTemplate(); - var self = this; + let text = this.getTemplate(); - var podsString = - Object.keys(this.pods).map(function (key) { - var name = key; - var spec = self.pods[key]; + const podsString = + Object.keys(this.pods).map(key => { + const name = key; + const json = this.pods[key]; - if (spec.length) { - if (spec.indexOf(':') === 0) { - // don't quote it, it's a specification (starts with ':') - return util.format('\tpod \'%s\', %s', name, spec); + if (typeof json === 'string') { // compatibility for using framework tag. + const spec = json; + if (spec.length) { + if (spec.indexOf(':') === 0) { + // don't quote it, it's a specification (starts with ':') + return util.format('\tpod \'%s\', %s', name, spec); + } else { + // quote it, it's a version + return util.format('\tpod \'%s\', \'%s\'', name, spec); + } } else { - // quote it, it's a version - return util.format('\tpod \'%s\', \'%s\'', name, spec); + return util.format('\tpod \'%s\'', name); } } else { - return util.format('\tpod \'%s\'', name); + const list = [`'${name}'`]; + if ('spec' in json && json.spec.length) { + list.push(`'${json.spec}'`); + } + + let options = ['tag', 'branch', 'commit', 'git', 'podspec'] + .filter(tag => tag in json) + .map(tag => `:${tag} => '${json[tag]}'`); + + if ('configurations' in json) { + options.push(`:configurations => [${json.configurations.split(',').map(conf => `'${conf.trim()}'`).join(',')}]`); + } + if ('options' in json) { + options = [json.options]; + } + if (options.length > 0) { + list.push(options.join(', ')); + } + return util.format('\tpod %s', list.join(', ')); } }).join('\n'); - text = text.replace(this.podToken, podsString); + const sourcesString = + Object.keys(this.sources).map(key => { + const source = this.sources[key]; + return util.format('source \'%s\'', source); + }).join('\n'); + + const declarationString = + Object.keys(this.declarations).map(key => { + const declaration = this.declarations[key]; + return declaration; + }).join('\n'); + + text = text.replace(this.podToken, podsString) + .replace(this.sourceToken, sourcesString) + .replace(this.declarationToken, declarationString); + fs.writeFileSync(this.path, text, 'utf8'); this.__dirty = false; @@ -184,45 +362,43 @@ Podfile.prototype.before_install = function (toolOptions) { toolOptions = toolOptions || {}; // Template tokens in order: project name, project name, debug | release - var template = + const template = '// DO NOT MODIFY -- auto-generated by Apache Cordova\n' + '#include "Pods/Target Support Files/Pods-%s/Pods-%s.%s.xcconfig"'; - var debugContents = util.format(template, this.projectName, this.projectName, 'debug'); - var releaseContents = util.format(template, this.projectName, this.projectName, 'release'); + const debugContents = util.format(template, this.projectName, this.projectName, 'debug'); + const releaseContents = util.format(template, this.projectName, this.projectName, 'release'); - var debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig'); - var releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig'); + const debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig'); + const releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig'); fs.writeFileSync(debugConfigPath, debugContents, 'utf8'); fs.writeFileSync(releaseConfigPath, releaseContents, 'utf8'); - return Q.resolve(toolOptions); + return Promise.resolve(toolOptions); }; Podfile.prototype.install = function (requirementsCheckerFunction) { - var opts = {}; + const opts = {}; opts.cwd = path.join(this.path, '..'); // parent path of this Podfile opts.stdio = 'pipe'; - var first = true; - var self = this; + opts.printCommand = true; + let first = true; if (!requirementsCheckerFunction) { - requirementsCheckerFunction = Q(); + requirementsCheckerFunction = Promise.resolve(); } return requirementsCheckerFunction() - .then(function (toolOptions) { - return self.before_install(toolOptions); - }) - .then(function (toolOptions) { + .then(toolOptions => this.before_install(toolOptions)) + .then(toolOptions => { if (toolOptions.ignore) { events.emit('verbose', '==== pod install start ====\n'); events.emit('verbose', toolOptions.ignoreMessage); - return Q.resolve(); + return Promise.resolve(); } else { - return superspawn.spawn('pod', ['install', '--verbose'], opts) - .progress(function (stdio) { + return spawn('pod', ['install', '--verbose'], opts) + .progress(stdio => { if (stdio.stderr) { console.error(stdio.stderr); } if (stdio.stdout) { if (first) { @@ -234,11 +410,8 @@ Podfile.prototype.install = function (requirementsCheckerFunction) { }); } }) - .then(function () { // done + .then(() => { // done events.emit('verbose', '==== pod install end ====\n'); - }) - .fail(function (error) { - throw error; }); }; diff --git a/StoneIsland/platforms/ios/cordova/lib/PodsJson.js b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js index 04705273..598d9607 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/PodsJson.js +++ b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js @@ -17,20 +17,23 @@ under the License. */ -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var events = require('cordova-common').events; -var CordovaError = require('cordova-common').CordovaError; +const fs = require('fs-extra'); +const path = require('path'); +const util = require('util'); +const events = require('cordova-common').events; +const CordovaError = require('cordova-common').CordovaError; PodsJson.FILENAME = 'pods.json'; +PodsJson.LIBRARY = 'libraries'; +PodsJson.SOURCE = 'sources'; +PodsJson.DECLARATION = 'declarations'; function PodsJson (podsJsonPath) { this.path = podsJsonPath; this.contents = null; this.__dirty = false; - var filename = this.path.split(path.sep).pop(); + const filename = this.path.split(path.sep).pop(); if (filename !== PodsJson.FILENAME) { throw new CordovaError(util.format('PodsJson: The file at %s is not `%s`.', this.path, PodsJson.FILENAME)); } @@ -43,25 +46,81 @@ function PodsJson (podsJsonPath) { } else { events.emit('verbose', 'pods.json found in platforms/ios'); // load contents - this.contents = fs.readFileSync(this.path, 'utf8'); - this.contents = JSON.parse(this.contents); + const contents = fs.readFileSync(this.path, 'utf8'); + this.contents = JSON.parse(contents); } + this.__updateFormatIfNecessary(); } -PodsJson.prototype.get = function (name) { - return this.contents[name]; +PodsJson.prototype.__isOldFormat = function () { + if (this.contents !== null) { + if (this.contents.declarations === undefined || + this.contents.sources === undefined || + this.contents.libraries === undefined) { + return true; + } + } + return false; }; -PodsJson.prototype.remove = function (name) { - if (this.contents[name]) { - delete this.contents[name]; +PodsJson.prototype.__updateFormatIfNecessary = function () { + if (this.__isOldFormat()) { + this.contents = { + declarations: {}, + sources: {}, + libraries: this.contents + }; this.__dirty = true; - events.emit('verbose', util.format('Remove from pods.json for `%s`', name)); + events.emit('verbose', 'Update format of pods.json'); } }; +PodsJson.prototype.getLibraries = function () { + return this.contents[PodsJson.LIBRARY]; +}; + +PodsJson.prototype.__get = function (kind, name) { + return this.contents[kind][name]; +}; + +PodsJson.prototype.getLibrary = function (name) { + return this.__get(PodsJson.LIBRARY, name); +}; + +PodsJson.prototype.getSource = function (name) { + return this.__get(PodsJson.SOURCE, name); +}; + +PodsJson.prototype.getDeclaration = function (name) { + return this.__get(PodsJson.DECLARATION, name); +}; + +PodsJson.prototype.__remove = function (kind, name) { + if (this.contents[kind][name]) { + delete this.contents[kind][name]; + this.__dirty = true; + events.emit('verbose', util.format('Remove from pods.json for `%s` - `%s`', name)); + } +}; + +PodsJson.prototype.removeLibrary = function (name) { + this.__remove(PodsJson.LIBRARY, name); +}; + +PodsJson.prototype.removeSource = function (name) { + this.__remove(PodsJson.SOURCE, name); +}; + +PodsJson.prototype.removeDeclaration = function (name) { + this.__remove(PodsJson.DECLARATION, name); +}; + PodsJson.prototype.clear = function () { - this.contents = {}; + this.contents = { + declarations: {}, + sources: {}, + libraries: {} + }; this.__dirty = true; }; @@ -78,34 +137,69 @@ PodsJson.prototype.write = function () { } }; -PodsJson.prototype.set = function (name, type, spec, count) { - this.setJson(name, { name: name, type: type, spec: spec, count: count }); -}; - -PodsJson.prototype.increment = function (name) { - var val = this.get(name); +PodsJson.prototype.__increment = function (kind, name) { + const val = this.__get(kind, name); if (val) { val.count++; - this.setJson(val); } }; -PodsJson.prototype.decrement = function (name) { - var val = this.get(name); +PodsJson.prototype.incrementLibrary = function (name) { + this.__increment(PodsJson.LIBRARY, name); +}; + +PodsJson.prototype.incrementSource = function (name) { + this.__increment(PodsJson.SOURCE, name); +}; + +PodsJson.prototype.incrementDeclaration = function (name) { + this.__increment(PodsJson.DECLARATION, name); +}; + +PodsJson.prototype.__decrement = function (kind, name) { + const val = this.__get(kind, name); if (val) { val.count--; if (val.count <= 0) { - this.remove(name); - } else { - this.setJson(val); + this.__remove(kind, name); } } }; -PodsJson.prototype.setJson = function (name, json) { - this.contents[name] = json; +PodsJson.prototype.decrementLibrary = function (name) { + this.__decrement(PodsJson.LIBRARY, name); +}; + +PodsJson.prototype.decrementSource = function (name) { + this.__decrement(PodsJson.SOURCE, name); +}; + +PodsJson.prototype.decrementDeclaration = function (name) { + this.__decrement(PodsJson.DECLARATION, name); +}; + +PodsJson.prototype.__setJson = function (kind, name, json) { + this.contents[kind][name] = Object.assign({}, json); this.__dirty = true; - events.emit('verbose', util.format('Set pods.json for `%s`', name)); + events.emit('verbose', util.format('Set pods.json for `%s` - `%s`', kind, name)); +}; + +// sample json for library +// { name: "Eureka", spec: "4.2.0", "swift-version": "4.1", count: 1 } +PodsJson.prototype.setJsonLibrary = function (name, json) { + this.__setJson(PodsJson.LIBRARY, name, json); +}; + +// sample json for source +// { source: "https://github.com/brightcove/BrightcoveSpecs.git", count: 1 } +PodsJson.prototype.setJsonSource = function (name, json) { + this.__setJson(PodsJson.SOURCE, name, json); +}; + +// sample json for declaration +// { declaration: ""} +PodsJson.prototype.setJsonDeclaration = function (name, json) { + this.__setJson(PodsJson.DECLARATION, name, json); }; PodsJson.prototype.isDirty = function () { diff --git a/StoneIsland/platforms/ios/cordova/lib/build.js b/StoneIsland/platforms/ios/cordova/lib/build.js index f51b084c..a7203875 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/build.js +++ b/StoneIsland/platforms/ios/cordova/lib/build.js @@ -17,38 +17,51 @@ * under the License. */ -var Q = require('q'); -var path = require('path'); -var shell = require('shelljs'); -var spawn = require('./spawn'); -var fs = require('fs'); -var plist = require('plist'); -var util = require('util'); +const path = require('path'); +const which = require('which'); +const { + CordovaError, + events, + superspawn: { spawn } +} = require('cordova-common'); +const fs = require('fs-extra'); +const plist = require('plist'); +const util = require('util'); -var check_reqs = require('./check_reqs'); -var projectFile = require('./projectFile'); - -var events = require('cordova-common').events; - -var projectPath = path.join(__dirname, '..', '..'); -var projectName = null; +const check_reqs = require('./check_reqs'); +const projectFile = require('./projectFile'); // These are regular expressions to detect if the user is changing any of the built-in xcodebuildArgs /* eslint-disable no-useless-escape */ -var buildFlagMatchers = { - 'xcconfig': /^\-xcconfig\s*(.*)$/, - 'workspace': /^\-workspace\s*(.*)/, - 'scheme': /^\-scheme\s*(.*)/, - 'configuration': /^\-configuration\s*(.*)/, - 'sdk': /^\-sdk\s*(.*)/, - 'destination': /^\-destination\s*(.*)/, - 'archivePath': /^\-archivePath\s*(.*)/, - 'configuration_build_dir': /^(CONFIGURATION_BUILD_DIR=.*)/, - 'shared_precomps_dir': /^(SHARED_PRECOMPS_DIR=.*)/ +const buildFlagMatchers = { + workspace: /^\-workspace\s*(.*)/, + scheme: /^\-scheme\s*(.*)/, + configuration: /^\-configuration\s*(.*)/, + sdk: /^\-sdk\s*(.*)/, + destination: /^\-destination\s*(.*)/, + archivePath: /^\-archivePath\s*(.*)/, + configuration_build_dir: /^(CONFIGURATION_BUILD_DIR=.*)/, + shared_precomps_dir: /^(SHARED_PRECOMPS_DIR=.*)/ }; /* eslint-enable no-useless-escape */ /** + * Creates a project object (see projectFile.js/parseProjectFile) from + * a project path and name + * + * @param {*} projectPath + * @param {*} projectName + */ +function createProjectObject (projectPath, projectName) { + const locations = { + root: projectPath, + pbxproj: path.join(projectPath, `${projectName}.xcodeproj`, 'project.pbxproj') + }; + + return projectFile.parse(locations); +} + +/** * Returns a promise that resolves to the default simulator target; the logic here * matches what `cordova emulate ios` does. * @@ -58,13 +71,13 @@ var buildFlagMatchers = { * @return {Promise} */ function getDefaultSimulatorTarget () { - return require('./list-emulator-build-targets').run() - .then(function (emulators) { - var targetEmulator; + return require('./listEmulatorBuildTargets').run() + .then(emulators => { + let targetEmulator; if (emulators.length > 0) { targetEmulator = emulators[0]; } - emulators.forEach(function (emulator) { + emulators.forEach(emulator => { if (emulator.name.indexOf('iPhone') === 0) { targetEmulator = emulator; } @@ -73,120 +86,137 @@ function getDefaultSimulatorTarget () { }); } -module.exports.run = function (buildOpts) { - var emulatorTarget = ''; +module.exports.run = buildOpts => { + let emulatorTarget = ''; + const projectPath = path.join(__dirname, '..', '..'); + let projectName = ''; buildOpts = buildOpts || {}; if (buildOpts.debug && buildOpts.release) { - return Q.reject('Cannot specify "debug" and "release" options together.'); + return Promise.reject(new CordovaError('Cannot specify "debug" and "release" options together.')); } if (buildOpts.device && buildOpts.emulator) { - return Q.reject('Cannot specify "device" and "emulator" options together.'); + return Promise.reject(new CordovaError('Cannot specify "device" and "emulator" options together.')); } if (buildOpts.buildConfig) { if (!fs.existsSync(buildOpts.buildConfig)) { - return Q.reject('Build config file does not exist:' + buildOpts.buildConfig); + return Promise.reject(new CordovaError(`Build config file does not exist: ${buildOpts.buildConfig}`)); } - events.emit('log', 'Reading build config file:', path.resolve(buildOpts.buildConfig)); - var contents = fs.readFileSync(buildOpts.buildConfig, 'utf-8'); - var buildConfig = JSON.parse(contents.replace(/^\ufeff/, '')); // Remove BOM + events.emit('log', `Reading build config file: ${path.resolve(buildOpts.buildConfig)}`); + const contents = fs.readFileSync(buildOpts.buildConfig, 'utf-8'); + const buildConfig = JSON.parse(contents.replace(/^\ufeff/, '')); // Remove BOM if (buildConfig.ios) { - var buildType = buildOpts.release ? 'release' : 'debug'; - var config = buildConfig.ios[buildType]; + const buildType = buildOpts.release ? 'release' : 'debug'; + const config = buildConfig.ios[buildType]; if (config) { - ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType', 'buildFlag', 'iCloudContainerEnvironment'].forEach( - function (key) { + ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType', 'buildFlag', 'iCloudContainerEnvironment', 'automaticProvisioning'].forEach( + key => { buildOpts[key] = buildOpts[key] || config[key]; }); } } } - return require('./list-devices').run() - .then(function (devices) { + return require('./listDevices').run() + .then(devices => { if (devices.length > 0 && !(buildOpts.emulator)) { // we also explicitly set device flag in options as we pass // those parameters to other api (build as an example) buildOpts.device = true; return check_reqs.check_ios_deploy(); } - }).then(function () { + }).then(() => { // CB-12287: Determine the device we should target when building for a simulator if (!buildOpts.device) { - var newTarget = buildOpts.target || ''; + let newTarget = buildOpts.target || ''; if (newTarget) { // only grab the device name, not the runtime specifier newTarget = newTarget.split(',')[0]; } // a target was given to us, find the matching Xcode destination name - var promise = require('./list-emulator-build-targets').targetForSimIdentifier(newTarget); - return promise.then(function (theTarget) { + const promise = require('./listEmulatorBuildTargets').targetForSimIdentifier(newTarget); + return promise.then(theTarget => { if (!theTarget) { - return getDefaultSimulatorTarget().then(function (defaultTarget) { + return getDefaultSimulatorTarget().then(defaultTarget => { emulatorTarget = defaultTarget.name; - events.emit('log', 'Building for ' + emulatorTarget + ' Simulator'); + events.emit('warn', `No simulator found for "${newTarget}. Falling back to the default target.`); + events.emit('log', `Building for "${emulatorTarget}" Simulator (${defaultTarget.identifier}, ${defaultTarget.simIdentifier}).`); return emulatorTarget; }); } else { emulatorTarget = theTarget.name; - events.emit('log', 'Building for ' + emulatorTarget + ' Simulator'); + events.emit('log', `Building for "${emulatorTarget}" Simulator (${theTarget.identifier}, ${theTarget.simIdentifier}).`); return emulatorTarget; } }); } - }).then(function () { - return check_reqs.run(); - }).then(function () { - return findXCodeProjectIn(projectPath); - }).then(function (name) { + }) + .then(() => check_reqs.run()) + .then(() => findXCodeProjectIn(projectPath)) + .then(name => { projectName = name; - var extraConfig = ''; + let extraConfig = ''; if (buildOpts.codeSignIdentity) { - extraConfig += 'CODE_SIGN_IDENTITY = ' + buildOpts.codeSignIdentity + '\n'; - extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + buildOpts.codeSignIdentity + '\n'; + extraConfig += `CODE_SIGN_IDENTITY = ${buildOpts.codeSignIdentity}\n`; + extraConfig += `CODE_SIGN_IDENTITY[sdk=iphoneos*] = ${buildOpts.codeSignIdentity}\n`; } if (buildOpts.codeSignResourceRules) { - extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + buildOpts.codeSignResourceRules + '\n'; + extraConfig += `CODE_SIGN_RESOURCE_RULES_PATH = ${buildOpts.codeSignResourceRules}\n`; } if (buildOpts.provisioningProfile) { - extraConfig += 'PROVISIONING_PROFILE = ' + buildOpts.provisioningProfile + '\n'; + extraConfig += `PROVISIONING_PROFILE = ${buildOpts.provisioningProfile}\n`; } if (buildOpts.developmentTeam) { - extraConfig += 'DEVELOPMENT_TEAM = ' + buildOpts.developmentTeam + '\n'; + extraConfig += `DEVELOPMENT_TEAM = ${buildOpts.developmentTeam}\n`; } - return Q.nfcall(fs.writeFile, path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8'); - }).then(function () { - var configuration = buildOpts.release ? 'Release' : 'Debug'; - events.emit('log', 'Building project: ' + path.join(projectPath, projectName + '.xcworkspace')); - events.emit('log', '\tConfiguration: ' + configuration); - events.emit('log', '\tPlatform: ' + (buildOpts.device ? 'device' : 'emulator')); + function writeCodeSignStyle (value) { + const project = createProjectObject(projectPath, projectName); - var buildOutputDir = path.join(projectPath, 'build', (buildOpts.device ? 'device' : 'emulator')); + events.emit('verbose', `Set CODE_SIGN_STYLE Build Property to ${value}.`); + project.xcode.updateBuildProperty('CODE_SIGN_STYLE', value); + events.emit('verbose', `Set ProvisioningStyle Target Attribute to ${value}.`); + project.xcode.addTargetAttribute('ProvisioningStyle', value); + + project.write(); + } + + if (buildOpts.provisioningProfile) { + events.emit('verbose', 'ProvisioningProfile build option set, changing project settings to Manual.'); + writeCodeSignStyle('Manual'); + } else if (buildOpts.automaticProvisioning) { + events.emit('verbose', 'ProvisioningProfile build option NOT set, changing project settings to Automatic.'); + writeCodeSignStyle('Automatic'); + } + + return fs.writeFile(path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8'); + }).then(() => { + const configuration = buildOpts.release ? 'Release' : 'Debug'; + + events.emit('log', `Building project: ${path.join(projectPath, `${projectName}.xcworkspace`)}`); + events.emit('log', `\tConfiguration: ${configuration}`); + events.emit('log', `\tPlatform: ${buildOpts.device ? 'device' : 'emulator'}`); + events.emit('log', `\tTarget: ${emulatorTarget}`); + + const buildOutputDir = path.join(projectPath, 'build', (buildOpts.device ? 'device' : 'emulator')); // remove the build/device folder before building - return spawn('rm', [ '-rf', buildOutputDir ], projectPath) - .then(function () { - var xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag, emulatorTarget); - return spawn('xcodebuild', xcodebuildArgs, projectPath); - }); + fs.removeSync(buildOutputDir); - }).then(function () { + const xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag, emulatorTarget, buildOpts.automaticProvisioning); + return spawn('xcodebuild', xcodebuildArgs, { cwd: projectPath, printCommand: true, stdio: 'inherit' }); + }).then(() => { if (!buildOpts.device || buildOpts.noSign) { return; } - var locations = { - root: projectPath, - pbxproj: path.join(projectPath, projectName + '.xcodeproj', 'project.pbxproj') - }; - - var bundleIdentifier = projectFile.parse(locations).getPackageName(); - var exportOptions = {'compileBitcode': false, 'method': 'development'}; + const project = createProjectObject(projectPath, projectName); + const bundleIdentifier = project.getPackageName(); + const exportOptions = { compileBitcode: false, method: 'development' }; if (buildOpts.packageType) { exportOptions.method = buildOpts.packageType; @@ -201,7 +231,7 @@ module.exports.run = function (buildOpts) { } if (buildOpts.provisioningProfile && bundleIdentifier) { - exportOptions.provisioningProfiles = { [ bundleIdentifier ]: String(buildOpts.provisioningProfile) }; + exportOptions.provisioningProfiles = { [bundleIdentifier]: String(buildOpts.provisioningProfile) }; exportOptions.signingStyle = 'manual'; } @@ -209,13 +239,13 @@ module.exports.run = function (buildOpts) { exportOptions.signingCertificate = buildOpts.codeSignIdentity; } - var exportOptionsPlist = plist.build(exportOptions); - var exportOptionsPath = path.join(projectPath, 'exportOptions.plist'); + const exportOptionsPlist = plist.build(exportOptions); + const exportOptionsPath = path.join(projectPath, 'exportOptions.plist'); - var buildOutputDir = path.join(projectPath, 'build', 'device'); + const buildOutputDir = path.join(projectPath, 'build', 'device'); function checkSystemRuby () { - var ruby_cmd = shell.which('ruby'); + const ruby_cmd = which.sync('ruby', { nothrow: true }); if (ruby_cmd !== '/usr/bin/ruby') { events.emit('warn', 'Non-system Ruby in use. This may cause packaging to fail.\n' + @@ -225,11 +255,11 @@ module.exports.run = function (buildOpts) { } function packageArchive () { - var xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath); - return spawn('xcodebuild', xcodearchiveArgs, projectPath); + const xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath, buildOpts.automaticProvisioning); + return spawn('xcodebuild', xcodearchiveArgs, { cwd: projectPath, printCommand: true, stdio: 'inherit' }); } - return Q.nfcall(fs.writeFile, exportOptionsPath, exportOptionsPlist, 'utf-8') + return fs.writeFile(exportOptionsPath, exportOptionsPlist, 'utf-8') .then(checkSystemRuby) .then(packageArchive); }); @@ -242,20 +272,17 @@ module.exports.run = function (buildOpts) { */ function findXCodeProjectIn (projectPath) { // 'Searching for Xcode project in ' + projectPath); - var xcodeProjFiles = shell.ls(projectPath).filter(function (name) { - return path.extname(name) === '.xcodeproj'; - }); + const xcodeProjFiles = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj'); if (xcodeProjFiles.length === 0) { - return Q.reject('No Xcode project found in ' + projectPath); + return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`)); } if (xcodeProjFiles.length > 1) { - events.emit('warn', 'Found multiple .xcodeproj directories in \n' + - projectPath + '\nUsing first one'); + events.emit('warn', `Found multiple .xcodeproj directories in \n${projectPath}\nUsing first one`); } - var projectName = path.basename(xcodeProjFiles[0], '.xcodeproj'); - return Q.resolve(projectName); + const projectName = path.basename(xcodeProjFiles[0], '.xcodeproj'); + return Promise.resolve(projectName); } module.exports.findXCodeProjectIn = findXCodeProjectIn; @@ -268,21 +295,21 @@ module.exports.findXCodeProjectIn = findXCodeProjectIn; * @param {Boolean} isDevice Flag that specify target for package (device/emulator) * @param {Array} buildFlags * @param {String} emulatorTarget Target for emulator (rather than default) + * @param {Boolean} autoProvisioning Whether to allow Xcode to automatically update provisioning * @return {Array} Array of arguments that could be passed directly to spawn method */ -function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, buildFlags, emulatorTarget) { - var xcodebuildArgs; - var options; - var buildActions; - var settings; - var customArgs = {}; +function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, buildFlags, emulatorTarget, autoProvisioning) { + let options; + let buildActions; + let settings; + const customArgs = {}; customArgs.otherFlags = []; if (buildFlags) { if (typeof buildFlags === 'string' || buildFlags instanceof String) { parseBuildFlag(buildFlags, customArgs); } else { // buildFlags is an Array of strings - buildFlags.forEach(function (flag) { + buildFlags.forEach(flag => { parseBuildFlag(flag, customArgs); }); } @@ -290,36 +317,38 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b if (isDevice) { options = [ - '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'), - '-workspace', customArgs.workspace || projectName + '.xcworkspace', + '-workspace', customArgs.workspace || `${projectName}.xcworkspace`, '-scheme', customArgs.scheme || projectName, '-configuration', customArgs.configuration || configuration, '-destination', customArgs.destination || 'generic/platform=iOS', - '-archivePath', customArgs.archivePath || projectName + '.xcarchive' + '-archivePath', customArgs.archivePath || `${projectName}.xcarchive` ]; - buildActions = [ 'archive' ]; + buildActions = ['archive']; settings = [ - customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'device'), - customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch') + customArgs.configuration_build_dir || `CONFIGURATION_BUILD_DIR=${path.join(projectPath, 'build', 'device')}`, + customArgs.shared_precomps_dir || `SHARED_PRECOMPS_DIR=${path.join(projectPath, 'build', 'sharedpch')}` ]; // Add other matched flags to otherFlags to let xcodebuild present an appropriate error. // This is preferable to just ignoring the flags that the user has passed in. if (customArgs.sdk) { customArgs.otherFlags = customArgs.otherFlags.concat(['-sdk', customArgs.sdk]); } + + if (autoProvisioning) { + options = options.concat(['-allowProvisioningUpdates']); + } } else { // emulator options = [ - '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'), - '-workspace', customArgs.project || projectName + '.xcworkspace', + '-workspace', customArgs.project || `${projectName}.xcworkspace`, '-scheme', customArgs.scheme || projectName, '-configuration', customArgs.configuration || configuration, '-sdk', customArgs.sdk || 'iphonesimulator', - '-destination', customArgs.destination || 'platform=iOS Simulator,name=' + emulatorTarget + '-destination', customArgs.destination || `platform=iOS Simulator,name=${emulatorTarget}` ]; - buildActions = [ 'build' ]; + buildActions = ['build']; settings = [ - customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'emulator'), - customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch') + customArgs.configuration_build_dir || `CONFIGURATION_BUILD_DIR=${path.join(projectPath, 'build', 'emulator')}`, + customArgs.shared_precomps_dir || `SHARED_PRECOMPS_DIR=${path.join(projectPath, 'build', 'sharedpch')}` ]; // Add other matched flags to otherFlags to let xcodebuild present an appropriate error. // This is preferable to just ignoring the flags that the user has passed in. @@ -327,8 +356,8 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b customArgs.otherFlags = customArgs.otherFlags.concat(['-archivePath', customArgs.archivePath]); } } - xcodebuildArgs = options.concat(buildActions).concat(settings).concat(customArgs.otherFlags); - return xcodebuildArgs; + + return options.concat(buildActions).concat(settings).concat(customArgs.otherFlags); } /** @@ -337,21 +366,22 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b * @param {String} projectPath Path to project file. Will be used to set CWD for xcodebuild * @param {String} outputPath Output directory to contain the IPA * @param {String} exportOptionsPath Path to the exportOptions.plist file + * @param {Boolean} autoProvisioning Whether to allow Xcode to automatically update provisioning * @return {Array} Array of arguments that could be passed directly to spawn method */ -function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath) { +function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath, autoProvisioning) { return [ '-exportArchive', - '-archivePath', projectName + '.xcarchive', + '-archivePath', `${projectName}.xcarchive`, '-exportOptionsPlist', exportOptionsPath, '-exportPath', outputPath - ]; + ].concat(autoProvisioning ? ['-allowProvisioningUpdates'] : []); } function parseBuildFlag (buildFlag, args) { - var matched; - for (var key in buildFlagMatchers) { - var found = buildFlag.match(buildFlagMatchers[key]); + let matched; + for (const key in buildFlagMatchers) { + const found = buildFlag.match(buildFlagMatchers[key]); if (found) { matched = true; // found[0] is the whole match, found[1] is the first match in parentheses. diff --git a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js index 21a22081..33dc684f 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js +++ b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js @@ -19,37 +19,28 @@ 'use strict'; -const Q = require('q'); -const shell = require('shelljs'); -const util = require('util'); +const which = require('which'); const versions = require('./versions'); +const { CordovaError } = require('cordova-common'); -const SUPPORTED_OS_PLATFORMS = [ 'darwin' ]; +const SUPPORTED_OS_PLATFORMS = ['darwin']; -const XCODEBUILD_MIN_VERSION = '7.0.0'; +const XCODEBUILD_MIN_VERSION = '9.0.0'; const XCODEBUILD_NOT_FOUND_MESSAGE = - 'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store'; + `Please install version ${XCODEBUILD_MIN_VERSION} or greater from App Store`; const IOS_DEPLOY_MIN_VERSION = '1.9.2'; const IOS_DEPLOY_NOT_FOUND_MESSAGE = - 'Please download, build and install version ' + IOS_DEPLOY_MIN_VERSION + ' or greater' + - ' from https://github.com/phonegap/ios-deploy into your path, or do \'npm install -g ios-deploy\''; + `Please download, build and install version ${IOS_DEPLOY_MIN_VERSION} or greater from https://github.com/ios-control/ios-deploy into your path, or do 'npm install -g ios-deploy'`; -const COCOAPODS_MIN_VERSION = '1.0.1'; -const COCOAPODS_NOT_FOUND_MESSAGE = - 'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/'; -const COCOAPODS_NOT_SYNCED_MESSAGE = - 'The CocoaPods repo has not been synced yet, this will take a long time (approximately 500MB as of Sept 2016). Please run `pod setup` first to sync the repo.'; -const COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes -const COCOAPODS_SYNC_ERROR_MESSAGE = - 'The CocoaPods repo has been created, but there appears to be a sync error. The repo size should be at least ' + COCOAPODS_SYNCED_MIN_SIZE + '. Please run `pod setup --verbose` to sync the repo.'; -const COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.'; +const COCOAPODS_MIN_VERSION = '1.8.0'; +const COCOAPODS_NOT_FOUND_MESSAGE = `Please install version ${COCOAPODS_MIN_VERSION} or greater from https://cocoapods.org/`; /** * Checks if xcode util is available * @return {Promise} Returns a promise either resolved with xcode version or rejected */ -module.exports.run = module.exports.check_xcodebuild = function () { +module.exports.run = module.exports.check_xcodebuild = () => { return checkTool('xcodebuild', XCODEBUILD_MIN_VERSION, XCODEBUILD_NOT_FOUND_MESSAGE); }; @@ -57,81 +48,27 @@ module.exports.run = module.exports.check_xcodebuild = function () { * Checks if ios-deploy util is available * @return {Promise} Returns a promise either resolved with ios-deploy version or rejected */ -module.exports.check_ios_deploy = function () { +module.exports.check_ios_deploy = () => { return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE); }; -module.exports.check_os = function () { +module.exports.check_os = () => { // Build iOS apps available for OSX platform only, so we reject on others platforms - return os_platform_is_supported() ? - Q.resolve(process.platform) : - Q.reject('Cordova tooling for iOS requires Apple macOS'); + return os_platform_is_supported() + ? Promise.resolve(process.platform) + : Promise.reject(new CordovaError('Cordova tooling for iOS requires Apple macOS')); }; function os_platform_is_supported () { return (SUPPORTED_OS_PLATFORMS.indexOf(process.platform) !== -1); } -function check_cocoapod_tool (toolChecker) { - toolChecker = toolChecker || checkTool; - if (os_platform_is_supported()) { // CB-12856 - return toolChecker('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods'); - } else { - return Q.resolve({ - 'ignore': true, - 'ignoreMessage': `CocoaPods check and installation ignored on ${process.platform}` - }); - } -} - /** - * Checks if cocoapods repo size is what is expected + * Checks if cocoapods is available. * @return {Promise} Returns a promise either resolved or rejected */ -module.exports.check_cocoapods_repo_size = function () { - return check_cocoapod_tool() - .then(function (toolOptions) { - // check size of ~/.cocoapods repo - let commandString = util.format('du -sh %s/.cocoapods', process.env.HOME); - let command = shell.exec(commandString, { silent: true }); - // command.output is e.g "750M path/to/.cocoapods", we just scan the number - let size = toolOptions.ignore ? 0 : parseFloat(command.output); - - if (toolOptions.ignore || command.code === 0) { // success, parse output - return Q.resolve(size, toolOptions); - } else { // error, perhaps not found - return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output)); - } - }) - .then(function (repoSize, toolOptions) { - if (toolOptions.ignore || COCOAPODS_SYNCED_MIN_SIZE <= repoSize) { // success, expected size - return Q.resolve(toolOptions); - } else { - return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE); - } - }); -}; - -/** - * Checks if cocoapods is available, and whether the repo is synced (because it takes a long time to download) - * @return {Promise} Returns a promise either resolved or rejected - */ -module.exports.check_cocoapods = function (toolChecker) { - return check_cocoapod_tool(toolChecker) - // check whether the cocoapods repo has been synced through `pod repo` command - // a value of '0 repos' means it hasn't been synced - .then(function (toolOptions) { - let code = shell.exec('pod repo | grep -e "^0 repos"', { silent: true }).code; - let repoIsSynced = (code !== 0); - - if (toolOptions.ignore || repoIsSynced) { - // return check_cocoapods_repo_size(); - // we could check the repo size above, but it takes too long. - return Q.resolve(toolOptions); - } else { - return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE); - } - }); +module.exports.check_cocoapods = toolChecker => { + return checkTool('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods'); }; /** @@ -146,18 +83,17 @@ function checkTool (tool, minVersion, message, toolFriendlyName) { toolFriendlyName = toolFriendlyName || tool; // Check whether tool command is available at all - let tool_command = shell.which(tool); + const tool_command = which.sync(tool, { nothrow: true }); if (!tool_command) { - return Q.reject(toolFriendlyName + ' was not found. ' + (message || '')); + return Promise.reject(new CordovaError(`${toolFriendlyName} was not found. ${message || ''}`)); } // check if tool version is greater than specified one - return versions.get_tool_version(tool).then(function (version) { + return versions.get_tool_version(tool).then(version => { version = version.trim(); - return versions.compareVersions(version, minVersion) >= 0 ? - Q.resolve({ 'version': version }) : - Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion + - ' or greater, you have version ' + version + '. ' + (message || '')); + return versions.compareVersions(version, minVersion) >= 0 + ? Promise.resolve({ version }) + : Promise.reject(new CordovaError(`Cordova needs ${toolFriendlyName} version ${minVersion} or greater, you have version ${version}. ${message || ''}`)); }); } @@ -168,7 +104,7 @@ function checkTool (tool, minVersion, message, toolFriendlyName) { * @param {Boolean} isFatal Marks the requirement as fatal. If such requirement will fail * next requirements' checks will be skipped. */ -let Requirement = function (id, name, isFatal) { +const Requirement = function (id, name, isFatal) { this.id = id; this.name = name; this.installed = false; @@ -182,8 +118,7 @@ let Requirement = function (id, name, isFatal) { * * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled. */ -module.exports.check_all = function () { - +module.exports.check_all = () => { const requirements = [ new Requirement('os', 'Apple macOS', true), new Requirement('xcode', 'Xcode'), @@ -191,10 +126,10 @@ module.exports.check_all = function () { new Requirement('CocoaPods', 'CocoaPods') ]; - let result = []; + const result = []; let fatalIsHit = false; - let checkFns = [ + const checkFns = [ module.exports.check_os, module.exports.check_xcodebuild, module.exports.check_ios_deploy, @@ -202,27 +137,25 @@ module.exports.check_all = function () { ]; // Then execute requirement checks one-by-one - return checkFns.reduce(function (promise, checkFn, idx) { - return promise.then(function () { + return checkFns.reduce((promise, checkFn, idx) => { + return promise.then(() => { // If fatal requirement is failed, // we don't need to check others - if (fatalIsHit) return Q(); + if (fatalIsHit) return Promise.resolve(); - let requirement = requirements[idx]; + const requirement = requirements[idx]; return checkFn() - .then(function (version) { + .then(version => { requirement.installed = true; requirement.metadata.version = version; result.push(requirement); - }, function (err) { + }, err => { if (requirement.isFatal) fatalIsHit = true; requirement.metadata.reason = err; result.push(requirement); }); }); - }, Q()) - .then(function () { - // When chain is completed, return requirements array to upstream API - return result; - }); + }, Promise.resolve()) + // When chain is completed, return requirements array to upstream API + .then(() => result); }; diff --git a/StoneIsland/platforms/ios/cordova/lib/clean.js b/StoneIsland/platforms/ios/cordova/lib/clean.js index 20e8ac66..72aac0ba 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/clean.js +++ b/StoneIsland/platforms/ios/cordova/lib/clean.js @@ -17,26 +17,31 @@ * under the License. */ -var Q = require('q'); -var path = require('path'); -var shell = require('shelljs'); -var spawn = require('./spawn'); +const path = require('path'); +const fs = require('fs-extra'); +const { + CordovaError, + superspawn: { spawn } +} = require('cordova-common'); -var projectPath = path.join(__dirname, '..', '..'); +const projectPath = path.join(__dirname, '..', '..'); -module.exports.run = function () { - var projectName = shell.ls(projectPath).filter(function (name) { - return path.extname(name) === '.xcodeproj'; - })[0]; +module.exports.run = () => { + const projectName = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj'); if (!projectName) { - return Q.reject('No Xcode project found in ' + projectPath); + return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`)); } - return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Debug', '-alltargets', 'clean'], projectPath) - .then(function () { - return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Release', '-alltargets', 'clean'], projectPath); - }).then(function () { - return shell.rm('-rf', path.join(projectPath, 'build')); - }); + const xcodebuildClean = configName => { + return spawn( + 'xcodebuild', + ['-project', projectName, '-configuration', configName, '-alltargets', 'clean'], + { cwd: projectPath, printCommand: true, stdio: 'inherit' } + ); + }; + + return xcodebuildClean('Debug') + .then(() => xcodebuildClean('Release')) + .then(() => fs.removeSync(path.join(projectPath, 'build'))); }; diff --git a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js b/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js deleted file mode 100755 index e05aacf2..00000000 --- a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -// This script copies the www directory into the Xcode project. - -// This script should not be called directly. -// It is called as a build step from Xcode. - -var BUILT_PRODUCTS_DIR = process.env.BUILT_PRODUCTS_DIR; -var FULL_PRODUCT_NAME = process.env.FULL_PRODUCT_NAME; -var COPY_HIDDEN = process.env.COPY_HIDDEN; -var PROJECT_FILE_PATH = process.env.PROJECT_FILE_PATH; - -var path = require('path'); -var fs = require('fs'); -var shell = require('shelljs'); -var srcDir = 'www'; -var dstDir = path.join(BUILT_PRODUCTS_DIR, FULL_PRODUCT_NAME); -var dstWwwDir = path.join(dstDir, 'www'); - -if (!BUILT_PRODUCTS_DIR) { - console.error('The script is meant to be run as an Xcode build step and relies on env variables set by Xcode.'); - process.exit(1); -} - -try { - fs.statSync(srcDir); -} catch (e) { - console.error('Path does not exist: ' + srcDir); - process.exit(2); -} - -// Code signing files must be removed or else there are -// resource signing errors. -shell.rm('-rf', dstWwwDir); -shell.rm('-rf', path.join(dstDir, '_CodeSignature')); -shell.rm('-rf', path.join(dstDir, 'PkgInfo')); -shell.rm('-rf', path.join(dstDir, 'embedded.mobileprovision')); - -// Copy www dir recursively -var code; -if (COPY_HIDDEN) { - code = shell.exec('rsync -Lra "' + srcDir + '" "' + dstDir + '"').code; -} else { - code = shell.exec('rsync -Lra --exclude="- .*" "' + srcDir + '" "' + dstDir + '"').code; -} - -if (code !== 0) { - console.error('Error occured on copying www. Code: ' + code); - process.exit(3); -} - -// Copy the config.xml file. -shell.cp('-f', path.join(path.dirname(PROJECT_FILE_PATH), path.basename(PROJECT_FILE_PATH, '.xcodeproj'), 'config.xml'), - dstDir); diff --git a/StoneIsland/platforms/ios/cordova/lib/list-devices b/StoneIsland/platforms/ios/cordova/lib/list-devices index 047d5950..5f89e21b 100755 --- a/StoneIsland/platforms/ios/cordova/lib/list-devices +++ b/StoneIsland/platforms/ios/cordova/lib/list-devices @@ -19,49 +19,10 @@ under the License. */ +const { run } = require('./listDevices'); -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Gets list of connected iOS devices - * @return {Promise} Promise fulfilled with list of available iOS devices - */ -function listDevices() { - var commands = [ - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPad/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPad"}\''), - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPhone/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPhone"}\''), - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPod/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPod"}\'') - ]; - - // wrap al lexec calls into promises and wait until they're fullfilled - return Q.all(commands).then(function (results) { - var accumulator = []; - results.forEach(function (result) { - var devicefound; - // Each command promise resolves with array [stout, stderr], and we need stdout only - // Append stdout lines to accumulator - devicefound = result[0].trim().split('\n'); - if(devicefound && devicefound.length) { - devicefound.forEach(function(device) { - if (device) { - accumulator.push(device); - } - }); - } - }); - return accumulator; - }); -} - -exports.run = listDevices; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listDevices().then(function (devices) { - devices.forEach(function (device) { - console.log(device); - }); +run().then(devices => { + devices.forEach(device => { + console.log(device); }); -}
\ No newline at end of file +}); diff --git a/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets b/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets index ccf61f98..304c4c17 100755 --- a/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets +++ b/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets @@ -19,99 +19,8 @@ under the License. */ +const { run } = require('./listEmulatorBuildTargets'); -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Returns a list of available simulator build targets of the form - * - * [ - * { name: <xcode-destination-name>, - * identifier: <simctl-identifier>, - * simIdentifier: <cordova emulate target> - * } - * ] - * - */ -function listEmulatorBuildTargets () { - return Q.nfcall(exec, 'xcrun simctl list --json') - .then(function(stdio) { - return JSON.parse(stdio[0]); - }) - .then(function(simInfo) { - var devices = simInfo.devices; - var deviceTypes = simInfo.devicetypes; - return deviceTypes.reduce(function (typeAcc, deviceType) { - if (!deviceType.name.match(/^[iPad|iPhone]/)) { - // ignore targets we don't support (like Apple Watch or Apple TV) - return typeAcc; - } - var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) { - var availableDevicesInCategory = devices[deviceCategory]; - availableDevicesInCategory.forEach(function (device) { - if (device && device.name === deviceType.name.replace(/\-inch/g, ' inch') && device.isAvailable == true) { - availAcc.push(device); - } - }); - return availAcc; - }, []); - - // var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) { - // var availableDevicesInCategory = devices[deviceCategory]; - // availableDevicesInCategory.forEach(function (device) { - // if (device.name === deviceType.name.replace(/\-inch/g, ' inch') && - // device.availability.toLowerCase().indexOf('unavailable') < 0) { - // availAcc.push(device); - // } - // }); - // return availAcc; - //}, []); - // we only want device types that have at least one available device - // (regardless of OS); this filters things out like iPhone 4s, which - // is present in deviceTypes, but probably not available on the user's - // system. - if (availableDevices.length > 0) { - typeAcc.push(deviceType); - } - return typeAcc; - }, []); - }) - .then(function(filteredTargets) { - // the simIdentifier, or cordova emulate target name, is the very last part - // of identifier. - return filteredTargets.map(function (target) { - var identifierPieces = target.identifier.split("."); - target.simIdentifier = identifierPieces[identifierPieces.length-1]; - return target; - }); - }); -} - -exports.run = listEmulatorBuildTargets; - -/** - * Given a simIdentifier, return the matching target. - * - * @param {string} simIdentifier a target, like "iPhone-SE" - * @return {Object} the matching target, or undefined if no match - */ -exports.targetForSimIdentifier = function(simIdentifier) { - return listEmulatorBuildTargets() - .then(function(targets) { - return targets.reduce(function(acc, target) { - if (!acc && target.simIdentifier.toLowerCase() === simIdentifier.toLowerCase()) { - acc = target; - } - return acc; - }, undefined); - }); -} - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listEmulatorBuildTargets().then(function (targets) { - console.log(JSON.stringify(targets, null, 2)); - }); -} +run().then(targets => { + console.log(JSON.stringify(targets, null, 2)); +}); diff --git a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images index d8be5766..db9b72af 100755 --- a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images +++ b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images @@ -19,29 +19,10 @@ under the License. */ +const { run } = require('./listEmulatorImages'); -var Q = require('q'), - iossim = require('ios-sim'), - exec = require('child_process').exec, - check_reqs = require('./check_reqs'); - -/** - * Gets list of iOS devices available for simulation - * @return {Promise} Promise fulfilled with list of devices available for simulation - */ -function listEmulatorImages () { - return Q.resolve(iossim.getdevicetypes()); -} - - -exports.run = listEmulatorImages; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listEmulatorImages().then(function (names) { - names.forEach(function (name) { - console.log(name); - }); +run().then(names => { + names.forEach(name => { + console.log(name); }); -} +}); diff --git a/StoneIsland/platforms/ios/cordova/lib/list-started-emulators b/StoneIsland/platforms/ios/cordova/lib/list-started-emulators index 710fa2f7..7f06cf2e 100755 --- a/StoneIsland/platforms/ios/cordova/lib/list-started-emulators +++ b/StoneIsland/platforms/ios/cordova/lib/list-started-emulators @@ -19,32 +19,10 @@ under the License. */ +const { run } = require('./listStartedEmulators'); -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Gets list of running iOS simulators - * @return {Promise} Promise fulfilled with list of running iOS simulators - */ -function listStartedEmulators () { - // wrap exec call into promise - return Q.nfcall(exec, 'ps aux | grep -i "[i]OS Simulator"') - .then(function () { - return Q.nfcall(exec, 'defaults read com.apple.iphonesimulator "SimulateDevice"'); - }).then(function (stdio) { - return stdio[0].trim().split('\n'); - }); -} - -exports.run = listStartedEmulators; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listStartedEmulators().then(function (emulators) { - emulators.forEach(function (emulator) { - console.log(emulator); - }); +run().then(emulators => { + emulators.forEach(emulator => { + console.log(emulator); }); -} +}); diff --git a/StoneIsland/platforms/ios/cordova/lib/listDevices.js b/StoneIsland/platforms/ios/cordova/lib/listDevices.js new file mode 100644 index 00000000..86a67ffb --- /dev/null +++ b/StoneIsland/platforms/ios/cordova/lib/listDevices.js @@ -0,0 +1,42 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +const { superspawn: { spawn } } = require('cordova-common'); + +const DEVICE_REGEX = /-o (iPhone|iPad|iPod)@.*?"USB Serial Number" = "([^"]*)"/gs; + +/** + * Gets list of connected iOS devices + * @return {Promise} Promise fulfilled with list of available iOS devices + */ +function listDevices () { + return spawn('ioreg', ['-p', 'IOUSB', '-l']) + .then(output => { + return [...matchAll(output, DEVICE_REGEX)] + .map(m => m.slice(1).reverse().join(' ')); + }); +} + +// TODO: Should be replaced with String#matchAll once available +function * matchAll (s, r) { + let match; + while ((match = r.exec(s))) yield match; +} + +exports.run = listDevices; diff --git a/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js b/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js new file mode 100644 index 00000000..73e35c05 --- /dev/null +++ b/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js @@ -0,0 +1,95 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +const { superspawn: { spawn } } = require('cordova-common'); + +/** + * Returns a list of available simulator build targets of the form + * + * [ + * { name: <xcode-destination-name>, + * identifier: <simctl-identifier>, + * simIdentifier: <cordova emulate target> + * } + * ] + * + */ +function listEmulatorBuildTargets () { + return spawn('xcrun', ['simctl', 'list', '--json']) + .then(output => JSON.parse(output)) + .then(function (simInfo) { + var devices = simInfo.devices; + var deviceTypes = simInfo.devicetypes; + return deviceTypes.reduce(function (typeAcc, deviceType) { + if (!deviceType.name.match(/^[iPad|iPhone]/)) { + // ignore targets we don't support (like Apple Watch or Apple TV) + return typeAcc; + } + var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) { + var availableDevicesInCategory = devices[deviceCategory]; + availableDevicesInCategory.forEach(function (device) { + if (device.name === deviceType.name || device.name === deviceType.name.replace(/-inch/g, ' inch')) { + // Check new flag isAvailable (XCode 10.1+) or legacy string availability (XCode 10 and lower) + if (device.isAvailable || (device.availability && device.availability.toLowerCase().indexOf('unavailable') < 0)) { + availAcc.push(device); + } + } + }); + return availAcc; + }, []); + // we only want device types that have at least one available device + // (regardless of OS); this filters things out like iPhone 4s, which + // is present in deviceTypes, but probably not available on the user's + // system. + if (availableDevices.length > 0) { + typeAcc.push(deviceType); + } + return typeAcc; + }, []); + }) + .then(function (filteredTargets) { + // the simIdentifier, or cordova emulate target name, is the very last part + // of identifier. + return filteredTargets.map(function (target) { + var identifierPieces = target.identifier.split('.'); + target.simIdentifier = identifierPieces[identifierPieces.length - 1]; + return target; + }); + }); +} + +exports.run = listEmulatorBuildTargets; + +/** + * Given a simIdentifier, return the matching target. + * + * @param {string} simIdentifier a target, like "iPhone-SE" + * @return {Object} the matching target, or undefined if no match + */ +exports.targetForSimIdentifier = function (simIdentifier) { + return listEmulatorBuildTargets() + .then(function (targets) { + return targets.reduce(function (acc, target) { + if (!acc && target.simIdentifier.toLowerCase() === simIdentifier.toLowerCase()) { + acc = target; + } + return acc; + }, undefined); + }); +}; diff --git a/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js b/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js new file mode 100644 index 00000000..09e14340 --- /dev/null +++ b/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js @@ -0,0 +1,30 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +var iossim = require('ios-sim'); + +/** + * Gets list of iOS devices available for simulation + * @return {Promise} Promise fulfilled with list of devices available for simulation + */ +function listEmulatorImages () { + return Promise.resolve(iossim.getdevicetypes()); +} + +exports.run = listEmulatorImages; diff --git a/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js b/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js new file mode 100644 index 00000000..ec1cb7f2 --- /dev/null +++ b/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js @@ -0,0 +1,50 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +const { superspawn: { spawn } } = require('cordova-common'); + +/** + * Gets list of running iOS simulators + * @return {Promise} Promise fulfilled with list of running iOS simulators + * + * @todo In the next PR, I will refactor this entire method. + * + * The process no longer contains the pattern "[i]OS Simulator". + * The process is now called "Simulator.app" + * + * Additionaly, `defaults read com.apple.iphonesimulator "SimulateDevice"` is also not valid aymore. + * + * I will replace this entire method to locate the active simulators though `simctl` + * + * Alternativly, remove this file. It is not documented in Cordova and not used anywhere in our code base. + */ +function listStartedEmulators () { + // wrap exec call into promise + return spawn('ps', ['aux']) + .then(output => { + if (output.match(/[i]OS Simulator/)) { + return spawn('defaults', ['read', 'com.apple.iphonesimulator', '"SimulateDevice"']); + } + + return ''; + }) + .then(output => output.split('\n')); +} + +exports.run = listStartedEmulators; diff --git a/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js index 1f6920fa..09d5ae51 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js +++ b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js @@ -15,21 +15,20 @@ under the License. */ 'use strict'; -var fs = require('fs'); -var path = require('path'); -var shell = require('shelljs'); -var util = require('util'); -var events = require('cordova-common').events; -var CordovaError = require('cordova-common').CordovaError; +const fs = require('fs-extra'); +const path = require('path'); +const util = require('util'); +const events = require('cordova-common').events; +const CordovaError = require('cordova-common').CordovaError; // These frameworks are required by cordova-ios by default. We should never add/remove them. -var keep_these_frameworks = [ +const keep_these_frameworks = [ 'MobileCoreServices.framework', 'CoreGraphics.framework', 'AssetsLibrary.framework' ]; -var handlers = { +const handlers = { 'source-file': { install: function (obj, plugin, project, options) { installHelper('source-file', obj, plugin.dir, project.projectDir, plugin.id, options, project); @@ -48,47 +47,47 @@ var handlers = { }, 'resource-file': { install: function (obj, plugin, project, options) { - var src = obj.src; - var target = obj.target; - var srcFile = path.resolve(plugin.dir, src); + const src = obj.src; + let target = obj.target; + const srcFile = path.resolve(plugin.dir, src); if (!target) { target = path.basename(src); } - var destFile = path.resolve(project.resources_dir, target); + const destFile = path.resolve(project.resources_dir, target); if (!fs.existsSync(srcFile)) { - throw new CordovaError('Cannot find resource file "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform'); + throw new CordovaError(`Cannot find resource file "${srcFile}" for plugin ${plugin.id} in iOS platform`); } if (fs.existsSync(destFile)) { - throw new CordovaError('File already exists at destination "' + destFile + '" for resource file specified by plugin ' + plugin.id + ' in iOS platform'); + throw new CordovaError(`File already exists at destination "${destFile}" for resource file specified by plugin ${plugin.id} in iOS platform`); } project.xcode.addResourceFile(path.join('Resources', target)); - var link = !!(options && options.link); + const link = !!(options && options.link); copyFile(plugin.dir, src, project.projectDir, destFile, link); }, uninstall: function (obj, plugin, project, options) { - var src = obj.src; - var target = obj.target; + const src = obj.src; + let target = obj.target; if (!target) { target = path.basename(src); } - var destFile = path.resolve(project.resources_dir, target); + const destFile = path.resolve(project.resources_dir, target); project.xcode.removeResourceFile(path.join('Resources', target)); - shell.rm('-rf', destFile); + fs.removeSync(destFile); } }, - 'framework': { // CB-5238 custom frameworks only + framework: { // CB-5238 custom frameworks only install: function (obj, plugin, project, options) { - var src = obj.src; - var custom = !!(obj.custom); // convert to boolean (if truthy/falsy) - var embed = !!(obj.embed); // convert to boolean (if truthy/falsy) - var link = !embed; // either link or embed can be true, but not both. the other has to be false + const src = obj.src; + const custom = !!(obj.custom); // convert to boolean (if truthy/falsy) + const embed = !!(obj.embed); // convert to boolean (if truthy/falsy) + const link = !embed; // either link or embed can be true, but not both. the other has to be false if (!custom) { - var keepFrameworks = keep_these_frameworks; + const keepFrameworks = keep_these_frameworks; if (keepFrameworks.indexOf(src) < 0) { if (obj.type === 'podspec') { @@ -96,7 +95,7 @@ var handlers = { } else { project.frameworks[src] = project.frameworks[src] || 0; project.frameworks[src]++; - let opt = { customFramework: false, embed: false, link: true, weak: obj.weak }; + const opt = { customFramework: false, embed: false, link: true, weak: obj.weak }; events.emit('verbose', util.format('Adding non-custom framework to project... %s -> %s', src, JSON.stringify(opt))); project.xcode.addFramework(src, opt); events.emit('verbose', util.format('Non-custom framework added to project. %s -> %s', src, JSON.stringify(opt))); @@ -104,41 +103,32 @@ var handlers = { } return; } - var srcFile = path.resolve(plugin.dir, src); - var targetDir = path.resolve(project.plugins_dir, plugin.id, path.basename(src)); - if (!fs.existsSync(srcFile)) throw new CordovaError('Cannot find framework "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform'); - if (fs.existsSync(targetDir)) throw new CordovaError('Framework "' + targetDir + '" for plugin ' + plugin.id + ' already exists in iOS platform'); - var symlink = !!(options && options.link); + const srcFile = path.resolve(plugin.dir, src); + const targetDir = path.resolve(project.plugins_dir, plugin.id, path.basename(src)); + if (!fs.existsSync(srcFile)) throw new CordovaError(`Cannot find framework "${srcFile}" for plugin ${plugin.id} in iOS platform`); + if (fs.existsSync(targetDir)) throw new CordovaError(`Framework "${targetDir}" for plugin ${plugin.id} already exists in iOS platform`); + const symlink = !!(options && options.link); copyFile(plugin.dir, src, project.projectDir, targetDir, symlink); // frameworks are directories // CB-10773 translate back slashes to forward on win32 - var project_relative = fixPathSep(path.relative(project.projectDir, targetDir)); + const project_relative = fixPathSep(path.relative(project.projectDir, targetDir)); // CB-11233 create Embed Frameworks Build Phase if does not exist - var existsEmbedFrameworks = project.xcode.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks'); + const existsEmbedFrameworks = project.xcode.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks'); if (!existsEmbedFrameworks && embed) { events.emit('verbose', '"Embed Frameworks" Build Phase (Embedded Binaries) does not exist, creating it.'); project.xcode.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', null, 'frameworks'); } - let opt = { customFramework: true, embed: embed, link: link, sign: true }; + const opt = { customFramework: true, embed, link, sign: true }; events.emit('verbose', util.format('Adding custom framework to project... %s -> %s', src, JSON.stringify(opt))); project.xcode.addFramework(project_relative, opt); events.emit('verbose', util.format('Custom framework added to project. %s -> %s', src, JSON.stringify(opt))); }, uninstall: function (obj, plugin, project, options) { - var src = obj.src; + const src = obj.src; if (!obj.custom) { // CB-9825 cocoapod integration for plugins - var keepFrameworks = keep_these_frameworks; + const keepFrameworks = keep_these_frameworks; if (keepFrameworks.indexOf(src) < 0) { - if (obj.type === 'podspec') { - var podsJSON = require(path.join(project.projectDir, 'pods.json')); - if (podsJSON[src]) { - if (podsJSON[src].count > 1) { - podsJSON[src].count = podsJSON[src].count - 1; - } else { - delete podsJSON[src]; - } - } - } else { + if (obj.type !== 'podspec') { // this should be refactored project.frameworks[src] = project.frameworks[src] || 1; project.frameworks[src]--; @@ -153,12 +143,12 @@ var handlers = { return; } - var targetDir = fixPathSep(path.resolve(project.plugins_dir, plugin.id, path.basename(src))); - var pbxFile = project.xcode.removeFramework(targetDir, {customFramework: true}); + const targetDir = fixPathSep(path.resolve(project.plugins_dir, plugin.id, path.basename(src))); + const pbxFile = project.xcode.removeFramework(targetDir, { customFramework: true }); if (pbxFile) { project.xcode.removeFromPbxEmbedFrameworksBuildPhase(pbxFile); } - shell.rm('-rf', targetDir); + fs.removeSync(targetDir); } }, 'lib-file': { @@ -169,7 +159,7 @@ var handlers = { events.emit('verbose', '<lib-file> uninstall is not supported for iOS plugins'); } }, - 'asset': { + asset: { install: function (obj, plugin, project, options) { if (!obj.src) { throw new CordovaError(generateAttributeError('src', 'asset', plugin.id)); @@ -182,7 +172,7 @@ var handlers = { if (options && options.usePlatformWww) copyFile(plugin.dir, obj.src, project.platformWww, obj.target); }, uninstall: function (obj, plugin, project, options) { - var target = obj.target; + const target = obj.target; if (!target) { throw new CordovaError(generateAttributeError('target', 'asset', plugin.id)); @@ -199,58 +189,58 @@ var handlers = { 'js-module': { install: function (obj, plugin, project, options) { // Copy the plugin's files into the www directory. - var moduleSource = path.resolve(plugin.dir, obj.src); - var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src))); + const moduleSource = path.resolve(plugin.dir, obj.src); + const moduleName = `${plugin.id}.${obj.name || path.basename(obj.src, path.extname(obj.src))}`; // Read in the file, prepend the cordova.define, and write it back out. - var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM + let scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM if (moduleSource.match(/.*\.json$/)) { - scriptContent = 'module.exports = ' + scriptContent; + scriptContent = `module.exports = ${scriptContent}`; } - scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n'; + scriptContent = `cordova.define("${moduleName}", function(require, exports, module) {\n${scriptContent}\n});\n`; - var moduleDestination = path.resolve(project.www, 'plugins', plugin.id, obj.src); - shell.mkdir('-p', path.dirname(moduleDestination)); + const moduleDestination = path.resolve(project.www, 'plugins', plugin.id, obj.src); + fs.ensureDirSync(path.dirname(moduleDestination)); fs.writeFileSync(moduleDestination, scriptContent, 'utf-8'); if (options && options.usePlatformWww) { - var platformWwwDestination = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src); - shell.mkdir('-p', path.dirname(platformWwwDestination)); + const platformWwwDestination = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src); + fs.ensureDirSync(path.dirname(platformWwwDestination)); fs.writeFileSync(platformWwwDestination, scriptContent, 'utf-8'); } }, uninstall: function (obj, plugin, project, options) { - var pluginRelativePath = path.join('plugins', plugin.id, obj.src); + const pluginRelativePath = path.join('plugins', plugin.id, obj.src); removeFileAndParents(project.www, pluginRelativePath); if (options && options.usePlatformWww) removeFileAndParents(project.platformWww, pluginRelativePath); } } }; -module.exports.getInstaller = function (type) { +module.exports.getInstaller = type => { if (handlers[type] && handlers[type].install) { return handlers[type].install; } - events.emit('warn', '<' + type + '> is not supported for iOS plugins'); + events.emit('warn', `<${type}> is not supported for iOS plugins`); }; -module.exports.getUninstaller = function (type) { +module.exports.getUninstaller = type => { if (handlers[type] && handlers[type].uninstall) { return handlers[type].uninstall; } - events.emit('warn', '<' + type + '> is not supported for iOS plugins'); + events.emit('warn', `<${type}> is not supported for iOS plugins`); }; function installHelper (type, obj, plugin_dir, project_dir, plugin_id, options, project) { - var srcFile = path.resolve(plugin_dir, obj.src); - var targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || ''); - var destFile = path.join(targetDir, path.basename(obj.src)); + const srcFile = path.resolve(plugin_dir, obj.src); + const targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || ''); + const destFile = path.join(targetDir, path.basename(obj.src)); - var project_ref; - var link = !!(options && options.link); + let project_ref; + const link = !!(options && options.link); if (link) { - var trueSrc = fs.realpathSync(srcFile); + const trueSrc = fs.realpathSync(srcFile); // Create a symlink in the expected place, so that uninstall can use it. if (options && options.force) { copyFile(plugin_dir, trueSrc, project_dir, destFile, link); @@ -261,101 +251,98 @@ function installHelper (type, obj, plugin_dir, project_dir, plugin_id, options, // Make the Xcode reference the file directly. // Note: Can't use path.join() here since it collapses 'Plugins/..', and xcode // library special-cases Plugins/ prefix. - project_ref = 'Plugins/' + fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc)); + project_ref = `Plugins/${fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc))}`; } else { if (options && options.force) { copyFile(plugin_dir, srcFile, project_dir, destFile, link); } else { copyNewFile(plugin_dir, srcFile, project_dir, destFile, link); } - project_ref = 'Plugins/' + fixPathSep(path.relative(project.plugins_dir, destFile)); + project_ref = `Plugins/${fixPathSep(path.relative(project.plugins_dir, destFile))}`; } if (type === 'header-file') { project.xcode.addHeaderFile(project_ref); } else if (obj.framework) { - var opt = { weak: obj.weak }; - var project_relative = path.join(path.basename(project.xcode_path), project_ref); + const opt = { weak: obj.weak }; + const project_relative = path.join(path.basename(project.xcode_path), project_ref); project.xcode.addFramework(project_relative, opt); - project.xcode.addToLibrarySearchPaths({path: project_ref}); + project.xcode.addToLibrarySearchPaths({ path: project_ref }); } else { - project.xcode.addSourceFile(project_ref, obj.compilerFlags ? {compilerFlags: obj.compilerFlags} : {}); + project.xcode.addSourceFile(project_ref, obj.compilerFlags ? { compilerFlags: obj.compilerFlags } : {}); } } function uninstallHelper (type, obj, project_dir, plugin_id, options, project) { - var targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || ''); - var destFile = path.join(targetDir, path.basename(obj.src)); + const targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || ''); + const destFile = path.join(targetDir, path.basename(obj.src)); - var project_ref; - var link = !!(options && options.link); + let project_ref; + const link = !!(options && options.link); if (link) { - var trueSrc = fs.readlinkSync(destFile); - project_ref = 'Plugins/' + fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc)); + const trueSrc = fs.readlinkSync(destFile); + project_ref = `Plugins/${fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc))}`; } else { - project_ref = 'Plugins/' + fixPathSep(path.relative(project.plugins_dir, destFile)); + project_ref = `Plugins/${fixPathSep(path.relative(project.plugins_dir, destFile))}`; } - shell.rm('-rf', targetDir); + fs.removeSync(targetDir); if (type === 'header-file') { project.xcode.removeHeaderFile(project_ref); } else if (obj.framework) { - var project_relative = path.join(path.basename(project.xcode_path), project_ref); + const project_relative = path.join(path.basename(project.xcode_path), project_ref); project.xcode.removeFramework(project_relative); - project.xcode.removeFromLibrarySearchPaths({path: project_ref}); + project.xcode.removeFromLibrarySearchPaths({ path: project_ref }); } else { project.xcode.removeSourceFile(project_ref); } } -var pathSepFix = new RegExp(path.sep.replace(/\\/, '\\\\'), 'g'); +const pathSepFix = new RegExp(path.sep.replace(/\\/, '\\\\'), 'g'); function fixPathSep (file) { return file.replace(pathSepFix, '/'); } function copyFile (plugin_dir, src, project_dir, dest, link) { src = path.resolve(plugin_dir, src); - if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!'); + if (!fs.existsSync(src)) throw new CordovaError(`"${src}" not found!`); // check that src path is inside plugin directory - var real_path = fs.realpathSync(src); - var real_plugin_path = fs.realpathSync(plugin_dir); - if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); } + const real_path = fs.realpathSync(src); + const real_plugin_path = fs.realpathSync(plugin_dir); + if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError(`File "${src}" is located outside the plugin directory "${plugin_dir}"`); } dest = path.resolve(project_dir, dest); // check that dest path is located in project directory - if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); } + if (dest.indexOf(project_dir) !== 0) { throw new CordovaError(`Destination "${dest}" for source file "${src}" is located outside the project`); } - shell.mkdir('-p', path.dirname(dest)); + fs.ensureDirSync(path.dirname(dest)); if (link) { linkFileOrDirTree(src, dest); - } else if (fs.statSync(src).isDirectory()) { - // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq - shell.cp('-Rf', path.join(src, '/*'), dest); } else { - shell.cp('-f', src, dest); + fs.copySync(src, dest); } } // Same as copy file but throws error if target exists function copyNewFile (plugin_dir, src, project_dir, dest, link) { - var target_path = path.resolve(project_dir, dest); - if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); } + const target_path = path.resolve(project_dir, dest); + if (fs.existsSync(target_path)) { throw new CordovaError(`"${target_path}" already exists!`); } copyFile(plugin_dir, src, project_dir, dest, !!link); } function linkFileOrDirTree (src, dest) { if (fs.existsSync(dest)) { - shell.rm('-Rf', dest); + fs.removeSync(dest); } if (fs.statSync(src).isDirectory()) { - shell.mkdir('-p', dest); - fs.readdirSync(src).forEach(function (entry) { + fs.ensureDirSync(dest); + fs.readdirSync(src).forEach(entry => { linkFileOrDirTree(path.join(src, entry), path.join(dest, entry)); }); } else { @@ -365,24 +352,24 @@ function linkFileOrDirTree (src, dest) { // checks if file exists and then deletes. Error if doesn't exist function removeFile (project_dir, src) { - var file = path.resolve(project_dir, src); - shell.rm('-Rf', file); + const file = path.resolve(project_dir, src); + fs.removeSync(file); } // deletes file/directory without checking function removeFileF (file) { - shell.rm('-Rf', file); + fs.removeSync(file); } function removeFileAndParents (baseDir, destFile, stopper) { stopper = stopper || '.'; - var file = path.resolve(baseDir, destFile); + const file = path.resolve(baseDir, destFile); if (!fs.existsSync(file)) return; removeFileF(file); // check if directory is empty - var curDir = path.dirname(file); + let curDir = path.dirname(file); while (curDir !== path.resolve(baseDir, stopper)) { if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) { @@ -396,5 +383,5 @@ function removeFileAndParents (baseDir, destFile, stopper) { } function generateAttributeError (attribute, element, id) { - return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id; + return `Required attribute "${attribute}" not specified in <${element}> element from plugin: ${id}`; } diff --git a/StoneIsland/platforms/ios/cordova/lib/prepare.js b/StoneIsland/platforms/ios/cordova/lib/prepare.js index 17bbfeb7..c98cb8f4 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/prepare.js +++ b/StoneIsland/platforms/ios/cordova/lib/prepare.js @@ -18,53 +18,46 @@ */ 'use strict'; -var Q = require('q'); -var fs = require('fs'); -var path = require('path'); -var shell = require('shelljs'); -var xcode = require('xcode'); -var unorm = require('unorm'); -var plist = require('plist'); -var URL = require('url'); -var events = require('cordova-common').events; -var xmlHelpers = require('cordova-common').xmlHelpers; -var ConfigParser = require('cordova-common').ConfigParser; -var CordovaError = require('cordova-common').CordovaError; -var PlatformJson = require('cordova-common').PlatformJson; -var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger; -var PluginInfoProvider = require('cordova-common').PluginInfoProvider; -var FileUpdater = require('cordova-common').FileUpdater; -var projectFile = require('./projectFile'); + +const fs = require('fs-extra'); +const path = require('path'); +const unorm = require('unorm'); +const plist = require('plist'); +const URL = require('url'); +const events = require('cordova-common').events; +const xmlHelpers = require('cordova-common').xmlHelpers; +const ConfigParser = require('cordova-common').ConfigParser; +const CordovaError = require('cordova-common').CordovaError; +const PlatformJson = require('cordova-common').PlatformJson; +const PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger; +const PluginInfoProvider = require('cordova-common').PluginInfoProvider; +const FileUpdater = require('cordova-common').FileUpdater; +const projectFile = require('./projectFile'); // launch storyboard and related constants -var LAUNCHIMAGE_BUILD_SETTING = 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME'; -var LAUNCHIMAGE_BUILD_SETTING_VALUE = 'LaunchImage'; -var UI_LAUNCH_STORYBOARD_NAME = 'UILaunchStoryboardName'; -var CDV_LAUNCH_STORYBOARD_NAME = 'CDVLaunchScreen'; -var IMAGESET_COMPACT_SIZE_CLASS = 'compact'; -var CDV_ANY_SIZE_CLASS = 'any'; +const IMAGESET_COMPACT_SIZE_CLASS = 'compact'; +const CDV_ANY_SIZE_CLASS = 'any'; module.exports.prepare = function (cordovaProject, options) { - var self = this; - - var platformJson = PlatformJson.load(this.locations.root, 'ios'); - var munger = new PlatformMunger('ios', this.locations.root, platformJson, new PluginInfoProvider()); + const platformJson = PlatformJson.load(this.locations.root, 'ios'); + const munger = new PlatformMunger('ios', this.locations.root, platformJson, new PluginInfoProvider()); this._config = updateConfigFile(cordovaProject.projectConfig, munger, this.locations); // Update own www dir with project's www assets and plugins' assets and js-files - return Q.when(updateWww(cordovaProject, this.locations)) - .then(function () { - // update project according to config.xml changes. - return updateProject(self._config, self.locations); + return updateWww(cordovaProject, this.locations) + // update project according to config.xml changes. + .then(() => updateProject(this._config, this.locations)) + .then(() => { + updateIcons(cordovaProject, this.locations); + updateLaunchStoryboardImages(cordovaProject, this.locations); + updateBackgroundColor(cordovaProject, this.locations); + updateFileResources(cordovaProject, this.locations); }) - .then(function () { - updateIcons(cordovaProject, self.locations); - updateSplashScreens(cordovaProject, self.locations); - updateLaunchStoryboardImages(cordovaProject, self.locations); - updateFileResources(cordovaProject, self.locations); + .then(() => { + alertDeprecatedPreference(this._config); }) - .then(function () { + .then(() => { events.emit('verbose', 'Prepared iOS project successfully'); }); }; @@ -74,22 +67,21 @@ module.exports.clean = function (options) { // been called from the platform shell script rather than the CLI. Check for the // noPrepare option passed in by the non-CLI clean script. If that's present, or if // there's no config.xml found at the project root, then don't clean prepared files. - var projectRoot = path.resolve(this.root, '../..'); - var projectConfigFile = path.join(projectRoot, 'config.xml'); + const projectRoot = path.resolve(this.root, '../..'); + const projectConfigFile = path.join(projectRoot, 'config.xml'); if ((options && options.noPrepare) || !fs.existsSync(projectConfigFile) || !fs.existsSync(this.locations.configXml)) { - return Q(); + return Promise.resolve(); } - var projectConfig = new ConfigParser(this.locations.configXml); + const projectConfig = new ConfigParser(this.locations.configXml); - var self = this; - return Q().then(function () { - cleanWww(projectRoot, self.locations); - cleanIcons(projectRoot, projectConfig, self.locations); - cleanSplashScreens(projectRoot, projectConfig, self.locations); - cleanLaunchStoryboardImages(projectRoot, projectConfig, self.locations); - cleanFileResources(projectRoot, projectConfig, self.locations); + return Promise.resolve().then(() => { + cleanWww(projectRoot, this.locations); + cleanIcons(projectRoot, projectConfig, this.locations); + cleanLaunchStoryboardImages(projectRoot, projectConfig, this.locations); + cleanBackgroundColor(projectRoot, projectConfig, this.locations); + cleanFileResources(projectRoot, projectConfig, this.locations); }); }; @@ -108,11 +100,11 @@ module.exports.clean = function (options) { * configuration is already dumped to appropriate config.xml file. */ function updateConfigFile (sourceConfig, configMunger, locations) { - events.emit('verbose', 'Generating platform-specific config.xml from defaults for iOS at ' + locations.configXml); + events.emit('verbose', `Generating platform-specific config.xml from defaults for iOS at ${locations.configXml}`); // First cleanup current config and merge project's one into own // Overwrite platform config.xml with defaults.xml. - shell.cp('-f', locations.defaultConfigXml, locations.configXml); + fs.copySync(locations.defaultConfigXml, locations.configXml); // Then apply config changes from global munge to all config files // in project (including project's config) @@ -120,7 +112,7 @@ function updateConfigFile (sourceConfig, configMunger, locations) { events.emit('verbose', 'Merging project\'s config.xml into platform-specific iOS config.xml'); // Merge changes from app's config.xml into platform's one - var config = new ConfigParser(locations.configXml); + const config = new ConfigParser(locations.configXml); xmlHelpers.mergeXml(sourceConfig.doc.getroot(), config.doc.getroot(), 'ios', /* clobber= */true); @@ -132,7 +124,7 @@ function updateConfigFile (sourceConfig, configMunger, locations) { * Logs all file operations via the verbose event stream, indented. */ function logFileOp (message) { - events.emit('verbose', ' ' + message); + events.emit('verbose', ` ${message}`); } /** @@ -145,31 +137,33 @@ function logFileOp (message) { * paths for www files. */ function updateWww (cordovaProject, destinations) { - var sourceDirs = [ + const sourceDirs = [ path.relative(cordovaProject.root, cordovaProject.locations.www), path.relative(cordovaProject.root, destinations.platformWww) ]; // If project contains 'merges' for our platform, use them as another overrides - var merges_path = path.join(cordovaProject.root, 'merges', 'ios'); + const merges_path = path.join(cordovaProject.root, 'merges', 'ios'); if (fs.existsSync(merges_path)) { events.emit('verbose', 'Found "merges/ios" folder. Copying its contents into the iOS project.'); sourceDirs.push(path.join('merges', 'ios')); } - var targetDir = path.relative(cordovaProject.root, destinations.www); + const targetDir = path.relative(cordovaProject.root, destinations.www); events.emit( - 'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir); + 'verbose', `Merging and updating files from [${sourceDirs.join(', ')}] to ${targetDir}`); FileUpdater.mergeAndUpdateDir( sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp); + + return Promise.resolve(); } /** * Cleans all files from the platform 'www' directory. */ function cleanWww (projectRoot, locations) { - var targetDir = path.relative(projectRoot, locations.www); - events.emit('verbose', 'Cleaning ' + targetDir); + const targetDir = path.relative(projectRoot, locations.www); + events.emit('verbose', `Cleaning ${targetDir}`); // No source paths are specified, so mergeAndUpdateDir() will clear the target directory. FileUpdater.mergeAndUpdateDir( @@ -184,169 +178,176 @@ function cleanWww (projectRoot, locations) { * @param {Object} locations A map of locations for this platform (In/Out) */ function updateProject (platformConfig, locations) { - // CB-6992 it is necessary to normalize characters // because node and shell scripts handles unicode symbols differently // We need to normalize the name to NFD form since iOS uses NFD unicode form - var name = unorm.nfd(platformConfig.name()); - var pkg = platformConfig.getAttribute('ios-CFBundleIdentifier') || platformConfig.packageName(); - var version = platformConfig.version(); - var displayName = platformConfig.shortName && platformConfig.shortName(); + const name = unorm.nfd(platformConfig.name()); + const version = platformConfig.version(); + const displayName = platformConfig.shortName && platformConfig.shortName(); - var originalName = path.basename(locations.xcodeCordovaProj); + const originalName = path.basename(locations.xcodeCordovaProj); // Update package id (bundle id) - var plistFile = path.join(locations.xcodeCordovaProj, originalName + '-Info.plist'); - var infoPlist = plist.parse(fs.readFileSync(plistFile, 'utf8')); - infoPlist['CFBundleIdentifier'] = pkg; + const plistFile = path.join(locations.xcodeCordovaProj, `${originalName}-Info.plist`); + const infoPlist = plist.parse(fs.readFileSync(plistFile, 'utf8')); // Update version (bundle version) - infoPlist['CFBundleShortVersionString'] = version; - var CFBundleVersion = platformConfig.getAttribute('ios-CFBundleVersion') || default_CFBundleVersion(version); - infoPlist['CFBundleVersion'] = CFBundleVersion; + infoPlist.CFBundleShortVersionString = version; + const CFBundleVersion = platformConfig.getAttribute('ios-CFBundleVersion') || default_CFBundleVersion(version); + infoPlist.CFBundleVersion = CFBundleVersion; if (platformConfig.getAttribute('defaultlocale')) { - infoPlist['CFBundleDevelopmentRegion'] = platformConfig.getAttribute('defaultlocale'); + infoPlist.CFBundleDevelopmentRegion = platformConfig.getAttribute('defaultlocale'); } if (displayName) { - infoPlist['CFBundleDisplayName'] = displayName; + infoPlist.CFBundleDisplayName = displayName; } // replace Info.plist ATS entries according to <access> and <allow-navigation> config.xml entries - var ats = writeATSEntries(platformConfig); + const ats = writeATSEntries(platformConfig); if (Object.keys(ats).length > 0) { - infoPlist['NSAppTransportSecurity'] = ats; + infoPlist.NSAppTransportSecurity = ats; } else { - delete infoPlist['NSAppTransportSecurity']; + delete infoPlist.NSAppTransportSecurity; } handleOrientationSettings(platformConfig, infoPlist); - updateProjectPlistForLaunchStoryboard(platformConfig, infoPlist); - var info_contents = plist.build(infoPlist); + /* eslint-disable no-tabs */ + // Write out the plist file with the same formatting as Xcode does + let info_contents = plist.build(infoPlist, { indent: '\t', offset: -1 }); + /* eslint-enable no-tabs */ + info_contents = info_contents.replace(/<string>[\s\r\n]*<\/string>/g, '<string></string>'); fs.writeFileSync(plistFile, info_contents, 'utf-8'); - events.emit('verbose', 'Wrote out iOS Bundle Identifier "' + pkg + '" and iOS Bundle Version "' + version + '" to ' + plistFile); + events.emit('verbose', `Wrote out iOS Bundle Version "${version}" to ${plistFile}`); - return handleBuildSettings(platformConfig, locations, infoPlist).then(function () { + return handleBuildSettings(platformConfig, locations, infoPlist).then(() => { if (name === originalName) { - events.emit('verbose', 'iOS Product Name has not changed (still "' + originalName + '")'); - return Q(); + events.emit('verbose', `iOS Product Name has not changed (still "${originalName}")`); + return Promise.resolve(); } else { // CB-11712 <name> was changed, we don't support it' - var errorString = + const errorString = 'The product name change (<name> tag) in config.xml is not supported dynamically.\n' + 'To change your product name, you have to remove, then add your ios platform again.\n' + 'Make sure you save your plugins beforehand using `cordova plugin save`.\n' + '\tcordova plugin save\n' + '\tcordova platform rm ios\n' + - '\tcordova platform add ios\n' - ; + '\tcordova platform add ios\n'; - return Q.reject(new CordovaError(errorString)); + return Promise.reject(new CordovaError(errorString)); } }); } function handleOrientationSettings (platformConfig, infoPlist) { - switch (getOrientationValue(platformConfig)) { case 'portrait': - infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationPortrait' ]; - infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown' ]; - infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown' ]; + infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationPortrait']; + infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown']; + infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown']; break; case 'landscape': - infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationLandscapeLeft' ]; - infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; - infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; + infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationLandscapeLeft']; + infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; + infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; break; case 'all': - infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationPortrait' ]; - infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; - infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; + infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationPortrait']; + infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; + infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; break; case 'default': - infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; - infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ]; - delete infoPlist['UIInterfaceOrientation']; + infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; + infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']; + delete infoPlist.UIInterfaceOrientation; } } function handleBuildSettings (platformConfig, locations, infoPlist) { - var targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios')); - var deploymentTarget = platformConfig.getPreference('deployment-target', 'ios'); - var needUpdatedBuildSettingsForLaunchStoryboard = checkIfBuildSettingsNeedUpdatedForLaunchStoryboard(platformConfig, infoPlist); + const pkg = platformConfig.getAttribute('ios-CFBundleIdentifier') || platformConfig.packageName(); + const targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios')); + const deploymentTarget = platformConfig.getPreference('deployment-target', 'ios'); + const swiftVersion = platformConfig.getPreference('SwiftVersion', 'ios'); + + let project; + + try { + project = projectFile.parse(locations); + } catch (err) { + return Promise.reject(new CordovaError(`Could not parse ${locations.pbxproj}: ${err}`)); + } + + const origPkg = project.xcode.getBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', undefined, platformConfig.name()); // no build settings provided and we don't need to update build settings for launch storyboards, // then we don't need to parse and update .pbxproj file - if (!targetDevice && !deploymentTarget && !needUpdatedBuildSettingsForLaunchStoryboard) { - return Q(); + if (origPkg === pkg && !targetDevice && !deploymentTarget && !swiftVersion) { + return Promise.resolve(); } - var proj = new xcode.project(locations.pbxproj); /* eslint new-cap : 0 */ - - try { - proj.parseSync(); - } catch (err) { - return Q.reject(new CordovaError('Could not parse project.pbxproj: ' + err)); + if (origPkg !== pkg) { + events.emit('verbose', `Set PRODUCT_BUNDLE_IDENTIFIER to ${pkg}.`); + project.xcode.updateBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', pkg, null, platformConfig.name()); } if (targetDevice) { - events.emit('verbose', 'Set TARGETED_DEVICE_FAMILY to ' + targetDevice + '.'); - proj.updateBuildProperty('TARGETED_DEVICE_FAMILY', targetDevice); + events.emit('verbose', `Set TARGETED_DEVICE_FAMILY to ${targetDevice}.`); + project.xcode.updateBuildProperty('TARGETED_DEVICE_FAMILY', targetDevice); } if (deploymentTarget) { - events.emit('verbose', 'Set IPHONEOS_DEPLOYMENT_TARGET to "' + deploymentTarget + '".'); - proj.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget); + events.emit('verbose', `Set IPHONEOS_DEPLOYMENT_TARGET to "${deploymentTarget}".`); + project.xcode.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget); } - updateBuildSettingsForLaunchStoryboard(proj, platformConfig, infoPlist); + if (swiftVersion) { + events.emit('verbose', `Set SwiftVersion to "${swiftVersion}".`); + project.xcode.updateBuildProperty('SWIFT_VERSION', swiftVersion); + } - fs.writeFileSync(locations.pbxproj, proj.writeSync(), 'utf-8'); + project.write(); - return Q(); + return Promise.resolve(); } function mapIconResources (icons, iconsDir) { // See https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html // for launch images sizes reference. - var platformIcons = [ - {dest: 'icon-20.png', width: 20, height: 20}, - {dest: 'icon-20@2x.png', width: 40, height: 40}, - {dest: 'icon-20@3x.png', width: 60, height: 60}, - {dest: 'icon-40.png', width: 40, height: 40}, - {dest: 'icon-50.png', width: 50, height: 50}, - {dest: 'icon-50@2x.png', width: 100, height: 100}, - {dest: 'icon-60@2x.png', width: 120, height: 120}, - {dest: 'icon-60@3x.png', width: 180, height: 180}, - {dest: 'icon-72.png', width: 72, height: 72}, - {dest: 'icon-72@2x.png', width: 144, height: 144}, - {dest: 'icon-76.png', width: 76, height: 76}, - {dest: 'icon-76@2x.png', width: 152, height: 152}, - {dest: 'icon-83.5@2x.png', width: 167, height: 167}, - {dest: 'icon-1024.png', width: 1024, height: 1024}, - {dest: 'icon-small.png', width: 29, height: 29}, - {dest: 'icon-small@2x.png', width: 58, height: 58}, - {dest: 'icon-small@3x.png', width: 87, height: 87}, - {dest: 'icon.png', width: 57, height: 57}, - {dest: 'icon@2x.png', width: 114, height: 114}, - {dest: 'AppIcon24x24@2x.png', width: 48, height: 48}, - {dest: 'AppIcon27.5x27.5@2x.png', width: 55, height: 55}, - {dest: 'AppIcon29x29@2x.png', width: 58, height: 58}, - {dest: 'AppIcon29x29@3x.png', width: 87, height: 87}, - {dest: 'AppIcon40x40@2x.png', width: 80, height: 80}, - {dest: 'AppIcon44x44@2x.png', width: 88, height: 88}, - {dest: 'AppIcon86x86@2x.png', width: 172, height: 172}, - {dest: 'AppIcon98x98@2x.png', width: 196, height: 196} + const platformIcons = [ + { dest: 'icon-20.png', width: 20, height: 20 }, + { dest: 'icon-20@2x.png', width: 40, height: 40 }, + { dest: 'icon-20@3x.png', width: 60, height: 60 }, + { dest: 'icon-40.png', width: 40, height: 40 }, + { dest: 'icon-40@2x.png', width: 80, height: 80 }, + { dest: 'icon-50.png', width: 50, height: 50 }, + { dest: 'icon-50@2x.png', width: 100, height: 100 }, + { dest: 'icon-60@2x.png', width: 120, height: 120 }, + { dest: 'icon-60@3x.png', width: 180, height: 180 }, + { dest: 'icon-72.png', width: 72, height: 72 }, + { dest: 'icon-72@2x.png', width: 144, height: 144 }, + { dest: 'icon-76.png', width: 76, height: 76 }, + { dest: 'icon-76@2x.png', width: 152, height: 152 }, + { dest: 'icon-83.5@2x.png', width: 167, height: 167 }, + { dest: 'icon-1024.png', width: 1024, height: 1024 }, + { dest: 'icon-29.png', width: 29, height: 29 }, + { dest: 'icon-29@2x.png', width: 58, height: 58 }, + { dest: 'icon-29@3x.png', width: 87, height: 87 }, + { dest: 'icon.png', width: 57, height: 57 }, + { dest: 'icon@2x.png', width: 114, height: 114 }, + { dest: 'icon-24@2x.png', width: 48, height: 48 }, + { dest: 'icon-27.5@2x.png', width: 55, height: 55 }, + { dest: 'icon-44@2x.png', width: 88, height: 88 }, + { dest: 'icon-86@2x.png', width: 172, height: 172 }, + { dest: 'icon-98@2x.png', width: 196, height: 196 } ]; - var pathMap = {}; - platformIcons.forEach(function (item) { - var icon = icons.getBySize(item.width, item.height) || icons.getDefault(); + const pathMap = {}; + platformIcons.forEach(item => { + const icon = icons.getBySize(item.width, item.height) || icons.getDefault(); if (icon) { - var target = path.join(iconsDir, item.dest); + const target = path.join(iconsDir, item.dest); pathMap[target] = icon.src; } }); @@ -354,8 +355,8 @@ function mapIconResources (icons, iconsDir) { } function getIconsDir (projectRoot, platformProjDir) { - var iconsDir; - var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/')); + let iconsDir; + const xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/')); if (xcassetsExists) { iconsDir = path.join(platformProjDir, 'Images.xcassets/AppIcon.appiconset/'); @@ -367,31 +368,31 @@ function getIconsDir (projectRoot, platformProjDir) { } function updateIcons (cordovaProject, locations) { - var icons = cordovaProject.projectConfig.getIcons('ios'); + const icons = cordovaProject.projectConfig.getIcons('ios'); if (icons.length === 0) { events.emit('verbose', 'This app does not have icons defined'); return; } - var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); - var iconsDir = getIconsDir(cordovaProject.root, platformProjDir); - var resourceMap = mapIconResources(icons, iconsDir); - events.emit('verbose', 'Updating icons at ' + iconsDir); + const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); + const iconsDir = getIconsDir(cordovaProject.root, platformProjDir); + const resourceMap = mapIconResources(icons, iconsDir); + events.emit('verbose', `Updating icons at ${iconsDir}`); FileUpdater.updatePaths( resourceMap, { rootDir: cordovaProject.root }, logFileOp); } function cleanIcons (projectRoot, projectConfig, locations) { - var icons = projectConfig.getIcons('ios'); + const icons = projectConfig.getIcons('ios'); if (icons.length > 0) { - var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); - var iconsDir = getIconsDir(projectRoot, platformProjDir); - var resourceMap = mapIconResources(icons, iconsDir); - Object.keys(resourceMap).forEach(function (targetIconPath) { + const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); + const iconsDir = getIconsDir(projectRoot, platformProjDir); + const resourceMap = mapIconResources(icons, iconsDir); + Object.keys(resourceMap).forEach(targetIconPath => { resourceMap[targetIconPath] = null; }); - events.emit('verbose', 'Cleaning icons at ' + iconsDir); + events.emit('verbose', `Cleaning icons at ${iconsDir}`); // Source paths are removed from the map, so updatePaths() will delete the target files. FileUpdater.updatePaths( @@ -399,74 +400,120 @@ function cleanIcons (projectRoot, projectConfig, locations) { } } -function mapSplashScreenResources (splashScreens, splashScreensDir) { - var platformSplashScreens = [ - {dest: 'Default~iphone.png', width: 320, height: 480}, - {dest: 'Default@2x~iphone.png', width: 640, height: 960}, - {dest: 'Default-Portrait~ipad.png', width: 768, height: 1024}, - {dest: 'Default-Portrait@2x~ipad.png', width: 1536, height: 2048}, - {dest: 'Default-Landscape~ipad.png', width: 1024, height: 768}, - {dest: 'Default-Landscape@2x~ipad.png', width: 2048, height: 1536}, - {dest: 'Default-568h@2x~iphone.png', width: 640, height: 1136}, - {dest: 'Default-667h.png', width: 750, height: 1334}, - {dest: 'Default-736h.png', width: 1242, height: 2208}, - {dest: 'Default-Landscape-736h.png', width: 2208, height: 1242} - ]; - - var pathMap = {}; - platformSplashScreens.forEach(function (item) { - var splash = splashScreens.getBySize(item.width, item.height); - if (splash) { - var target = path.join(splashScreensDir, item.dest); - pathMap[target] = splash.src; - } - }); - return pathMap; +/** + * Returns the directory for the BackgroundColor.colorset asset, or null if no + * xcassets exist. + * + * @param {string} projectRoot The project's root directory + * @param {string} platformProjDir The platform's project directory + */ +function getBackgroundColorDir (projectRoot, platformProjDir) { + if (folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'))) { + return path.join(platformProjDir, 'Images.xcassets', 'BackgroundColor.colorset'); + } else { + return null; + } } -function getSplashScreensDir (projectRoot, platformProjDir) { - var splashScreensDir; - var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/')); +function colorPreferenceToComponents (pref) { + if (!pref || !pref.match(/^(#[0-9A-F]{3}|(0x|#)([0-9A-F]{2})?[0-9A-F]{6})$/)) { + return { + platform: 'ios', + reference: 'systemBackgroundColor' + }; + } - if (xcassetsExists) { - splashScreensDir = path.join(platformProjDir, 'Images.xcassets/LaunchImage.launchimage/'); - } else { - splashScreensDir = path.join(platformProjDir, 'Resources/splash/'); + let red = 'FF'; + let green = 'FF'; + let blue = 'FF'; + let alpha = 1.0; + + if (pref[0] === '#' && pref.length === 4) { + red = pref[1] + pref[1]; + green = pref[2] + pref[2]; + blue = pref[3] + pref[3]; } - return splashScreensDir; -} + if (pref.length >= 7 && (pref[0] === '#' || pref.substring(0, 2) === '0x')) { + let offset = pref[0] === '#' ? 1 : 2; -function updateSplashScreens (cordovaProject, locations) { - var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios'); + if (pref.substring(offset).length === 8) { + alpha = parseInt(pref.substring(offset, offset + 2), 16) / 255.0; + offset += 2; + } - if (splashScreens.length === 0) { - events.emit('verbose', 'This app does not have splash screens defined'); - return; + red = pref.substring(offset, offset + 2); + green = pref.substring(offset + 2, offset + 4); + blue = pref.substring(offset + 4, offset + 6); } - var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); - var splashScreensDir = getSplashScreensDir(cordovaProject.root, platformProjDir); - var resourceMap = mapSplashScreenResources(splashScreens, splashScreensDir); - events.emit('verbose', 'Updating splash screens at ' + splashScreensDir); - FileUpdater.updatePaths( - resourceMap, { rootDir: cordovaProject.root }, logFileOp); + return { + 'color-space': 'srgb', + components: { + red: '0x' + red, + green: '0x' + green, + blue: '0x' + blue, + alpha: alpha.toFixed(3) + } + }; } -function cleanSplashScreens (projectRoot, projectConfig, locations) { - var splashScreens = projectConfig.getSplashScreens('ios'); - if (splashScreens.length > 0) { - var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); - var splashScreensDir = getSplashScreensDir(projectRoot, platformProjDir); - var resourceMap = mapIconResources(splashScreens, splashScreensDir); - Object.keys(resourceMap).forEach(function (targetSplashPath) { - resourceMap[targetSplashPath] = null; - }); - events.emit('verbose', 'Cleaning splash screens at ' + splashScreensDir); +/** + * Update the background color Contents.json in xcassets. + * + * @param {Object} cordovaProject The cordova project + * @param {Object} locations A dictionary containing useful location paths + */ +function updateBackgroundColor (cordovaProject, locations) { + const pref = cordovaProject.projectConfig.getPreference('BackgroundColor', 'ios') || ''; - // Source paths are removed from the map, so updatePaths() will delete the target files. - FileUpdater.updatePaths( - resourceMap, { rootDir: projectRoot, all: true }, logFileOp); + const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); + const backgroundColorDir = getBackgroundColorDir(cordovaProject.root, platformProjDir); + + if (backgroundColorDir) { + const contentsJSON = { + colors: [{ + idiom: 'universal', + color: colorPreferenceToComponents(pref) + }], + info: { + author: 'Xcode', + version: 1 + } + }; + + events.emit('verbose', 'Updating Background Color color set Contents.json'); + fs.writeFileSync(path.join(cordovaProject.root, backgroundColorDir, 'Contents.json'), + JSON.stringify(contentsJSON, null, 2)); + } +} + +/** + * Resets the background color Contents.json in xcassets to default. + * + * @param {string} projectRoot Path to the project root + * @param {Object} projectConfig The project's config.xml + * @param {Object} locations A dictionary containing useful location paths + */ +function cleanBackgroundColor (projectRoot, projectConfig, locations) { + const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); + const backgroundColorDir = getBackgroundColorDir(projectRoot, platformProjDir); + + if (backgroundColorDir) { + const contentsJSON = { + colors: [{ + idiom: 'universal', + color: colorPreferenceToComponents(null) + }], + info: { + author: 'Xcode', + version: 1 + } + }; + + events.emit('verbose', 'Cleaning Background Color color set Contents.json'); + fs.writeFileSync(path.join(projectRoot, backgroundColorDir, 'Contents.json'), + JSON.stringify(contentsJSON, null, 2)); } } @@ -482,9 +529,9 @@ function updateFileResources (cordovaProject, locations) { return; } - let resourceMap = {}; - files.forEach(function (res) { - let src = res.src; + const resourceMap = {}; + files.forEach(res => { + const src = res.src; let target = res.target; if (!target) { @@ -494,29 +541,75 @@ function updateFileResources (cordovaProject, locations) { let targetPath = path.join(project.resources_dir, target); targetPath = path.relative(cordovaProject.root, targetPath); - project.xcode.addResourceFile(target); + if (!fs.existsSync(targetPath)) { + project.xcode.addResourceFile(target); + } else { + events.emit('warn', `Overwriting existing resource file at ${targetPath}`); + } resourceMap[targetPath] = src; }); - events.emit('verbose', 'Updating resource files at ' + platformDir); + events.emit('verbose', `Updating resource files at ${platformDir}`); FileUpdater.updatePaths( resourceMap, { rootDir: cordovaProject.root }, logFileOp); project.write(); } +function alertDeprecatedPreference (configParser) { + const deprecatedToNewPreferences = { + MediaPlaybackRequiresUserAction: { + newPreference: 'MediaTypesRequiringUserActionForPlayback', + isDeprecated: true + }, + MediaPlaybackAllowsAirPlay: { + newPreference: 'AllowsAirPlayForMediaPlayback', + isDeprecated: false + } + }; + + Object.keys(deprecatedToNewPreferences).forEach(oldKey => { + if (configParser.getPreference(oldKey)) { + const isDeprecated = deprecatedToNewPreferences[oldKey].isDeprecated; + const verb = isDeprecated ? 'has been' : 'is being'; + const newPreferenceKey = deprecatedToNewPreferences[oldKey].newPreference; + + // Create the Log Message + const log = [`The preference name "${oldKey}" ${verb} deprecated.`]; + if (newPreferenceKey) { + log.push(`It is recommended to replace this preference with "${newPreferenceKey}."`); + } else { + log.push('There is no replacement for this preference.'); + } + + /** + * If the preference has been deprecated, the usage of the old preference is no longer used. + * Therefore, the following line is not appended. It is added only if the old preference is still used. + * We are only keeping the top lines for deprecated items only for an additional major release when + * the pre-warning was not provided in a past major release due to a necessary quick deprecation. + * Typically caused by implementation nature or third-party requirement changes. + */ + if (!isDeprecated) { + log.push('Please note that this preference will be removed in the near future.'); + } + + events.emit('warn', log.join(' ')); + } + }); +} + function cleanFileResources (projectRoot, projectConfig, locations) { const platformDir = path.relative(projectRoot, locations.root); const files = projectConfig.getFileResources('ios', true); if (files.length > 0) { - events.emit('verbose', 'Cleaning resource files at ' + platformDir); + events.emit('verbose', `Cleaning resource files at ${platformDir}`); const project = projectFile.parse(locations); - var resourceMap = {}; - files.forEach(function (res) { - let src = res.src; + const resourceMap = {}; + files.forEach(res => { + const src = res.src; let target = res.target; if (!target) { @@ -532,7 +625,7 @@ function cleanFileResources (projectRoot, projectConfig, locations) { }); FileUpdater.updatePaths( - resourceMap, {rootDir: projectRoot, all: true}, logFileOp); + resourceMap, { rootDir: projectRoot, all: true }, logFileOp); project.write(); } @@ -555,7 +648,8 @@ function cleanFileResources (projectRoot, projectConfig, locations) { * height: 'any|com', * filename: undefined|'Default@scale~idiom~widthheight.png', * src: undefined|'path/to/original/matched/image/from/splash/screens.png', - * target: undefined|'path/to/asset/library/Default@scale~idiom~widthheight.png' + * target: undefined|'path/to/asset/library/Default@scale~idiom~widthheight.png', + * appearence: undefined|'dark'|'light' * }, ... * ] * @@ -564,51 +658,54 @@ function cleanFileResources (projectRoot, projectConfig, locations) { * @return {Array<Object>} */ function mapLaunchStoryboardContents (splashScreens, launchStoryboardImagesDir) { - var platformLaunchStoryboardImages = []; - var idioms = ['universal', 'ipad', 'iphone']; - var scalesForIdiom = { + const platformLaunchStoryboardImages = []; + const idioms = ['universal', 'ipad', 'iphone']; + const scalesForIdiom = { universal: ['1x', '2x', '3x'], ipad: ['1x', '2x'], iphone: ['1x', '2x', '3x'] }; - var sizes = ['com', 'any']; + const sizes = ['com', 'any']; + const appearences = ['', 'dark', 'light']; - idioms.forEach(function (idiom) { - scalesForIdiom[idiom].forEach(function (scale) { - sizes.forEach(function (width) { - sizes.forEach(function (height) { - var item = { - idiom: idiom, - scale: scale, - width: width, - height: height - }; + idioms.forEach(idiom => { + scalesForIdiom[idiom].forEach(scale => { + sizes.forEach(width => { + sizes.forEach(height => { + appearences.forEach(appearence => { + const item = { idiom, scale, width, height }; - /* examples of the search pattern: - * scale ~ idiom ~ width height - * @2x ~ universal ~ any any - * @3x ~ iphone ~ com any - * @2x ~ ipad ~ com any - */ - var searchPattern = '@' + scale + '~' + idiom + '~' + width + height; + if (appearence !== '') { + item.appearence = appearence; + } - /* because old node versions don't have Array.find, the below is - * functionally equivalent to this: - * var launchStoryboardImage = splashScreens.find(function(item) { - * return item.src.indexOf(searchPattern) >= 0; - * }); - */ - var launchStoryboardImage = splashScreens.reduce(function (p, c) { - return (c.src.indexOf(searchPattern) >= 0) ? c : p; - }, undefined); + /* examples of the search pattern: + * scale ~ idiom ~ width height ~ appearence + * @2x ~ universal ~ any any + * @3x ~ iphone ~ com any ~ dark + * @2x ~ ipad ~ com any ~ light + */ + const searchPattern = '@' + scale + '~' + idiom + '~' + width + height + (appearence ? '~' + appearence : ''); - if (launchStoryboardImage) { - item.filename = 'Default' + searchPattern + '.png'; - item.src = launchStoryboardImage.src; - item.target = path.join(launchStoryboardImagesDir, item.filename); - } + /* because old node versions don't have Array.find, the below is + * functionally equivalent to this: + * var launchStoryboardImage = splashScreens.find(function(item) { + * return (item.src.indexOf(searchPattern) >= 0) ? (appearence !== '' ? true : ((item.src.indexOf(searchPattern + '~light') >= 0 || (item.src.indexOf(searchPattern + '~dark') >= 0)) ? false : true)) : false; + * }); + */ + const launchStoryboardImage = splashScreens.reduce( + (p, c) => (c.src.indexOf(searchPattern) >= 0) ? (appearence !== '' ? c : ((c.src.indexOf(searchPattern + '~light') >= 0 || (c.src.indexOf(searchPattern + '~dark') >= 0)) ? p : c)) : p, + undefined + ); - platformLaunchStoryboardImages.push(item); + if (launchStoryboardImage) { + item.filename = `Default${searchPattern}.png`; + item.src = launchStoryboardImage.src; + item.target = path.join(launchStoryboardImagesDir, item.filename); + } + + platformLaunchStoryboardImages.push(item); + }); }); }); }); @@ -632,9 +729,9 @@ function mapLaunchStoryboardContents (splashScreens, launchStoryboardImagesDir) * @return {Object} */ function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir) { - var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir); - var pathMap = {}; - platformLaunchStoryboardImages.forEach(function (item) { + const platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir); + const pathMap = {}; + platformLaunchStoryboardImages.forEach(item => { if (item.target) { pathMap[item.target] = item.src; } @@ -654,6 +751,7 @@ function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir) * scale: '1x|2x|3x', * width-class: undefined|'compact', * height-class: undefined|'compact' + * ... * }, ... * ], * info: { @@ -670,17 +768,16 @@ function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir) * @return {Object} */ function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesDir) { - - var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir); - var contentsJSON = { + const platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir); + const contentsJSON = { images: [], info: { author: 'Xcode', version: 1 } }; - contentsJSON.images = platformLaunchStoryboardImages.map(function (item) { - var newItem = { + contentsJSON.images = platformLaunchStoryboardImages.map(item => { + const newItem = { idiom: item.idiom, scale: item.scale }; @@ -694,6 +791,10 @@ function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesD newItem['height-class'] = IMAGESET_COMPACT_SIZE_CLASS; } + if (item.appearence) { + newItem.appearances = [{ appearance: 'luminosity', value: item.appearence }]; + } + // Xcode doesn't want a filename property if there's no image for these traits if (item.filename) { newItem.filename = item.filename; @@ -704,107 +805,6 @@ function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesD } /** - * Determines if the project's build settings may need to be updated for launch storyboard support - * - */ -function checkIfBuildSettingsNeedUpdatedForLaunchStoryboard (platformConfig, infoPlist) { - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig); - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - - if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) { - // don't need legacy launch images if we are using our launch storyboard - // so we do need to update the project file - events.emit('verbose', 'Need to update build settings because project is using our launch storyboard.'); - return true; - } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) { - // we do need to ensure legacy launch images are used if there's no launch storyboard present - // so we do need to update the project file - events.emit('verbose', 'Need to update build settings because project is using legacy launch images and no storyboard.'); - return true; - } - events.emit('verbose', 'No need to update build settings for launch storyboard support.'); - return false; -} - -function updateBuildSettingsForLaunchStoryboard (proj, platformConfig, infoPlist) { - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig); - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - - if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) { - // don't need legacy launch images if we are using our launch storyboard - events.emit('verbose', 'Removed ' + LAUNCHIMAGE_BUILD_SETTING + ' because project is using our launch storyboard.'); - proj.removeBuildProperty(LAUNCHIMAGE_BUILD_SETTING); - } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) { - // we do need to ensure legacy launch images are used if there's no launch storyboard present - events.emit('verbose', 'Set ' + LAUNCHIMAGE_BUILD_SETTING + ' to ' + LAUNCHIMAGE_BUILD_SETTING_VALUE + ' because project is using legacy launch images and no storyboard.'); - proj.updateBuildProperty(LAUNCHIMAGE_BUILD_SETTING, LAUNCHIMAGE_BUILD_SETTING_VALUE); - } else { - events.emit('verbose', 'Did not update build settings for launch storyboard support.'); - } -} - -function splashScreensHaveLaunchStoryboardImages (contentsJSON) { - /* do we have any launch images do we have for our launch storyboard? - * Again, for old Node versions, the below code is equivalent to this: - * return !!contentsJSON.images.find(function (item) { - * return item.filename !== undefined; - * }); - */ - return !!contentsJSON.images.reduce(function (p, c) { - return (c.filename !== undefined) ? c : p; - }, undefined); -} - -function platformHasLaunchStoryboardImages (platformConfig) { - var splashScreens = platformConfig.getSplashScreens('ios'); - var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, ''); // note: we don't need a file path here; we're just counting - return splashScreensHaveLaunchStoryboardImages(contentsJSON); -} - -function platformHasLegacyLaunchImages (platformConfig) { - var splashScreens = platformConfig.getSplashScreens('ios'); - return !!splashScreens.reduce(function (p, c) { - return (c.width !== undefined || c.height !== undefined) ? c : p; - }, undefined); -} - -/** - * Updates the project's plist based upon our launch storyboard images. If there are no images, then we should - * fall back to the regular launch images that might be supplied (that is, our app will be scaled on an iPad Pro), - * and if there are some images, we need to alter the UILaunchStoryboardName property to point to - * CDVLaunchScreen. - * - * There's some logic here to avoid overwriting changes the user might have made to their plist if they are using - * their own launch storyboard. - */ -function updateProjectPlistForLaunchStoryboard (platformConfig, infoPlist) { - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - events.emit('verbose', 'Current launch storyboard ' + currentLaunchStoryboard); - - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - - if (hasLaunchStoryboardImages && !currentLaunchStoryboard) { - // only change the launch storyboard if we have images to use AND the current value is blank - // if it's not blank, we've either done this before, or the user has their own launch storyboard - events.emit('verbose', 'Changing info plist to use our launch storyboard'); - infoPlist[UI_LAUNCH_STORYBOARD_NAME] = CDV_LAUNCH_STORYBOARD_NAME; - return; - } - - if (!hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME) { - // only revert to using the launch images if we have don't have any images for the launch storyboard - // but only clear it if current launch storyboard is our storyboard; the user might be using their - // own storyboard instead. - events.emit('verbose', 'Changing info plist to use legacy launch images'); - delete infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - return; - } - events.emit('verbose', 'Not changing launch storyboard setting in info plist.'); -} - -/** * Returns the directory for the Launch Storyboard image set, if image sets are being used. If they aren't * being used, returns null. * @@ -812,8 +812,8 @@ function updateProjectPlistForLaunchStoryboard (platformConfig, infoPlist) { * @param {string} platformProjDir The platform's project directory */ function getLaunchStoryboardImagesDir (projectRoot, platformProjDir) { - var launchStoryboardImagesDir; - var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/')); + let launchStoryboardImagesDir; + const xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/')); if (xcassetsExists) { launchStoryboardImagesDir = path.join(platformProjDir, 'Images.xcassets/LaunchStoryboard.imageset/'); @@ -832,15 +832,15 @@ function getLaunchStoryboardImagesDir (projectRoot, platformProjDir) { * @param {Object} locations A dictionary containing useful location paths */ function updateLaunchStoryboardImages (cordovaProject, locations) { - var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios'); - var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); - var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(cordovaProject.root, platformProjDir); + const splashScreens = cordovaProject.projectConfig.getSplashScreens('ios'); + const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj); + const launchStoryboardImagesDir = getLaunchStoryboardImagesDir(cordovaProject.root, platformProjDir); if (launchStoryboardImagesDir) { - var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir); - var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir); + const resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir); + const contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir); - events.emit('verbose', 'Updating launch storyboard images at ' + launchStoryboardImagesDir); + events.emit('verbose', `Updating launch storyboard images at ${launchStoryboardImagesDir}`); FileUpdater.updatePaths( resourceMap, { rootDir: cordovaProject.root }, logFileOp); @@ -859,24 +859,24 @@ function updateLaunchStoryboardImages (cordovaProject, locations) { * @param {Object} locations A dictionary containing useful location paths */ function cleanLaunchStoryboardImages (projectRoot, projectConfig, locations) { - var splashScreens = projectConfig.getSplashScreens('ios'); - var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); - var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(projectRoot, platformProjDir); + const splashScreens = projectConfig.getSplashScreens('ios'); + const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj); + const launchStoryboardImagesDir = getLaunchStoryboardImagesDir(projectRoot, platformProjDir); if (launchStoryboardImagesDir) { - var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir); - var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir); + const resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir); + const contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir); - Object.keys(resourceMap).forEach(function (targetPath) { + Object.keys(resourceMap).forEach(targetPath => { resourceMap[targetPath] = null; }); - events.emit('verbose', 'Cleaning storyboard image set at ' + launchStoryboardImagesDir); + events.emit('verbose', `Cleaning storyboard image set at ${launchStoryboardImagesDir}`); // Source paths are removed from the map, so updatePaths() will delete the target files. FileUpdater.updatePaths( resourceMap, { rootDir: projectRoot, all: true }, logFileOp); // delete filename from contents.json - contentsJSON.images.forEach(function (image) { + contentsJSON.images.forEach(image => { image.filename = undefined; }); @@ -896,10 +896,9 @@ function cleanLaunchStoryboardImages (projectRoot, projectConfig, locations) { * (or empty string if both are undefined). */ function getOrientationValue (platformConfig) { + const ORIENTATION_DEFAULT = 'default'; - var ORIENTATION_DEFAULT = 'default'; - - var orientation = platformConfig.getPreference('orientation'); + let orientation = platformConfig.getPreference('orientation'); if (!orientation) { return ''; } @@ -911,8 +910,7 @@ function getOrientationValue (platformConfig) { return orientation; } - events.emit('warn', 'Unrecognized value for Orientation preference: ' + orientation + - '. Defaulting to value: ' + ORIENTATION_DEFAULT + '.'); + events.emit('warn', `Unrecognized value for Orientation preference: ${orientation}. Defaulting to value: ${ORIENTATION_DEFAULT}.`); return ORIENTATION_DEFAULT; } @@ -938,20 +936,20 @@ function getOrientationValue (platformConfig) { } */ function processAccessAndAllowNavigationEntries (config) { - var accesses = config.getAccesses(); - var allow_navigations = config.getAllowNavigations(); + const accesses = config.getAccesses(); + const allow_navigations = config.getAllowNavigations(); return allow_navigations - // we concat allow_navigations and accesses, after processing accesses - .concat(accesses.map(function (obj) { + // we concat allow_navigations and accesses, after processing accesses + .concat(accesses.map(obj => { // map accesses to a common key interface using 'href', not origin obj.href = obj.origin; delete obj.origin; return obj; })) // we reduce the array to an object with all the entries processed (key is Hostname) - .reduce(function (previousReturn, currentElement) { - var options = { + .reduce((previousReturn, currentElement) => { + const options = { minimum_tls_version: currentElement.minimum_tls_version, requires_forward_secrecy: currentElement.requires_forward_secrecy, requires_certificate_transparency: currentElement.requires_certificate_transparency, @@ -959,16 +957,16 @@ function processAccessAndAllowNavigationEntries (config) { allows_arbitrary_loads_in_web_content: currentElement.allows_arbitrary_loads_in_web_content, allows_local_networking: currentElement.allows_local_networking }; - var obj = parseWhitelistUrlForATS(currentElement.href, options); + const obj = parseWhitelistUrlForATS(currentElement.href, options); if (obj) { // we 'union' duplicate entries - var item = previousReturn[obj.Hostname]; + let item = previousReturn[obj.Hostname]; if (!item) { item = {}; } - for (var o in obj) { - if (obj.hasOwnProperty(o)) { + for (const o in obj) { + if (Object.prototype.hasOwnProperty.call(obj, o)) { item[o] = obj[o]; } } @@ -999,15 +997,16 @@ function processAccessAndAllowNavigationEntries (config) { null is returned if the URL cannot be parsed, or is to be skipped for ATS. */ function parseWhitelistUrlForATS (url, options) { - var href = URL.parse(url); - var retObj = {}; + // @todo 'url.parse' was deprecated since v11.0.0. Use 'url.URL' constructor instead. + const href = URL.parse(url); // eslint-disable-line + const retObj = {}; retObj.Hostname = href.hostname; // Guiding principle: we only set values in retObj if they are NOT the default if (url === '*') { retObj.Hostname = '*'; - var val; + let val; val = (options.allows_arbitrary_loads_in_web_content === 'true'); if (options.allows_arbitrary_loads_in_web_content && val) { // default is false @@ -1029,10 +1028,12 @@ function parseWhitelistUrlForATS (url, options) { if (!retObj.Hostname) { // check origin, if it allows subdomains (wildcard in hostname), we set NSIncludesSubdomains to YES. Default is NO - var subdomain1 = '/*.'; // wildcard in hostname - var subdomain2 = '*://*.'; // wildcard in hostname and protocol - var subdomain3 = '*://'; // wildcard in protocol only - if (href.pathname.indexOf(subdomain1) === 0) { + const subdomain1 = '/*.'; // wildcard in hostname + const subdomain2 = '*://*.'; // wildcard in hostname and protocol + const subdomain3 = '*://'; // wildcard in protocol only + if (!href.pathname) { + return null; + } else if (href.pathname.indexOf(subdomain1) === 0) { retObj.NSIncludesSubdomains = true; retObj.Hostname = href.pathname.substring(subdomain1.length); } else if (href.pathname.indexOf(subdomain2) === 0) { @@ -1050,12 +1051,12 @@ function parseWhitelistUrlForATS (url, options) { retObj.NSExceptionMinimumTLSVersion = options.minimum_tls_version; } - var rfs = (options.requires_forward_secrecy === 'true'); + const rfs = (options.requires_forward_secrecy === 'true'); if (options.requires_forward_secrecy && !rfs) { // default is true retObj.NSExceptionRequiresForwardSecrecy = false; } - var rct = (options.requires_certificate_transparency === 'true'); + const rct = (options.requires_certificate_transparency === 'true'); if (options.requires_certificate_transparency && rct) { // default is false retObj.NSRequiresCertificateTransparency = true; } @@ -1075,48 +1076,48 @@ function parseWhitelistUrlForATS (url, options) { in config.xml */ function writeATSEntries (config) { - var pObj = processAccessAndAllowNavigationEntries(config); + const pObj = processAccessAndAllowNavigationEntries(config); - var ats = {}; + const ats = {}; - for (var hostname in pObj) { - if (pObj.hasOwnProperty(hostname)) { - var entry = pObj[hostname]; + for (const hostname in pObj) { + if (Object.prototype.hasOwnProperty.call(pObj, hostname)) { + const entry = pObj[hostname]; // Guiding principle: we only set values if they are available if (hostname === '*') { // always write this, for iOS 9, since in iOS 10 it will be overriden if // any of the other three keys are written - ats['NSAllowsArbitraryLoads'] = true; + ats.NSAllowsArbitraryLoads = true; // at least one of the overriding keys is present if (entry.NSAllowsArbitraryLoadsInWebContent) { - ats['NSAllowsArbitraryLoadsInWebContent'] = true; + ats.NSAllowsArbitraryLoadsInWebContent = true; } if (entry.NSAllowsArbitraryLoadsForMedia) { - ats['NSAllowsArbitraryLoadsForMedia'] = true; + ats.NSAllowsArbitraryLoadsForMedia = true; } if (entry.NSAllowsLocalNetworking) { - ats['NSAllowsLocalNetworking'] = true; + ats.NSAllowsLocalNetworking = true; } continue; } - var exceptionDomain = {}; + const exceptionDomain = {}; - for (var key in entry) { - if (entry.hasOwnProperty(key) && key !== 'Hostname') { + for (const key in entry) { + if (Object.prototype.hasOwnProperty.call(entry, key) && key !== 'Hostname') { exceptionDomain[key] = entry[key]; } } - if (!ats['NSExceptionDomains']) { - ats['NSExceptionDomains'] = {}; + if (!ats.NSExceptionDomains) { + ats.NSExceptionDomains = {}; } - ats['NSExceptionDomains'][hostname] = exceptionDomain; + ats.NSExceptionDomains[hostname] = exceptionDomain; } } @@ -1125,7 +1126,7 @@ function writeATSEntries (config) { function folderExists (folderPath) { try { - var stat = fs.statSync(folderPath); + const stat = fs.statSync(folderPath); return stat && stat.isDirectory(); } catch (e) { return false; @@ -1141,10 +1142,10 @@ function default_CFBundleVersion (version) { // Converts cordova specific representation of target device to XCode value function parseTargetDevicePreference (value) { if (!value) return null; - var map = {'universal': '"1,2"', 'handset': '"1"', 'tablet': '"2"'}; + const map = { universal: '"1,2"', handset: '"1"', tablet: '"2"' }; if (map[value.toLowerCase()]) { return map[value.toLowerCase()]; } - events.emit('warn', 'Unrecognized value for target-device preference: ' + value + '.'); + events.emit('warn', `Unrecognized value for target-device preference: ${value}.`); return null; } diff --git a/StoneIsland/platforms/ios/cordova/lib/projectFile.js b/StoneIsland/platforms/ios/cordova/lib/projectFile.js index 8a3f7e51..3e1e8304 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/projectFile.js +++ b/StoneIsland/platforms/ios/cordova/lib/projectFile.js @@ -17,47 +17,46 @@ under the License. */ -var xcode = require('xcode'); -var plist = require('plist'); -var _ = require('underscore'); -var path = require('path'); -var fs = require('fs'); -var shell = require('shelljs'); +const xcode = require('xcode'); +const plist = require('plist'); +const _ = require('underscore'); +const path = require('path'); +const fs = require('fs-extra'); -var pluginHandlers = require('./plugman/pluginHandlers'); -var CordovaError = require('cordova-common').CordovaError; +const pluginHandlers = require('./plugman/pluginHandlers'); +const CordovaError = require('cordova-common').CordovaError; -var cachedProjectFiles = {}; +const cachedProjectFiles = {}; function parseProjectFile (locations) { - var project_dir = locations.root; - var pbxPath = locations.pbxproj; + const project_dir = locations.root; + const pbxPath = locations.pbxproj; if (cachedProjectFiles[project_dir]) { return cachedProjectFiles[project_dir]; } - var xcodeproj = xcode.project(pbxPath); + const xcodeproj = xcode.project(pbxPath); xcodeproj.parseSync(); - var xcBuildConfiguration = xcodeproj.pbxXCBuildConfigurationSection(); - var plist_file_entry = _.find(xcBuildConfiguration, function (entry) { return entry.buildSettings && entry.buildSettings.INFOPLIST_FILE; }); - var plist_file = path.join(project_dir, plist_file_entry.buildSettings.INFOPLIST_FILE.replace(/^"(.*)"$/g, '$1').replace(/\\&/g, '&')); - var config_file = path.join(path.dirname(plist_file), 'config.xml'); + const xcBuildConfiguration = xcodeproj.pbxXCBuildConfigurationSection(); + const plist_file_entry = _.find(xcBuildConfiguration, entry => entry.buildSettings && entry.buildSettings.INFOPLIST_FILE); + const plist_file = path.join(project_dir, plist_file_entry.buildSettings.INFOPLIST_FILE.replace(/^"(.*)"$/g, '$1').replace(/\\&/g, '&')); + const config_file = path.join(path.dirname(plist_file), 'config.xml'); if (!fs.existsSync(plist_file) || !fs.existsSync(config_file)) { throw new CordovaError('Could not find *-Info.plist file, or config.xml file.'); } - var frameworks_file = path.join(project_dir, 'frameworks.json'); - var frameworks = {}; + const frameworks_file = path.join(project_dir, 'frameworks.json'); + let frameworks = {}; try { frameworks = require(frameworks_file); } catch (e) { } - var xcode_dir = path.dirname(plist_file); - var pluginsDir = path.resolve(xcode_dir, 'Plugins'); - var resourcesDir = path.resolve(xcode_dir, 'Resources'); + const xcode_dir = path.dirname(plist_file); + const pluginsDir = path.resolve(xcode_dir, 'Plugins'); + const resourcesDir = path.resolve(xcode_dir, 'Resources'); cachedProjectFiles[project_dir] = { plugins_dir: pluginsDir, @@ -72,13 +71,21 @@ function parseProjectFile (locations) { fs.writeFileSync(pbxPath, xcodeproj.writeSync()); if (Object.keys(this.frameworks).length === 0) { // If there is no framework references remain in the project, just remove this file - shell.rm('-rf', frameworks_file); + fs.removeSync(frameworks_file); return; } fs.writeFileSync(frameworks_file, JSON.stringify(this.frameworks, null, 4)); }, getPackageName: function () { - return plist.parse(fs.readFileSync(plist_file, 'utf8')).CFBundleIdentifier; + const packageName = plist.parse(fs.readFileSync(plist_file, 'utf8')).CFBundleIdentifier; + let bundleIdentifier = packageName; + + const variables = packageName.match(/\$\((\w+)\)/); // match $(VARIABLE), if any + if (variables && variables.length >= 2) { + bundleIdentifier = xcodeproj.getBuildProperty(variables[1]); + } + + return bundleIdentifier.replace(/^"/, '').replace(/"$/, ''); }, getInstaller: function (name) { return pluginHandlers.getInstaller(name); @@ -86,7 +93,7 @@ function parseProjectFile (locations) { getUninstaller: function (name) { return pluginHandlers.getUninstaller(name); }, - frameworks: frameworks + frameworks }; return cachedProjectFiles[project_dir]; } @@ -97,7 +104,7 @@ function purgeProjectFileCache (project_dir) { module.exports = { parse: parseProjectFile, - purgeProjectFileCache: purgeProjectFileCache + purgeProjectFileCache }; xcode.project.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) { @@ -105,25 +112,23 @@ xcode.project.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) { }; xcode.project.prototype.addToPbxEmbedFrameworksBuildPhase = function (file) { - var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target); + const sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target); if (sources) { sources.files.push(pbxBuildPhaseObj(file)); } }; xcode.project.prototype.removeFromPbxEmbedFrameworksBuildPhase = function (file) { - var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target); + const sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target); if (sources) { - sources.files = _.reject(sources.files, function (file) { - return file.comment === longComment(file); - }); + sources.files = _.reject(sources.files, file => file.comment === longComment(file)); } }; // special handlers to add frameworks to the 'Embed Frameworks' build phase, needed for custom frameworks // see CB-9517. should probably be moved to node-xcode. -var util = require('util'); +const util = require('util'); function pbxBuildPhaseObj (file) { - var obj = Object.create(null); + const obj = Object.create(null); obj.value = file.uuid; obj.comment = longComment(file); return obj; diff --git a/StoneIsland/platforms/ios/cordova/lib/run.js b/StoneIsland/platforms/ios/cordova/lib/run.js index 3a6246e1..f7fd8c13 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/run.js +++ b/StoneIsland/platforms/ios/cordova/lib/run.js @@ -17,23 +17,23 @@ under the License. */ -var Q = require('q'); -var path = require('path'); -var iossim = require('ios-sim'); -var build = require('./build'); -var spawn = require('./spawn'); -var check_reqs = require('./check_reqs'); +const path = require('path'); +const build = require('./build'); +const { + CordovaError, + events, + superspawn: { spawn } +} = require('cordova-common'); +const check_reqs = require('./check_reqs'); +const fs = require('fs-extra'); -var events = require('cordova-common').events; - -var cordovaPath = path.join(__dirname, '..'); -var projectPath = path.join(__dirname, '..', '..'); - -module.exports.run = function (runOptions) { +const cordovaPath = path.join(__dirname, '..'); +const projectPath = path.join(__dirname, '..', '..'); +module.exports.run = runOptions => { // Validate args if (runOptions.device && runOptions.emulator) { - return Q.reject('Only one of "device"/"emulator" options should be specified'); + return Promise.reject(new CordovaError('Only one of "device"/"emulator" options should be specified')); } // support for CB-8168 `cordova/run --list` @@ -41,15 +41,13 @@ module.exports.run = function (runOptions) { if (runOptions.device) return module.exports.listDevices(); if (runOptions.emulator) return module.exports.listEmulators(); // if no --device or --emulator flag is specified, list both devices and emulators - return module.exports.listDevices().then(function () { - return module.exports.listEmulators(); - }); + return module.exports.listDevices().then(() => module.exports.listEmulators()); } - var useDevice = !!runOptions.device; + let useDevice = !!runOptions.device; - return require('./list-devices').run() - .then(function (devices) { + return require('./listDevices').run() + .then(devices => { if (devices.length > 0 && !(runOptions.emulator)) { useDevice = true; // we also explicitly set device flag in options as we pass @@ -57,58 +55,56 @@ module.exports.run = function (runOptions) { runOptions.device = true; return check_reqs.check_ios_deploy(); } - }).then(function () { + }).then(() => { if (!runOptions.nobuild) { return build.run(runOptions); } else { - return Q.resolve(); + return Promise.resolve(); } - }).then(function () { - return build.findXCodeProjectIn(projectPath); - }).then(function (projectName) { - var appPath = path.join(projectPath, 'build', 'emulator', projectName + '.app'); - var buildOutputDir = path.join(projectPath, 'build', 'device'); + }).then(() => build.findXCodeProjectIn(projectPath)) + .then(projectName => { + let appPath = path.join(projectPath, 'build', 'emulator', `${projectName}.app`); + const buildOutputDir = path.join(projectPath, 'build', 'device'); // select command to run and arguments depending whether // we're running on device/emulator if (useDevice) { return module.exports.checkDeviceConnected() - .then(function () { + .then(() => { // Unpack IPA - var ipafile = path.join(buildOutputDir, projectName + '.ipa'); + const ipafile = path.join(buildOutputDir, `${projectName}.ipa`); // unpack the existing platform/ios/build/device/appname.ipa (zipfile), will create a Payload folder - return spawn('unzip', [ '-o', '-qq', ipafile ], buildOutputDir); + return spawn('unzip', ['-o', '-qq', ipafile], { cwd: buildOutputDir, printCommand: true, stdio: 'inherit' }); }) - .then(function () { + .then(() => { // Uncompress IPA (zip file) - var appFileInflated = path.join(buildOutputDir, 'Payload', projectName + '.app'); - var appFile = path.join(buildOutputDir, projectName + '.app'); - var payloadFolder = path.join(buildOutputDir, 'Payload'); + const appFileInflated = path.join(buildOutputDir, 'Payload', `${projectName}.app`); + const appFile = path.join(buildOutputDir, `${projectName}.app`); + const payloadFolder = path.join(buildOutputDir, 'Payload'); // delete the existing platform/ios/build/device/appname.app - return spawn('rm', [ '-rf', appFile ], buildOutputDir) - .then(function () { - // move the platform/ios/build/device/Payload/appname.app to parent - return spawn('mv', [ '-f', appFileInflated, buildOutputDir ], buildOutputDir); - }) - .then(function () { - // delete the platform/ios/build/device/Payload folder - return spawn('rm', [ '-rf', payloadFolder ], buildOutputDir); - }); + fs.removeSync(appFile); + // move the platform/ios/build/device/Payload/appname.app to parent + fs.moveSync(appFileInflated, appFile); + // delete the platform/ios/build/device/Payload folder + fs.removeSync(payloadFolder); + + return null; }) - .then(function () { - appPath = path.join(projectPath, 'build', 'device', projectName + '.app'); - var extraArgs = []; - if (runOptions.argv) { - // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args - extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2)); - } - return module.exports.deployToDevice(appPath, runOptions.target, extraArgs); - }, function () { + .then( + () => { + appPath = path.join(projectPath, 'build', 'device', `${projectName}.app`); + let extraArgs = []; + if (runOptions.argv) { + // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args + extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2)); + } + return module.exports.deployToDevice(appPath, runOptions.target, extraArgs); + }, // if device connection check failed use emulator then - return module.exports.deployToSim(appPath, runOptions.target); - }); + () => module.exports.deployToSim(appPath, runOptions.target) + ); } else { return module.exports.deployToSim(appPath, runOptions.target); } @@ -129,11 +125,11 @@ module.exports.listEmulators = listEmulators; * @return {Array} array with unsupported args for the 'run' command */ function filterSupportedArgs (args) { - var filtered = []; - var sargs = ['--device', '--emulator', '--nobuild', '--list', '--target', '--debug', '--release']; - var re = new RegExp(sargs.join('|')); + const filtered = []; + const sargs = ['--device', '--emulator', '--nobuild', '--list', '--target', '--debug', '--release']; + const re = new RegExp(sargs.join('|')); - args.forEach(function (element) { + args.forEach(element => { // supported args not found, we add // we do a regex search because --target can be "--target=XXX" if (element.search(re) === -1) { @@ -149,7 +145,7 @@ function filterSupportedArgs (args) { * @return {Promise} Fullfilled when any device is connected, rejected otherwise */ function checkDeviceConnected () { - return spawn('ios-deploy', ['-c', '-t', '1']); + return spawn('ios-deploy', ['-c', '-t', '1'], { printCommand: true, stdio: 'inherit' }); } /** @@ -159,11 +155,12 @@ function checkDeviceConnected () { * @return {Promise} Resolves when deploy succeeds otherwise rejects */ function deployToDevice (appPath, target, extraArgs) { + events.emit('log', 'Deploying to device'); // Deploying to device... if (target) { - return spawn('ios-deploy', ['--justlaunch', '-d', '-b', appPath, '-i', target].concat(extraArgs)); + return spawn('ios-deploy', ['--justlaunch', '-d', '-b', appPath, '-i', target].concat(extraArgs), { printCommand: true, stdio: 'inherit' }); } else { - return spawn('ios-deploy', ['--justlaunch', '--no-wifi', '-d', '-b', appPath].concat(extraArgs)); + return spawn('ios-deploy', ['--justlaunch', '--no-wifi', '-d', '-b', appPath].concat(extraArgs), { printCommand: true, stdio: 'inherit' }); } } @@ -174,19 +171,20 @@ function deployToDevice (appPath, target, extraArgs) { * @return {Promise} Resolves when deploy succeeds otherwise rejects */ function deployToSim (appPath, target) { - // Select target device for emulator. Default is 'iPhone-6' + events.emit('log', 'Deploying to simulator'); if (!target) { - return require('./list-emulator-images').run() - .then(function (emulators) { + // Select target device for emulator + return require('./listEmulatorImages').run() + .then(emulators => { if (emulators.length > 0) { target = emulators[0]; } - emulators.forEach(function (emulator) { + emulators.forEach(emulator => { if (emulator.indexOf('iPhone') === 0) { target = emulator; } }); - events.emit('log', 'No target specified for emulator. Deploying to ' + target + ' simulator'); + events.emit('log', `No target specified for emulator. Deploying to "${target}" simulator.`); return startSim(appPath, target); }); } else { @@ -195,32 +193,50 @@ function deployToSim (appPath, target) { } function startSim (appPath, target) { - var logPath = path.join(cordovaPath, 'console.log'); + const logPath = path.join(cordovaPath, 'console.log'); - return iossim.launch(appPath, 'com.apple.CoreSimulator.SimDeviceType.' + target, logPath, '--exit'); + return iossimLaunch(appPath, `com.apple.CoreSimulator.SimDeviceType.${target}`, logPath, '--exit'); +} + +function iossimLaunch (appPath, devicetypeid, log, exit) { + return spawn( + require.resolve('ios-sim/bin/ios-sim'), + ['launch', appPath, '--devicetypeid', devicetypeid, '--log', log, exit], + { cwd: projectPath, printCommand: true } + ).progress(stdio => { + if (stdio.stderr) { + events.emit('error', `[ios-sim] ${stdio.stderr}`); + } + if (stdio.stdout) { + events.emit('log', `[ios-sim] ${stdio.stdout.trim()}`); + } + }) + .then(result => { + events.emit('log', 'Simulator successfully started via `ios-sim`.'); + }); } function listDevices () { - return require('./list-devices').run() - .then(function (devices) { + return require('./listDevices').run() + .then(devices => { events.emit('log', 'Available iOS Devices:'); - devices.forEach(function (device) { - events.emit('log', '\t' + device); + devices.forEach(device => { + events.emit('log', `\t${device}`); }); }); } function listEmulators () { - return require('./list-emulator-images').run() - .then(function (emulators) { + return require('./listEmulatorImages').run() + .then(emulators => { events.emit('log', 'Available iOS Simulators:'); - emulators.forEach(function (emulator) { - events.emit('log', '\t' + emulator); + emulators.forEach(emulator => { + events.emit('log', `\t${emulator}`); }); }); } -module.exports.help = function () { +module.exports.help = () => { console.log('\nUsage: run [ --device | [ --emulator [ --target=<id> ] ] ] [ --debug | --release | --nobuild ]'); // TODO: add support for building different archs // console.log(" [ --archs=\"<list of target architectures>\" ] "); diff --git a/StoneIsland/platforms/ios/cordova/lib/spawn.js b/StoneIsland/platforms/ios/cordova/lib/spawn.js deleted file mode 100755 index b5a56852..00000000 --- a/StoneIsland/platforms/ios/cordova/lib/spawn.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -var Q = require('q'); -var proc = require('child_process'); - -/** - * Run specified command with arguments - * @param {String} cmd Command - * @param {Array} args Array of arguments that should be passed to command - * @param {String} opt_cwd Working directory for command - * @param {String} opt_verbosity Verbosity level for command stdout output, "verbose" by default - * @return {Promise} Promise either fullfilled or rejected with error code - */ -module.exports = function (cmd, args, opt_cwd) { - var d = Q.defer(); - try { - var child = proc.spawn(cmd, args, {cwd: opt_cwd, stdio: 'inherit'}); - - child.on('exit', function (code) { - if (code) { - d.reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args); - } else { - d.resolve(); - } - }); - } catch (e) { - d.reject(e); - } - return d.promise; -}; diff --git a/StoneIsland/platforms/ios/cordova/lib/versions.js b/StoneIsland/platforms/ios/cordova/lib/versions.js index c6a41b83..f8914785 100755..100644 --- a/StoneIsland/platforms/ios/cordova/lib/versions.js +++ b/StoneIsland/platforms/ios/cordova/lib/versions.js @@ -1,5 +1,3 @@ -#!/usr/bin/env node - /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -19,76 +17,43 @@ under the License. */ -var child_process = require('child_process'); -var Q = require('q'); +const { + CordovaError, + superspawn: { spawn } +} = require('cordova-common'); +const semver = require('semver'); -exports.get_apple_ios_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); +function fetchSdkVersionByType (sdkType) { + return spawn('xcodebuild', ['-showsdks']) + .then(output => { + const regexSdk = new RegExp(`^${sdkType} \\d`); - return d.promise.then(function (output) { - var regex = /[0-9]*\.[0-9]*/; - var versions = []; - var regexIOS = /^iOS \d+/; - output = output.split('\n'); - for (var i = 0; i < output.length; i++) { - if (output[i].trim().match(regexIOS)) { - versions[versions.length] = parseFloat(output[i].match(regex)[0]); - } - } - versions.sort(); - console.log(versions[0]); - return Q(); - }, function (stderr) { - return Q.reject(stderr); - }); -}; + const versions = output.split('\n') + .filter(line => line.trim().match(regexSdk)) + .map(line => line.match(/\d+\.\d+/)[0]) + .sort(exports.compareVersions); -exports.get_apple_osx_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); + console.log(versions[0]); + }); +} - return d.promise.then(function (output) { - var regex = /[0-9]*\.[0-9]*/; - var versions = []; - var regexOSX = /^OS X \d+/; - output = output.split('\n'); - for (var i = 0; i < output.length; i++) { - if (output[i].trim().match(regexOSX)) { - versions[versions.length] = parseFloat(output[i].match(regex)[0]); - } - } - versions.sort(); - console.log(versions[0]); - return Q(); - }, function (stderr) { - return Q.reject(stderr); - }); +exports.get_apple_ios_version = () => { + return fetchSdkVersionByType('iOS'); }; -exports.get_apple_xcode_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -version', function (error, stdout, stderr) { - var versionMatch = /Xcode (.*)/.exec(stdout); - if (error || !versionMatch) { - d.reject(stderr); - } else { - d.resolve(versionMatch[1]); - } - }); - return d.promise; +exports.get_apple_osx_version = () => { + return fetchSdkVersionByType('macOS'); +}; + +exports.get_apple_xcode_version = () => { + return spawn('xcodebuild', ['-version']) + .then(output => { + const versionMatch = /Xcode (.*)/.exec(output); + + if (!versionMatch) return Promise.reject(output); + + return versionMatch[1]; + }); }; /** @@ -96,16 +61,8 @@ exports.get_apple_xcode_version = function () { * @return {Promise} Promise that either resolved with ios-deploy version * or rejected in case of error */ -exports.get_ios_deploy_version = function () { - var d = Q.defer(); - child_process.exec('ios-deploy --version', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - return d.promise; +exports.get_ios_deploy_version = () => { + return spawn('ios-deploy', ['--version']); }; /** @@ -113,16 +70,8 @@ exports.get_ios_deploy_version = function () { * @return {Promise} Promise that either resolved with pod version * or rejected in case of error */ -exports.get_cocoapods_version = function () { - var d = Q.defer(); - child_process.exec('pod --version', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - return d.promise; +exports.get_cocoapods_version = () => { + return spawn('pod', ['--version']); }; /** @@ -130,16 +79,8 @@ exports.get_cocoapods_version = function () { * @return {Promise} Promise that either resolved with ios-sim version * or rejected in case of error */ -exports.get_ios_sim_version = function () { - var d = Q.defer(); - child_process.exec('ios-sim --version', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - return d.promise; +exports.get_ios_sim_version = () => { + return spawn('ios-sim', ['--version']); }; /** @@ -148,47 +89,31 @@ exports.get_ios_sim_version = function () { * @return {Promise} Promise that either resolved with tool version * or rejected in case of error */ -exports.get_tool_version = function (toolName) { +exports.get_tool_version = toolName => { switch (toolName) { case 'xcodebuild': return exports.get_apple_xcode_version(); case 'ios-sim': return exports.get_ios_sim_version(); case 'ios-deploy': return exports.get_ios_deploy_version(); case 'pod': return exports.get_cocoapods_version(); - default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\', \'ios-deploy\', and \'pod\''); + default: return Promise.reject(new CordovaError(`${toolName} is not valid tool name. Valid names are: 'xcodebuild', 'ios-sim', 'ios-deploy', and 'pod'`)); } }; /** - * Compares two semver-notated version strings. Returns number - * that indicates equality of provided version strings. + * Compares two version strings that can be coerced to semver. + * * @param {String} version1 Version to compare * @param {String} version2 Another version to compare * @return {Number} Negative number if first version is lower than the second, * positive otherwise and 0 if versions are equal. */ -exports.compareVersions = function (version1, version2) { - function parseVer (version) { - return version.split('.').map(function (value) { - // try to convert version segment to Number - var parsed = Number(value); - // Number constructor is strict enough and will return NaN - // if conversion fails. In this case we won't be able to compare versions properly - if (isNaN(parsed)) { - throw 'Version should contain only numbers and dots'; - } - return parsed; - }); - } - var parsedVer1 = parseVer(version1); - var parsedVer2 = parseVer(version2); +exports.compareVersions = (...args) => { + const coerceToSemverIfInvalid = v => { + const semverVersion = semver.parse(v) || semver.coerce(v); + if (!semverVersion) throw new TypeError(`Invalid Version: ${v}`); + return semverVersion; + }; - // Compare corresponding segments of each version - for (var i = 0; i < Math.max(parsedVer1.length, parsedVer2.length); i++) { - // if segment is not specified, assume that it is 0 - // E.g. 3.1 is equal to 3.1.0 - var ret = (parsedVer1[i] || 0) - (parsedVer2[i] || 0); - // if segments are not equal, we're finished - if (ret !== 0) return ret; - } - return 0; + const semverVersions = args.map(coerceToSemverIfInvalid); + return semver.compare(...semverVersions); }; diff --git a/StoneIsland/platforms/ios/cordova/loggingHelper.js b/StoneIsland/platforms/ios/cordova/loggingHelper.js index e353399c..871b6cf3 100755..100644 --- a/StoneIsland/platforms/ios/cordova/loggingHelper.js +++ b/StoneIsland/platforms/ios/cordova/loggingHelper.js @@ -17,7 +17,7 @@ under the License. */ -var CordovaLogger = require('cordova-common').CordovaLogger; +const CordovaLogger = require('cordova-common').CordovaLogger; module.exports = { adjustLoggerLevel: function (opts) { diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE b/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE deleted file mode 100755 index 19129e31..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js b/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js deleted file mode 100755 index 97707e78..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js +++ /dev/null @@ -1,415 +0,0 @@ -// info about each config option. - -var debug = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG - ? function () { console.error.apply(console, arguments) } - : function () {} - -var url = require("url") - , path = require("path") - , Stream = require("stream").Stream - , abbrev = require("abbrev") - -module.exports = exports = nopt -exports.clean = clean - -exports.typeDefs = - { String : { type: String, validate: validateString } - , Boolean : { type: Boolean, validate: validateBoolean } - , url : { type: url, validate: validateUrl } - , Number : { type: Number, validate: validateNumber } - , path : { type: path, validate: validatePath } - , Stream : { type: Stream, validate: validateStream } - , Date : { type: Date, validate: validateDate } - } - -function nopt (types, shorthands, args, slice) { - args = args || process.argv - types = types || {} - shorthands = shorthands || {} - if (typeof slice !== "number") slice = 2 - - debug(types, shorthands, args, slice) - - args = args.slice(slice) - var data = {} - , key - , remain = [] - , cooked = args - , original = args.slice(0) - - parse(args, data, remain, types, shorthands) - // now data is full - clean(data, types, exports.typeDefs) - data.argv = {remain:remain,cooked:cooked,original:original} - Object.defineProperty(data.argv, 'toString', { value: function () { - return this.original.map(JSON.stringify).join(" ") - }, enumerable: false }) - return data -} - -function clean (data, types, typeDefs) { - typeDefs = typeDefs || exports.typeDefs - var remove = {} - , typeDefault = [false, true, null, String, Array] - - Object.keys(data).forEach(function (k) { - if (k === "argv") return - var val = data[k] - , isArray = Array.isArray(val) - , type = types[k] - if (!isArray) val = [val] - if (!type) type = typeDefault - if (type === Array) type = typeDefault.concat(Array) - if (!Array.isArray(type)) type = [type] - - debug("val=%j", val) - debug("types=", type) - val = val.map(function (val) { - // if it's an unknown value, then parse false/true/null/numbers/dates - if (typeof val === "string") { - debug("string %j", val) - val = val.trim() - if ((val === "null" && ~type.indexOf(null)) - || (val === "true" && - (~type.indexOf(true) || ~type.indexOf(Boolean))) - || (val === "false" && - (~type.indexOf(false) || ~type.indexOf(Boolean)))) { - val = JSON.parse(val) - debug("jsonable %j", val) - } else if (~type.indexOf(Number) && !isNaN(val)) { - debug("convert to number", val) - val = +val - } else if (~type.indexOf(Date) && !isNaN(Date.parse(val))) { - debug("convert to date", val) - val = new Date(val) - } - } - - if (!types.hasOwnProperty(k)) { - return val - } - - // allow `--no-blah` to set 'blah' to null if null is allowed - if (val === false && ~type.indexOf(null) && - !(~type.indexOf(false) || ~type.indexOf(Boolean))) { - val = null - } - - var d = {} - d[k] = val - debug("prevalidated val", d, val, types[k]) - if (!validate(d, k, val, types[k], typeDefs)) { - if (exports.invalidHandler) { - exports.invalidHandler(k, val, types[k], data) - } else if (exports.invalidHandler !== false) { - debug("invalid: "+k+"="+val, types[k]) - } - return remove - } - debug("validated val", d, val, types[k]) - return d[k] - }).filter(function (val) { return val !== remove }) - - if (!val.length) delete data[k] - else if (isArray) { - debug(isArray, data[k], val) - data[k] = val - } else data[k] = val[0] - - debug("k=%s val=%j", k, val, data[k]) - }) -} - -function validateString (data, k, val) { - data[k] = String(val) -} - -function validatePath (data, k, val) { - if (val === true) return false - if (val === null) return true - - val = String(val) - var homePattern = process.platform === 'win32' ? /^~(\/|\\)/ : /^~\// - if (val.match(homePattern) && process.env.HOME) { - val = path.resolve(process.env.HOME, val.substr(2)) - } - data[k] = path.resolve(String(val)) - return true -} - -function validateNumber (data, k, val) { - debug("validate Number %j %j %j", k, val, isNaN(val)) - if (isNaN(val)) return false - data[k] = +val -} - -function validateDate (data, k, val) { - debug("validate Date %j %j %j", k, val, Date.parse(val)) - var s = Date.parse(val) - if (isNaN(s)) return false - data[k] = new Date(val) -} - -function validateBoolean (data, k, val) { - if (val instanceof Boolean) val = val.valueOf() - else if (typeof val === "string") { - if (!isNaN(val)) val = !!(+val) - else if (val === "null" || val === "false") val = false - else val = true - } else val = !!val - data[k] = val -} - -function validateUrl (data, k, val) { - val = url.parse(String(val)) - if (!val.host) return false - data[k] = val.href -} - -function validateStream (data, k, val) { - if (!(val instanceof Stream)) return false - data[k] = val -} - -function validate (data, k, val, type, typeDefs) { - // arrays are lists of types. - if (Array.isArray(type)) { - for (var i = 0, l = type.length; i < l; i ++) { - if (type[i] === Array) continue - if (validate(data, k, val, type[i], typeDefs)) return true - } - delete data[k] - return false - } - - // an array of anything? - if (type === Array) return true - - // NaN is poisonous. Means that something is not allowed. - if (type !== type) { - debug("Poison NaN", k, val, type) - delete data[k] - return false - } - - // explicit list of values - if (val === type) { - debug("Explicitly allowed %j", val) - // if (isArray) (data[k] = data[k] || []).push(val) - // else data[k] = val - data[k] = val - return true - } - - // now go through the list of typeDefs, validate against each one. - var ok = false - , types = Object.keys(typeDefs) - for (var i = 0, l = types.length; i < l; i ++) { - debug("test type %j %j %j", k, val, types[i]) - var t = typeDefs[types[i]] - if (t && - ((type && type.name && t.type && t.type.name) ? (type.name === t.type.name) : (type === t.type))) { - var d = {} - ok = false !== t.validate(d, k, val) - val = d[k] - if (ok) { - // if (isArray) (data[k] = data[k] || []).push(val) - // else data[k] = val - data[k] = val - break - } - } - } - debug("OK? %j (%j %j %j)", ok, k, val, types[i]) - - if (!ok) delete data[k] - return ok -} - -function parse (args, data, remain, types, shorthands) { - debug("parse", args, data, remain) - - var key = null - , abbrevs = abbrev(Object.keys(types)) - , shortAbbr = abbrev(Object.keys(shorthands)) - - for (var i = 0; i < args.length; i ++) { - var arg = args[i] - debug("arg", arg) - - if (arg.match(/^-{2,}$/)) { - // done with keys. - // the rest are args. - remain.push.apply(remain, args.slice(i + 1)) - args[i] = "--" - break - } - var hadEq = false - if (arg.charAt(0) === "-" && arg.length > 1) { - if (arg.indexOf("=") !== -1) { - hadEq = true - var v = arg.split("=") - arg = v.shift() - v = v.join("=") - args.splice.apply(args, [i, 1].concat([arg, v])) - } - - // see if it's a shorthand - // if so, splice and back up to re-parse it. - var shRes = resolveShort(arg, shorthands, shortAbbr, abbrevs) - debug("arg=%j shRes=%j", arg, shRes) - if (shRes) { - debug(arg, shRes) - args.splice.apply(args, [i, 1].concat(shRes)) - if (arg !== shRes[0]) { - i -- - continue - } - } - arg = arg.replace(/^-+/, "") - var no = null - while (arg.toLowerCase().indexOf("no-") === 0) { - no = !no - arg = arg.substr(3) - } - - if (abbrevs[arg]) arg = abbrevs[arg] - - var isArray = types[arg] === Array || - Array.isArray(types[arg]) && types[arg].indexOf(Array) !== -1 - - // allow unknown things to be arrays if specified multiple times. - if (!types.hasOwnProperty(arg) && data.hasOwnProperty(arg)) { - if (!Array.isArray(data[arg])) - data[arg] = [data[arg]] - isArray = true - } - - var val - , la = args[i + 1] - - var isBool = typeof no === 'boolean' || - types[arg] === Boolean || - Array.isArray(types[arg]) && types[arg].indexOf(Boolean) !== -1 || - (typeof types[arg] === 'undefined' && !hadEq) || - (la === "false" && - (types[arg] === null || - Array.isArray(types[arg]) && ~types[arg].indexOf(null))) - - if (isBool) { - // just set and move along - val = !no - // however, also support --bool true or --bool false - if (la === "true" || la === "false") { - val = JSON.parse(la) - la = null - if (no) val = !val - i ++ - } - - // also support "foo":[Boolean, "bar"] and "--foo bar" - if (Array.isArray(types[arg]) && la) { - if (~types[arg].indexOf(la)) { - // an explicit type - val = la - i ++ - } else if ( la === "null" && ~types[arg].indexOf(null) ) { - // null allowed - val = null - i ++ - } else if ( !la.match(/^-{2,}[^-]/) && - !isNaN(la) && - ~types[arg].indexOf(Number) ) { - // number - val = +la - i ++ - } else if ( !la.match(/^-[^-]/) && ~types[arg].indexOf(String) ) { - // string - val = la - i ++ - } - } - - if (isArray) (data[arg] = data[arg] || []).push(val) - else data[arg] = val - - continue - } - - if (types[arg] === String && la === undefined) - la = "" - - if (la && la.match(/^-{2,}$/)) { - la = undefined - i -- - } - - val = la === undefined ? true : la - if (isArray) (data[arg] = data[arg] || []).push(val) - else data[arg] = val - - i ++ - continue - } - remain.push(arg) - } -} - -function resolveShort (arg, shorthands, shortAbbr, abbrevs) { - // handle single-char shorthands glommed together, like - // npm ls -glp, but only if there is one dash, and only if - // all of the chars are single-char shorthands, and it's - // not a match to some other abbrev. - arg = arg.replace(/^-+/, '') - - // if it's an exact known option, then don't go any further - if (abbrevs[arg] === arg) - return null - - // if it's an exact known shortopt, same deal - if (shorthands[arg]) { - // make it an array, if it's a list of words - if (shorthands[arg] && !Array.isArray(shorthands[arg])) - shorthands[arg] = shorthands[arg].split(/\s+/) - - return shorthands[arg] - } - - // first check to see if this arg is a set of single-char shorthands - var singles = shorthands.___singles - if (!singles) { - singles = Object.keys(shorthands).filter(function (s) { - return s.length === 1 - }).reduce(function (l,r) { - l[r] = true - return l - }, {}) - shorthands.___singles = singles - debug('shorthand singles', singles) - } - - var chrs = arg.split("").filter(function (c) { - return singles[c] - }) - - if (chrs.join("") === arg) return chrs.map(function (c) { - return shorthands[c] - }).reduce(function (l, r) { - return l.concat(r) - }, []) - - - // if it's an arg abbrev, and not a literal shorthand, then prefer the arg - if (abbrevs[arg] && !shorthands[arg]) - return null - - // if it's an abbr for a shorthand, then use that - if (shortAbbr[arg]) - arg = shortAbbr[arg] - - // make it an array, if it's a list of words - if (shorthands[arg] && !Array.isArray(shorthands[arg])) - shorthands[arg] = shorthands[arg].split(/\s+/) - - return shorthands[arg] -} diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json b/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json deleted file mode 100755 index 3784dfb3..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "_from": "nopt@^3.0.6", - "_id": "nopt@3.0.6", - "_inBundle": true, - "_integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "_location": "/cordova-ios/nopt", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "nopt@^3.0.6", - "name": "nopt", - "escapedName": "nopt", - "rawSpec": "^3.0.6", - "saveSpec": null, - "fetchSpec": "^3.0.6" - }, - "_requiredBy": [ - "/cordova-ios" - ], - "_resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "_shasum": "c6465dbf08abcd4db359317f79ac68a646b28ff9", - "_spec": "nopt@^3.0.6", - "_where": "/Users/spindori/Documents/Cordova/cordova-ios", - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me/" - }, - "bin": { - "nopt": "./bin/nopt.js" - }, - "bugs": { - "url": "https://github.com/npm/nopt/issues" - }, - "bundleDependencies": false, - "dependencies": { - "abbrev": "1" - }, - "deprecated": false, - "description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.", - "devDependencies": { - "tap": "^1.2.0" - }, - "homepage": "https://github.com/npm/nopt#readme", - "license": "ISC", - "main": "lib/nopt.js", - "name": "nopt", - "repository": { - "type": "git", - "url": "git+https://github.com/npm/nopt.git" - }, - "scripts": { - "test": "tap test/*.js" - }, - "version": "3.0.6" -} diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/LICENSE b/StoneIsland/platforms/ios/cordova/node_modules/q/LICENSE deleted file mode 100755 index 9ce1ea59..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/q/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright 2009–2017 Kristopher Michael Kowal. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/package.json b/StoneIsland/platforms/ios/cordova/node_modules/q/package.json deleted file mode 100755 index 30e1b1b8..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/q/package.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "_from": "q@^1.4.1", - "_id": "q@1.5.0", - "_inBundle": true, - "_integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", - "_location": "/cordova-ios/q", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "q@^1.4.1", - "name": "q", - "escapedName": "q", - "rawSpec": "^1.4.1", - "saveSpec": null, - "fetchSpec": "^1.4.1" - }, - "_requiredBy": [ - "/cordova-ios", - "/cordova-ios/cordova-common" - ], - "_resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", - "_shasum": "dd01bac9d06d30e6f219aecb8253ee9ebdc308f1", - "_spec": "q@^1.4.1", - "_where": "/Users/spindori/Documents/Cordova/cordova-ios", - "author": { - "name": "Kris Kowal", - "email": "kris@cixar.com", - "url": "https://github.com/kriskowal" - }, - "bugs": { - "url": "http://github.com/kriskowal/q/issues" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Kris Kowal", - "email": "kris@cixar.com", - "url": "https://github.com/kriskowal" - }, - { - "name": "Irakli Gozalishvili", - "email": "rfobic@gmail.com", - "url": "http://jeditoolkit.com" - }, - { - "name": "Domenic Denicola", - "email": "domenic@domenicdenicola.com", - "url": "http://domenicdenicola.com" - } - ], - "dependencies": {}, - "deprecated": false, - "description": "A library for promises (CommonJS/Promises/A,B,D)", - "devDependencies": { - "cover": "*", - "grunt": "~0.4.1", - "grunt-cli": "~0.1.9", - "grunt-contrib-uglify": "~0.9.1", - "jasmine-node": "1.11.0", - "jshint": "~2.1.9", - "matcha": "~0.2.0", - "opener": "*", - "promises-aplus-tests": "1.x" - }, - "directories": { - "test": "./spec" - }, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - }, - "files": [ - "LICENSE", - "q.js", - "queue.js" - ], - "homepage": "https://github.com/kriskowal/q", - "keywords": [ - "q", - "promise", - "promises", - "promises-a", - "promises-aplus", - "deferred", - "future", - "async", - "flow control", - "fluent", - "browser", - "node" - ], - "license": "MIT", - "main": "q.js", - "name": "q", - "overlay": { - "teleport": { - "dependencies": { - "system": ">=0.0.4" - } - } - }, - "repository": { - "type": "git", - "url": "git://github.com/kriskowal/q.git" - }, - "scripts": { - "benchmark": "matcha", - "cover": "cover run jasmine-node spec && cover report html && opener cover_html/index.html", - "lint": "jshint q.js", - "minify": "grunt", - "prepublish": "grunt", - "test": "npm ls -s && jasmine-node spec && promises-aplus-tests spec/aplus-adapter && npm run -s lint", - "test-browser": "opener spec/q-spec.html" - }, - "version": "1.5.0" -} diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/q.js b/StoneIsland/platforms/ios/cordova/node_modules/q/q.js deleted file mode 100755 index 14dc24a6..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/q/q.js +++ /dev/null @@ -1,2073 +0,0 @@ -// vim:ts=4:sts=4:sw=4: -/*! - * - * Copyright 2009-2017 Kris Kowal under the terms of the MIT - * license found at https://github.com/kriskowal/q/blob/v1/LICENSE - * - * With parts by Tyler Close - * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found - * at http://www.opensource.org/licenses/mit-license.html - * Forked at ref_send.js version: 2009-05-11 - * - * With parts by Mark Miller - * Copyright (C) 2011 Google Inc. - * - * 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. - * - */ - -(function (definition) { - "use strict"; - - // This file will function properly as a <script> tag, or a module - // using CommonJS and NodeJS or RequireJS module formats. In - // Common/Node/RequireJS, the module exports the Q API and when - // executed as a simple <script>, it creates a Q global instead. - - // Montage Require - if (typeof bootstrap === "function") { - bootstrap("promise", definition); - - // CommonJS - } else if (typeof exports === "object" && typeof module === "object") { - module.exports = definition(); - - // RequireJS - } else if (typeof define === "function" && define.amd) { - define(definition); - - // SES (Secure EcmaScript) - } else if (typeof ses !== "undefined") { - if (!ses.ok()) { - return; - } else { - ses.makeQ = definition; - } - - // <script> - } else if (typeof window !== "undefined" || typeof self !== "undefined") { - // Prefer window over self for add-on scripts. Use self for - // non-windowed contexts. - var global = typeof window !== "undefined" ? window : self; - - // Get the `window` object, save the previous Q global - // and initialize Q as a global. - var previousQ = global.Q; - global.Q = definition(); - - // Add a noConflict function so Q can be removed from the - // global namespace. - global.Q.noConflict = function () { - global.Q = previousQ; - return this; - }; - - } else { - throw new Error("This environment was not anticipated by Q. Please file a bug."); - } - -})(function () { -"use strict"; - -var hasStacks = false; -try { - throw new Error(); -} catch (e) { - hasStacks = !!e.stack; -} - -// All code after this point will be filtered from stack traces reported -// by Q. -var qStartingLine = captureLine(); -var qFileName; - -// shims - -// used for fallback in "allResolved" -var noop = function () {}; - -// Use the fastest possible means to execute a task in a future turn -// of the event loop. -var nextTick =(function () { - // linked list of tasks (single, with head node) - var head = {task: void 0, next: null}; - var tail = head; - var flushing = false; - var requestTick = void 0; - var isNodeJS = false; - // queue for late tasks, used by unhandled rejection tracking - var laterQueue = []; - - function flush() { - /* jshint loopfunc: true */ - var task, domain; - - while (head.next) { - head = head.next; - task = head.task; - head.task = void 0; - domain = head.domain; - - if (domain) { - head.domain = void 0; - domain.enter(); - } - runSingle(task, domain); - - } - while (laterQueue.length) { - task = laterQueue.pop(); - runSingle(task); - } - flushing = false; - } - // runs a single function in the async queue - function runSingle(task, domain) { - try { - task(); - - } catch (e) { - if (isNodeJS) { - // In node, uncaught exceptions are considered fatal errors. - // Re-throw them synchronously to interrupt flushing! - - // Ensure continuation if the uncaught exception is suppressed - // listening "uncaughtException" events (as domains does). - // Continue in next event to avoid tick recursion. - if (domain) { - domain.exit(); - } - setTimeout(flush, 0); - if (domain) { - domain.enter(); - } - - throw e; - - } else { - // In browsers, uncaught exceptions are not fatal. - // Re-throw them asynchronously to avoid slow-downs. - setTimeout(function () { - throw e; - }, 0); - } - } - - if (domain) { - domain.exit(); - } - } - - nextTick = function (task) { - tail = tail.next = { - task: task, - domain: isNodeJS && process.domain, - next: null - }; - - if (!flushing) { - flushing = true; - requestTick(); - } - }; - - if (typeof process === "object" && - process.toString() === "[object process]" && process.nextTick) { - // Ensure Q is in a real Node environment, with a `process.nextTick`. - // To see through fake Node environments: - // * Mocha test runner - exposes a `process` global without a `nextTick` - // * Browserify - exposes a `process.nexTick` function that uses - // `setTimeout`. In this case `setImmediate` is preferred because - // it is faster. Browserify's `process.toString()` yields - // "[object Object]", while in a real Node environment - // `process.toString()` yields "[object process]". - isNodeJS = true; - - requestTick = function () { - process.nextTick(flush); - }; - - } else if (typeof setImmediate === "function") { - // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate - if (typeof window !== "undefined") { - requestTick = setImmediate.bind(window, flush); - } else { - requestTick = function () { - setImmediate(flush); - }; - } - - } else if (typeof MessageChannel !== "undefined") { - // modern browsers - // http://www.nonblocking.io/2011/06/windownexttick.html - var channel = new MessageChannel(); - // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create - // working message ports the first time a page loads. - channel.port1.onmessage = function () { - requestTick = requestPortTick; - channel.port1.onmessage = flush; - flush(); - }; - var requestPortTick = function () { - // Opera requires us to provide a message payload, regardless of - // whether we use it. - channel.port2.postMessage(0); - }; - requestTick = function () { - setTimeout(flush, 0); - requestPortTick(); - }; - - } else { - // old browsers - requestTick = function () { - setTimeout(flush, 0); - }; - } - // runs a task after all other tasks have been run - // this is useful for unhandled rejection tracking that needs to happen - // after all `then`d tasks have been run. - nextTick.runAfter = function (task) { - laterQueue.push(task); - if (!flushing) { - flushing = true; - requestTick(); - } - }; - return nextTick; -})(); - -// Attempt to make generics safe in the face of downstream -// modifications. -// There is no situation where this is necessary. -// If you need a security guarantee, these primordials need to be -// deeply frozen anyway, and if you don’t need a security guarantee, -// this is just plain paranoid. -// However, this **might** have the nice side-effect of reducing the size of -// the minified code by reducing x.call() to merely x() -// See Mark Miller’s explanation of what this does. -// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming -var call = Function.call; -function uncurryThis(f) { - return function () { - return call.apply(f, arguments); - }; -} -// This is equivalent, but slower: -// uncurryThis = Function_bind.bind(Function_bind.call); -// http://jsperf.com/uncurrythis - -var array_slice = uncurryThis(Array.prototype.slice); - -var array_reduce = uncurryThis( - Array.prototype.reduce || function (callback, basis) { - var index = 0, - length = this.length; - // concerning the initial value, if one is not provided - if (arguments.length === 1) { - // seek to the first value in the array, accounting - // for the possibility that is is a sparse array - do { - if (index in this) { - basis = this[index++]; - break; - } - if (++index >= length) { - throw new TypeError(); - } - } while (1); - } - // reduce - for (; index < length; index++) { - // account for the possibility that the array is sparse - if (index in this) { - basis = callback(basis, this[index], index); - } - } - return basis; - } -); - -var array_indexOf = uncurryThis( - Array.prototype.indexOf || function (value) { - // not a very good shim, but good enough for our one use of it - for (var i = 0; i < this.length; i++) { - if (this[i] === value) { - return i; - } - } - return -1; - } -); - -var array_map = uncurryThis( - Array.prototype.map || function (callback, thisp) { - var self = this; - var collect = []; - array_reduce(self, function (undefined, value, index) { - collect.push(callback.call(thisp, value, index, self)); - }, void 0); - return collect; - } -); - -var object_create = Object.create || function (prototype) { - function Type() { } - Type.prototype = prototype; - return new Type(); -}; - -var object_defineProperty = Object.defineProperty || function (obj, prop, descriptor) { - obj[prop] = descriptor.value; - return obj; -}; - -var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty); - -var object_keys = Object.keys || function (object) { - var keys = []; - for (var key in object) { - if (object_hasOwnProperty(object, key)) { - keys.push(key); - } - } - return keys; -}; - -var object_toString = uncurryThis(Object.prototype.toString); - -function isObject(value) { - return value === Object(value); -} - -// generator related shims - -// FIXME: Remove this function once ES6 generators are in SpiderMonkey. -function isStopIteration(exception) { - return ( - object_toString(exception) === "[object StopIteration]" || - exception instanceof QReturnValue - ); -} - -// FIXME: Remove this helper and Q.return once ES6 generators are in -// SpiderMonkey. -var QReturnValue; -if (typeof ReturnValue !== "undefined") { - QReturnValue = ReturnValue; -} else { - QReturnValue = function (value) { - this.value = value; - }; -} - -// long stack traces - -var STACK_JUMP_SEPARATOR = "From previous event:"; - -function makeStackTraceLong(error, promise) { - // If possible, transform the error stack trace by removing Node and Q - // cruft, then concatenating with the stack trace of `promise`. See #57. - if (hasStacks && - promise.stack && - typeof error === "object" && - error !== null && - error.stack - ) { - var stacks = []; - for (var p = promise; !!p; p = p.source) { - if (p.stack && (!error.__minimumStackCounter__ || error.__minimumStackCounter__ > p.stackCounter)) { - object_defineProperty(error, "__minimumStackCounter__", {value: p.stackCounter, configurable: true}); - stacks.unshift(p.stack); - } - } - stacks.unshift(error.stack); - - var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n"); - var stack = filterStackString(concatedStacks); - object_defineProperty(error, "stack", {value: stack, configurable: true}); - } -} - -function filterStackString(stackString) { - var lines = stackString.split("\n"); - var desiredLines = []; - for (var i = 0; i < lines.length; ++i) { - var line = lines[i]; - - if (!isInternalFrame(line) && !isNodeFrame(line) && line) { - desiredLines.push(line); - } - } - return desiredLines.join("\n"); -} - -function isNodeFrame(stackLine) { - return stackLine.indexOf("(module.js:") !== -1 || - stackLine.indexOf("(node.js:") !== -1; -} - -function getFileNameAndLineNumber(stackLine) { - // Named functions: "at functionName (filename:lineNumber:columnNumber)" - // In IE10 function name can have spaces ("Anonymous function") O_o - var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine); - if (attempt1) { - return [attempt1[1], Number(attempt1[2])]; - } - - // Anonymous functions: "at filename:lineNumber:columnNumber" - var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine); - if (attempt2) { - return [attempt2[1], Number(attempt2[2])]; - } - - // Firefox style: "function@filename:lineNumber or @filename:lineNumber" - var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine); - if (attempt3) { - return [attempt3[1], Number(attempt3[2])]; - } -} - -function isInternalFrame(stackLine) { - var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine); - - if (!fileNameAndLineNumber) { - return false; - } - - var fileName = fileNameAndLineNumber[0]; - var lineNumber = fileNameAndLineNumber[1]; - - return fileName === qFileName && - lineNumber >= qStartingLine && - lineNumber <= qEndingLine; -} - -// discover own file name and line number range for filtering stack -// traces -function captureLine() { - if (!hasStacks) { - return; - } - - try { - throw new Error(); - } catch (e) { - var lines = e.stack.split("\n"); - var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2]; - var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine); - if (!fileNameAndLineNumber) { - return; - } - - qFileName = fileNameAndLineNumber[0]; - return fileNameAndLineNumber[1]; - } -} - -function deprecate(callback, name, alternative) { - return function () { - if (typeof console !== "undefined" && - typeof console.warn === "function") { - console.warn(name + " is deprecated, use " + alternative + - " instead.", new Error("").stack); - } - return callback.apply(callback, arguments); - }; -} - -// end of shims -// beginning of real work - -/** - * Constructs a promise for an immediate reference, passes promises through, or - * coerces promises from different systems. - * @param value immediate reference or promise - */ -function Q(value) { - // If the object is already a Promise, return it directly. This enables - // the resolve function to both be used to created references from objects, - // but to tolerably coerce non-promises to promises. - if (value instanceof Promise) { - return value; - } - - // assimilate thenables - if (isPromiseAlike(value)) { - return coerce(value); - } else { - return fulfill(value); - } -} -Q.resolve = Q; - -/** - * Performs a task in a future turn of the event loop. - * @param {Function} task - */ -Q.nextTick = nextTick; - -/** - * Controls whether or not long stack traces will be on - */ -Q.longStackSupport = false; - -/** - * The counter is used to determine the stopping point for building - * long stack traces. In makeStackTraceLong we walk backwards through - * the linked list of promises, only stacks which were created before - * the rejection are concatenated. - */ -var longStackCounter = 1; - -// enable long stacks if Q_DEBUG is set -if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) { - Q.longStackSupport = true; -} - -/** - * Constructs a {promise, resolve, reject} object. - * - * `resolve` is a callback to invoke with a more resolved value for the - * promise. To fulfill the promise, invoke `resolve` with any value that is - * not a thenable. To reject the promise, invoke `resolve` with a rejected - * thenable, or invoke `reject` with the reason directly. To resolve the - * promise to another thenable, thus putting it in the same state, invoke - * `resolve` with that other thenable. - */ -Q.defer = defer; -function defer() { - // if "messages" is an "Array", that indicates that the promise has not yet - // been resolved. If it is "undefined", it has been resolved. Each - // element of the messages array is itself an array of complete arguments to - // forward to the resolved promise. We coerce the resolution value to a - // promise using the `resolve` function because it handles both fully - // non-thenable values and other thenables gracefully. - var messages = [], progressListeners = [], resolvedPromise; - - var deferred = object_create(defer.prototype); - var promise = object_create(Promise.prototype); - - promise.promiseDispatch = function (resolve, op, operands) { - var args = array_slice(arguments); - if (messages) { - messages.push(args); - if (op === "when" && operands[1]) { // progress operand - progressListeners.push(operands[1]); - } - } else { - Q.nextTick(function () { - resolvedPromise.promiseDispatch.apply(resolvedPromise, args); - }); - } - }; - - // XXX deprecated - promise.valueOf = function () { - if (messages) { - return promise; - } - var nearerValue = nearer(resolvedPromise); - if (isPromise(nearerValue)) { - resolvedPromise = nearerValue; // shorten chain - } - return nearerValue; - }; - - promise.inspect = function () { - if (!resolvedPromise) { - return { state: "pending" }; - } - return resolvedPromise.inspect(); - }; - - if (Q.longStackSupport && hasStacks) { - try { - throw new Error(); - } catch (e) { - // NOTE: don't try to use `Error.captureStackTrace` or transfer the - // accessor around; that causes memory leaks as per GH-111. Just - // reify the stack trace as a string ASAP. - // - // At the same time, cut off the first line; it's always just - // "[object Promise]\n", as per the `toString`. - promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1); - promise.stackCounter = longStackCounter++; - } - } - - // NOTE: we do the checks for `resolvedPromise` in each method, instead of - // consolidating them into `become`, since otherwise we'd create new - // promises with the lines `become(whatever(value))`. See e.g. GH-252. - - function become(newPromise) { - resolvedPromise = newPromise; - - if (Q.longStackSupport && hasStacks) { - // Only hold a reference to the new promise if long stacks - // are enabled to reduce memory usage - promise.source = newPromise; - } - - array_reduce(messages, function (undefined, message) { - Q.nextTick(function () { - newPromise.promiseDispatch.apply(newPromise, message); - }); - }, void 0); - - messages = void 0; - progressListeners = void 0; - } - - deferred.promise = promise; - deferred.resolve = function (value) { - if (resolvedPromise) { - return; - } - - become(Q(value)); - }; - - deferred.fulfill = function (value) { - if (resolvedPromise) { - return; - } - - become(fulfill(value)); - }; - deferred.reject = function (reason) { - if (resolvedPromise) { - return; - } - - become(reject(reason)); - }; - deferred.notify = function (progress) { - if (resolvedPromise) { - return; - } - - array_reduce(progressListeners, function (undefined, progressListener) { - Q.nextTick(function () { - progressListener(progress); - }); - }, void 0); - }; - - return deferred; -} - -/** - * Creates a Node-style callback that will resolve or reject the deferred - * promise. - * @returns a nodeback - */ -defer.prototype.makeNodeResolver = function () { - var self = this; - return function (error, value) { - if (error) { - self.reject(error); - } else if (arguments.length > 2) { - self.resolve(array_slice(arguments, 1)); - } else { - self.resolve(value); - } - }; -}; - -/** - * @param resolver {Function} a function that returns nothing and accepts - * the resolve, reject, and notify functions for a deferred. - * @returns a promise that may be resolved with the given resolve and reject - * functions, or rejected by a thrown exception in resolver - */ -Q.Promise = promise; // ES6 -Q.promise = promise; -function promise(resolver) { - if (typeof resolver !== "function") { - throw new TypeError("resolver must be a function."); - } - var deferred = defer(); - try { - resolver(deferred.resolve, deferred.reject, deferred.notify); - } catch (reason) { - deferred.reject(reason); - } - return deferred.promise; -} - -promise.race = race; // ES6 -promise.all = all; // ES6 -promise.reject = reject; // ES6 -promise.resolve = Q; // ES6 - -// XXX experimental. This method is a way to denote that a local value is -// serializable and should be immediately dispatched to a remote upon request, -// instead of passing a reference. -Q.passByCopy = function (object) { - //freeze(object); - //passByCopies.set(object, true); - return object; -}; - -Promise.prototype.passByCopy = function () { - //freeze(object); - //passByCopies.set(object, true); - return this; -}; - -/** - * If two promises eventually fulfill to the same value, promises that value, - * but otherwise rejects. - * @param x {Any*} - * @param y {Any*} - * @returns {Any*} a promise for x and y if they are the same, but a rejection - * otherwise. - * - */ -Q.join = function (x, y) { - return Q(x).join(y); -}; - -Promise.prototype.join = function (that) { - return Q([this, that]).spread(function (x, y) { - if (x === y) { - // TODO: "===" should be Object.is or equiv - return x; - } else { - throw new Error("Q can't join: not the same: " + x + " " + y); - } - }); -}; - -/** - * Returns a promise for the first of an array of promises to become settled. - * @param answers {Array[Any*]} promises to race - * @returns {Any*} the first promise to be settled - */ -Q.race = race; -function race(answerPs) { - return promise(function (resolve, reject) { - // Switch to this once we can assume at least ES5 - // answerPs.forEach(function (answerP) { - // Q(answerP).then(resolve, reject); - // }); - // Use this in the meantime - for (var i = 0, len = answerPs.length; i < len; i++) { - Q(answerPs[i]).then(resolve, reject); - } - }); -} - -Promise.prototype.race = function () { - return this.then(Q.race); -}; - -/** - * Constructs a Promise with a promise descriptor object and optional fallback - * function. The descriptor contains methods like when(rejected), get(name), - * set(name, value), post(name, args), and delete(name), which all - * return either a value, a promise for a value, or a rejection. The fallback - * accepts the operation name, a resolver, and any further arguments that would - * have been forwarded to the appropriate method above had a method been - * provided with the proper name. The API makes no guarantees about the nature - * of the returned object, apart from that it is usable whereever promises are - * bought and sold. - */ -Q.makePromise = Promise; -function Promise(descriptor, fallback, inspect) { - if (fallback === void 0) { - fallback = function (op) { - return reject(new Error( - "Promise does not support operation: " + op - )); - }; - } - if (inspect === void 0) { - inspect = function () { - return {state: "unknown"}; - }; - } - - var promise = object_create(Promise.prototype); - - promise.promiseDispatch = function (resolve, op, args) { - var result; - try { - if (descriptor[op]) { - result = descriptor[op].apply(promise, args); - } else { - result = fallback.call(promise, op, args); - } - } catch (exception) { - result = reject(exception); - } - if (resolve) { - resolve(result); - } - }; - - promise.inspect = inspect; - - // XXX deprecated `valueOf` and `exception` support - if (inspect) { - var inspected = inspect(); - if (inspected.state === "rejected") { - promise.exception = inspected.reason; - } - - promise.valueOf = function () { - var inspected = inspect(); - if (inspected.state === "pending" || - inspected.state === "rejected") { - return promise; - } - return inspected.value; - }; - } - - return promise; -} - -Promise.prototype.toString = function () { - return "[object Promise]"; -}; - -Promise.prototype.then = function (fulfilled, rejected, progressed) { - var self = this; - var deferred = defer(); - var done = false; // ensure the untrusted promise makes at most a - // single call to one of the callbacks - - function _fulfilled(value) { - try { - return typeof fulfilled === "function" ? fulfilled(value) : value; - } catch (exception) { - return reject(exception); - } - } - - function _rejected(exception) { - if (typeof rejected === "function") { - makeStackTraceLong(exception, self); - try { - return rejected(exception); - } catch (newException) { - return reject(newException); - } - } - return reject(exception); - } - - function _progressed(value) { - return typeof progressed === "function" ? progressed(value) : value; - } - - Q.nextTick(function () { - self.promiseDispatch(function (value) { - if (done) { - return; - } - done = true; - - deferred.resolve(_fulfilled(value)); - }, "when", [function (exception) { - if (done) { - return; - } - done = true; - - deferred.resolve(_rejected(exception)); - }]); - }); - - // Progress propagator need to be attached in the current tick. - self.promiseDispatch(void 0, "when", [void 0, function (value) { - var newValue; - var threw = false; - try { - newValue = _progressed(value); - } catch (e) { - threw = true; - if (Q.onerror) { - Q.onerror(e); - } else { - throw e; - } - } - - if (!threw) { - deferred.notify(newValue); - } - }]); - - return deferred.promise; -}; - -Q.tap = function (promise, callback) { - return Q(promise).tap(callback); -}; - -/** - * Works almost like "finally", but not called for rejections. - * Original resolution value is passed through callback unaffected. - * Callback may return a promise that will be awaited for. - * @param {Function} callback - * @returns {Q.Promise} - * @example - * doSomething() - * .then(...) - * .tap(console.log) - * .then(...); - */ -Promise.prototype.tap = function (callback) { - callback = Q(callback); - - return this.then(function (value) { - return callback.fcall(value).thenResolve(value); - }); -}; - -/** - * Registers an observer on a promise. - * - * Guarantees: - * - * 1. that fulfilled and rejected will be called only once. - * 2. that either the fulfilled callback or the rejected callback will be - * called, but not both. - * 3. that fulfilled and rejected will not be called in this turn. - * - * @param value promise or immediate reference to observe - * @param fulfilled function to be called with the fulfilled value - * @param rejected function to be called with the rejection exception - * @param progressed function to be called on any progress notifications - * @return promise for the return value from the invoked callback - */ -Q.when = when; -function when(value, fulfilled, rejected, progressed) { - return Q(value).then(fulfilled, rejected, progressed); -} - -Promise.prototype.thenResolve = function (value) { - return this.then(function () { return value; }); -}; - -Q.thenResolve = function (promise, value) { - return Q(promise).thenResolve(value); -}; - -Promise.prototype.thenReject = function (reason) { - return this.then(function () { throw reason; }); -}; - -Q.thenReject = function (promise, reason) { - return Q(promise).thenReject(reason); -}; - -/** - * If an object is not a promise, it is as "near" as possible. - * If a promise is rejected, it is as "near" as possible too. - * If it’s a fulfilled promise, the fulfillment value is nearer. - * If it’s a deferred promise and the deferred has been resolved, the - * resolution is "nearer". - * @param object - * @returns most resolved (nearest) form of the object - */ - -// XXX should we re-do this? -Q.nearer = nearer; -function nearer(value) { - if (isPromise(value)) { - var inspected = value.inspect(); - if (inspected.state === "fulfilled") { - return inspected.value; - } - } - return value; -} - -/** - * @returns whether the given object is a promise. - * Otherwise it is a fulfilled value. - */ -Q.isPromise = isPromise; -function isPromise(object) { - return object instanceof Promise; -} - -Q.isPromiseAlike = isPromiseAlike; -function isPromiseAlike(object) { - return isObject(object) && typeof object.then === "function"; -} - -/** - * @returns whether the given object is a pending promise, meaning not - * fulfilled or rejected. - */ -Q.isPending = isPending; -function isPending(object) { - return isPromise(object) && object.inspect().state === "pending"; -} - -Promise.prototype.isPending = function () { - return this.inspect().state === "pending"; -}; - -/** - * @returns whether the given object is a value or fulfilled - * promise. - */ -Q.isFulfilled = isFulfilled; -function isFulfilled(object) { - return !isPromise(object) || object.inspect().state === "fulfilled"; -} - -Promise.prototype.isFulfilled = function () { - return this.inspect().state === "fulfilled"; -}; - -/** - * @returns whether the given object is a rejected promise. - */ -Q.isRejected = isRejected; -function isRejected(object) { - return isPromise(object) && object.inspect().state === "rejected"; -} - -Promise.prototype.isRejected = function () { - return this.inspect().state === "rejected"; -}; - -//// BEGIN UNHANDLED REJECTION TRACKING - -// This promise library consumes exceptions thrown in handlers so they can be -// handled by a subsequent promise. The exceptions get added to this array when -// they are created, and removed when they are handled. Note that in ES6 or -// shimmed environments, this would naturally be a `Set`. -var unhandledReasons = []; -var unhandledRejections = []; -var reportedUnhandledRejections = []; -var trackUnhandledRejections = true; - -function resetUnhandledRejections() { - unhandledReasons.length = 0; - unhandledRejections.length = 0; - - if (!trackUnhandledRejections) { - trackUnhandledRejections = true; - } -} - -function trackRejection(promise, reason) { - if (!trackUnhandledRejections) { - return; - } - if (typeof process === "object" && typeof process.emit === "function") { - Q.nextTick.runAfter(function () { - if (array_indexOf(unhandledRejections, promise) !== -1) { - process.emit("unhandledRejection", reason, promise); - reportedUnhandledRejections.push(promise); - } - }); - } - - unhandledRejections.push(promise); - if (reason && typeof reason.stack !== "undefined") { - unhandledReasons.push(reason.stack); - } else { - unhandledReasons.push("(no stack) " + reason); - } -} - -function untrackRejection(promise) { - if (!trackUnhandledRejections) { - return; - } - - var at = array_indexOf(unhandledRejections, promise); - if (at !== -1) { - if (typeof process === "object" && typeof process.emit === "function") { - Q.nextTick.runAfter(function () { - var atReport = array_indexOf(reportedUnhandledRejections, promise); - if (atReport !== -1) { - process.emit("rejectionHandled", unhandledReasons[at], promise); - reportedUnhandledRejections.splice(atReport, 1); - } - }); - } - unhandledRejections.splice(at, 1); - unhandledReasons.splice(at, 1); - } -} - -Q.resetUnhandledRejections = resetUnhandledRejections; - -Q.getUnhandledReasons = function () { - // Make a copy so that consumers can't interfere with our internal state. - return unhandledReasons.slice(); -}; - -Q.stopUnhandledRejectionTracking = function () { - resetUnhandledRejections(); - trackUnhandledRejections = false; -}; - -resetUnhandledRejections(); - -//// END UNHANDLED REJECTION TRACKING - -/** - * Constructs a rejected promise. - * @param reason value describing the failure - */ -Q.reject = reject; -function reject(reason) { - var rejection = Promise({ - "when": function (rejected) { - // note that the error has been handled - if (rejected) { - untrackRejection(this); - } - return rejected ? rejected(reason) : this; - } - }, function fallback() { - return this; - }, function inspect() { - return { state: "rejected", reason: reason }; - }); - - // Note that the reason has not been handled. - trackRejection(rejection, reason); - - return rejection; -} - -/** - * Constructs a fulfilled promise for an immediate reference. - * @param value immediate reference - */ -Q.fulfill = fulfill; -function fulfill(value) { - return Promise({ - "when": function () { - return value; - }, - "get": function (name) { - return value[name]; - }, - "set": function (name, rhs) { - value[name] = rhs; - }, - "delete": function (name) { - delete value[name]; - }, - "post": function (name, args) { - // Mark Miller proposes that post with no name should apply a - // promised function. - if (name === null || name === void 0) { - return value.apply(void 0, args); - } else { - return value[name].apply(value, args); - } - }, - "apply": function (thisp, args) { - return value.apply(thisp, args); - }, - "keys": function () { - return object_keys(value); - } - }, void 0, function inspect() { - return { state: "fulfilled", value: value }; - }); -} - -/** - * Converts thenables to Q promises. - * @param promise thenable promise - * @returns a Q promise - */ -function coerce(promise) { - var deferred = defer(); - Q.nextTick(function () { - try { - promise.then(deferred.resolve, deferred.reject, deferred.notify); - } catch (exception) { - deferred.reject(exception); - } - }); - return deferred.promise; -} - -/** - * Annotates an object such that it will never be - * transferred away from this process over any promise - * communication channel. - * @param object - * @returns promise a wrapping of that object that - * additionally responds to the "isDef" message - * without a rejection. - */ -Q.master = master; -function master(object) { - return Promise({ - "isDef": function () {} - }, function fallback(op, args) { - return dispatch(object, op, args); - }, function () { - return Q(object).inspect(); - }); -} - -/** - * Spreads the values of a promised array of arguments into the - * fulfillment callback. - * @param fulfilled callback that receives variadic arguments from the - * promised array - * @param rejected callback that receives the exception if the promise - * is rejected. - * @returns a promise for the return value or thrown exception of - * either callback. - */ -Q.spread = spread; -function spread(value, fulfilled, rejected) { - return Q(value).spread(fulfilled, rejected); -} - -Promise.prototype.spread = function (fulfilled, rejected) { - return this.all().then(function (array) { - return fulfilled.apply(void 0, array); - }, rejected); -}; - -/** - * The async function is a decorator for generator functions, turning - * them into asynchronous generators. Although generators are only part - * of the newest ECMAScript 6 drafts, this code does not cause syntax - * errors in older engines. This code should continue to work and will - * in fact improve over time as the language improves. - * - * ES6 generators are currently part of V8 version 3.19 with the - * --harmony-generators runtime flag enabled. SpiderMonkey has had them - * for longer, but under an older Python-inspired form. This function - * works on both kinds of generators. - * - * Decorates a generator function such that: - * - it may yield promises - * - execution will continue when that promise is fulfilled - * - the value of the yield expression will be the fulfilled value - * - it returns a promise for the return value (when the generator - * stops iterating) - * - the decorated function returns a promise for the return value - * of the generator or the first rejected promise among those - * yielded. - * - if an error is thrown in the generator, it propagates through - * every following yield until it is caught, or until it escapes - * the generator function altogether, and is translated into a - * rejection for the promise returned by the decorated generator. - */ -Q.async = async; -function async(makeGenerator) { - return function () { - // when verb is "send", arg is a value - // when verb is "throw", arg is an exception - function continuer(verb, arg) { - var result; - - // Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only - // engine that has a deployed base of browsers that support generators. - // However, SM's generators use the Python-inspired semantics of - // outdated ES6 drafts. We would like to support ES6, but we'd also - // like to make it possible to use generators in deployed browsers, so - // we also support Python-style generators. At some point we can remove - // this block. - - if (typeof StopIteration === "undefined") { - // ES6 Generators - try { - result = generator[verb](arg); - } catch (exception) { - return reject(exception); - } - if (result.done) { - return Q(result.value); - } else { - return when(result.value, callback, errback); - } - } else { - // SpiderMonkey Generators - // FIXME: Remove this case when SM does ES6 generators. - try { - result = generator[verb](arg); - } catch (exception) { - if (isStopIteration(exception)) { - return Q(exception.value); - } else { - return reject(exception); - } - } - return when(result, callback, errback); - } - } - var generator = makeGenerator.apply(this, arguments); - var callback = continuer.bind(continuer, "next"); - var errback = continuer.bind(continuer, "throw"); - return callback(); - }; -} - -/** - * The spawn function is a small wrapper around async that immediately - * calls the generator and also ends the promise chain, so that any - * unhandled errors are thrown instead of forwarded to the error - * handler. This is useful because it's extremely common to run - * generators at the top-level to work with libraries. - */ -Q.spawn = spawn; -function spawn(makeGenerator) { - Q.done(Q.async(makeGenerator)()); -} - -// FIXME: Remove this interface once ES6 generators are in SpiderMonkey. -/** - * Throws a ReturnValue exception to stop an asynchronous generator. - * - * This interface is a stop-gap measure to support generator return - * values in older Firefox/SpiderMonkey. In browsers that support ES6 - * generators like Chromium 29, just use "return" in your generator - * functions. - * - * @param value the return value for the surrounding generator - * @throws ReturnValue exception with the value. - * @example - * // ES6 style - * Q.async(function* () { - * var foo = yield getFooPromise(); - * var bar = yield getBarPromise(); - * return foo + bar; - * }) - * // Older SpiderMonkey style - * Q.async(function () { - * var foo = yield getFooPromise(); - * var bar = yield getBarPromise(); - * Q.return(foo + bar); - * }) - */ -Q["return"] = _return; -function _return(value) { - throw new QReturnValue(value); -} - -/** - * The promised function decorator ensures that any promise arguments - * are settled and passed as values (`this` is also settled and passed - * as a value). It will also ensure that the result of a function is - * always a promise. - * - * @example - * var add = Q.promised(function (a, b) { - * return a + b; - * }); - * add(Q(a), Q(B)); - * - * @param {function} callback The function to decorate - * @returns {function} a function that has been decorated. - */ -Q.promised = promised; -function promised(callback) { - return function () { - return spread([this, all(arguments)], function (self, args) { - return callback.apply(self, args); - }); - }; -} - -/** - * sends a message to a value in a future turn - * @param object* the recipient - * @param op the name of the message operation, e.g., "when", - * @param args further arguments to be forwarded to the operation - * @returns result {Promise} a promise for the result of the operation - */ -Q.dispatch = dispatch; -function dispatch(object, op, args) { - return Q(object).dispatch(op, args); -} - -Promise.prototype.dispatch = function (op, args) { - var self = this; - var deferred = defer(); - Q.nextTick(function () { - self.promiseDispatch(deferred.resolve, op, args); - }); - return deferred.promise; -}; - -/** - * Gets the value of a property in a future turn. - * @param object promise or immediate reference for target object - * @param name name of property to get - * @return promise for the property value - */ -Q.get = function (object, key) { - return Q(object).dispatch("get", [key]); -}; - -Promise.prototype.get = function (key) { - return this.dispatch("get", [key]); -}; - -/** - * Sets the value of a property in a future turn. - * @param object promise or immediate reference for object object - * @param name name of property to set - * @param value new value of property - * @return promise for the return value - */ -Q.set = function (object, key, value) { - return Q(object).dispatch("set", [key, value]); -}; - -Promise.prototype.set = function (key, value) { - return this.dispatch("set", [key, value]); -}; - -/** - * Deletes a property in a future turn. - * @param object promise or immediate reference for target object - * @param name name of property to delete - * @return promise for the return value - */ -Q.del = // XXX legacy -Q["delete"] = function (object, key) { - return Q(object).dispatch("delete", [key]); -}; - -Promise.prototype.del = // XXX legacy -Promise.prototype["delete"] = function (key) { - return this.dispatch("delete", [key]); -}; - -/** - * Invokes a method in a future turn. - * @param object promise or immediate reference for target object - * @param name name of method to invoke - * @param value a value to post, typically an array of - * invocation arguments for promises that - * are ultimately backed with `resolve` values, - * as opposed to those backed with URLs - * wherein the posted value can be any - * JSON serializable object. - * @return promise for the return value - */ -// bound locally because it is used by other methods -Q.mapply = // XXX As proposed by "Redsandro" -Q.post = function (object, name, args) { - return Q(object).dispatch("post", [name, args]); -}; - -Promise.prototype.mapply = // XXX As proposed by "Redsandro" -Promise.prototype.post = function (name, args) { - return this.dispatch("post", [name, args]); -}; - -/** - * Invokes a method in a future turn. - * @param object promise or immediate reference for target object - * @param name name of method to invoke - * @param ...args array of invocation arguments - * @return promise for the return value - */ -Q.send = // XXX Mark Miller's proposed parlance -Q.mcall = // XXX As proposed by "Redsandro" -Q.invoke = function (object, name /*...args*/) { - return Q(object).dispatch("post", [name, array_slice(arguments, 2)]); -}; - -Promise.prototype.send = // XXX Mark Miller's proposed parlance -Promise.prototype.mcall = // XXX As proposed by "Redsandro" -Promise.prototype.invoke = function (name /*...args*/) { - return this.dispatch("post", [name, array_slice(arguments, 1)]); -}; - -/** - * Applies the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param args array of application arguments - */ -Q.fapply = function (object, args) { - return Q(object).dispatch("apply", [void 0, args]); -}; - -Promise.prototype.fapply = function (args) { - return this.dispatch("apply", [void 0, args]); -}; - -/** - * Calls the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param ...args array of application arguments - */ -Q["try"] = -Q.fcall = function (object /* ...args*/) { - return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]); -}; - -Promise.prototype.fcall = function (/*...args*/) { - return this.dispatch("apply", [void 0, array_slice(arguments)]); -}; - -/** - * Binds the promised function, transforming return values into a fulfilled - * promise and thrown errors into a rejected one. - * @param object promise or immediate reference for target function - * @param ...args array of application arguments - */ -Q.fbind = function (object /*...args*/) { - var promise = Q(object); - var args = array_slice(arguments, 1); - return function fbound() { - return promise.dispatch("apply", [ - this, - args.concat(array_slice(arguments)) - ]); - }; -}; -Promise.prototype.fbind = function (/*...args*/) { - var promise = this; - var args = array_slice(arguments); - return function fbound() { - return promise.dispatch("apply", [ - this, - args.concat(array_slice(arguments)) - ]); - }; -}; - -/** - * Requests the names of the owned properties of a promised - * object in a future turn. - * @param object promise or immediate reference for target object - * @return promise for the keys of the eventually settled object - */ -Q.keys = function (object) { - return Q(object).dispatch("keys", []); -}; - -Promise.prototype.keys = function () { - return this.dispatch("keys", []); -}; - -/** - * Turns an array of promises into a promise for an array. If any of - * the promises gets rejected, the whole array is rejected immediately. - * @param {Array*} an array (or promise for an array) of values (or - * promises for values) - * @returns a promise for an array of the corresponding values - */ -// By Mark Miller -// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled -Q.all = all; -function all(promises) { - return when(promises, function (promises) { - var pendingCount = 0; - var deferred = defer(); - array_reduce(promises, function (undefined, promise, index) { - var snapshot; - if ( - isPromise(promise) && - (snapshot = promise.inspect()).state === "fulfilled" - ) { - promises[index] = snapshot.value; - } else { - ++pendingCount; - when( - promise, - function (value) { - promises[index] = value; - if (--pendingCount === 0) { - deferred.resolve(promises); - } - }, - deferred.reject, - function (progress) { - deferred.notify({ index: index, value: progress }); - } - ); - } - }, void 0); - if (pendingCount === 0) { - deferred.resolve(promises); - } - return deferred.promise; - }); -} - -Promise.prototype.all = function () { - return all(this); -}; - -/** - * Returns the first resolved promise of an array. Prior rejected promises are - * ignored. Rejects only if all promises are rejected. - * @param {Array*} an array containing values or promises for values - * @returns a promise fulfilled with the value of the first resolved promise, - * or a rejected promise if all promises are rejected. - */ -Q.any = any; - -function any(promises) { - if (promises.length === 0) { - return Q.resolve(); - } - - var deferred = Q.defer(); - var pendingCount = 0; - array_reduce(promises, function (prev, current, index) { - var promise = promises[index]; - - pendingCount++; - - when(promise, onFulfilled, onRejected, onProgress); - function onFulfilled(result) { - deferred.resolve(result); - } - function onRejected(err) { - pendingCount--; - if (pendingCount === 0) { - err.message = ("Q can't get fulfillment value from any promise, all " + - "promises were rejected. Last error message: " + err.message); - deferred.reject(err); - } - } - function onProgress(progress) { - deferred.notify({ - index: index, - value: progress - }); - } - }, undefined); - - return deferred.promise; -} - -Promise.prototype.any = function () { - return any(this); -}; - -/** - * Waits for all promises to be settled, either fulfilled or - * rejected. This is distinct from `all` since that would stop - * waiting at the first rejection. The promise returned by - * `allResolved` will never be rejected. - * @param promises a promise for an array (or an array) of promises - * (or values) - * @return a promise for an array of promises - */ -Q.allResolved = deprecate(allResolved, "allResolved", "allSettled"); -function allResolved(promises) { - return when(promises, function (promises) { - promises = array_map(promises, Q); - return when(all(array_map(promises, function (promise) { - return when(promise, noop, noop); - })), function () { - return promises; - }); - }); -} - -Promise.prototype.allResolved = function () { - return allResolved(this); -}; - -/** - * @see Promise#allSettled - */ -Q.allSettled = allSettled; -function allSettled(promises) { - return Q(promises).allSettled(); -} - -/** - * Turns an array of promises into a promise for an array of their states (as - * returned by `inspect`) when they have all settled. - * @param {Array[Any*]} values an array (or promise for an array) of values (or - * promises for values) - * @returns {Array[State]} an array of states for the respective values. - */ -Promise.prototype.allSettled = function () { - return this.then(function (promises) { - return all(array_map(promises, function (promise) { - promise = Q(promise); - function regardless() { - return promise.inspect(); - } - return promise.then(regardless, regardless); - })); - }); -}; - -/** - * Captures the failure of a promise, giving an oportunity to recover - * with a callback. If the given promise is fulfilled, the returned - * promise is fulfilled. - * @param {Any*} promise for something - * @param {Function} callback to fulfill the returned promise if the - * given promise is rejected - * @returns a promise for the return value of the callback - */ -Q.fail = // XXX legacy -Q["catch"] = function (object, rejected) { - return Q(object).then(void 0, rejected); -}; - -Promise.prototype.fail = // XXX legacy -Promise.prototype["catch"] = function (rejected) { - return this.then(void 0, rejected); -}; - -/** - * Attaches a listener that can respond to progress notifications from a - * promise's originating deferred. This listener receives the exact arguments - * passed to ``deferred.notify``. - * @param {Any*} promise for something - * @param {Function} callback to receive any progress notifications - * @returns the given promise, unchanged - */ -Q.progress = progress; -function progress(object, progressed) { - return Q(object).then(void 0, void 0, progressed); -} - -Promise.prototype.progress = function (progressed) { - return this.then(void 0, void 0, progressed); -}; - -/** - * Provides an opportunity to observe the settling of a promise, - * regardless of whether the promise is fulfilled or rejected. Forwards - * the resolution to the returned promise when the callback is done. - * The callback can return a promise to defer completion. - * @param {Any*} promise - * @param {Function} callback to observe the resolution of the given - * promise, takes no arguments. - * @returns a promise for the resolution of the given promise when - * ``fin`` is done. - */ -Q.fin = // XXX legacy -Q["finally"] = function (object, callback) { - return Q(object)["finally"](callback); -}; - -Promise.prototype.fin = // XXX legacy -Promise.prototype["finally"] = function (callback) { - if (!callback || typeof callback.apply !== "function") { - throw new Error("Q can't apply finally callback"); - } - callback = Q(callback); - return this.then(function (value) { - return callback.fcall().then(function () { - return value; - }); - }, function (reason) { - // TODO attempt to recycle the rejection with "this". - return callback.fcall().then(function () { - throw reason; - }); - }); -}; - -/** - * Terminates a chain of promises, forcing rejections to be - * thrown as exceptions. - * @param {Any*} promise at the end of a chain of promises - * @returns nothing - */ -Q.done = function (object, fulfilled, rejected, progress) { - return Q(object).done(fulfilled, rejected, progress); -}; - -Promise.prototype.done = function (fulfilled, rejected, progress) { - var onUnhandledError = function (error) { - // forward to a future turn so that ``when`` - // does not catch it and turn it into a rejection. - Q.nextTick(function () { - makeStackTraceLong(error, promise); - if (Q.onerror) { - Q.onerror(error); - } else { - throw error; - } - }); - }; - - // Avoid unnecessary `nextTick`ing via an unnecessary `when`. - var promise = fulfilled || rejected || progress ? - this.then(fulfilled, rejected, progress) : - this; - - if (typeof process === "object" && process && process.domain) { - onUnhandledError = process.domain.bind(onUnhandledError); - } - - promise.then(void 0, onUnhandledError); -}; - -/** - * Causes a promise to be rejected if it does not get fulfilled before - * some milliseconds time out. - * @param {Any*} promise - * @param {Number} milliseconds timeout - * @param {Any*} custom error message or Error object (optional) - * @returns a promise for the resolution of the given promise if it is - * fulfilled before the timeout, otherwise rejected. - */ -Q.timeout = function (object, ms, error) { - return Q(object).timeout(ms, error); -}; - -Promise.prototype.timeout = function (ms, error) { - var deferred = defer(); - var timeoutId = setTimeout(function () { - if (!error || "string" === typeof error) { - error = new Error(error || "Timed out after " + ms + " ms"); - error.code = "ETIMEDOUT"; - } - deferred.reject(error); - }, ms); - - this.then(function (value) { - clearTimeout(timeoutId); - deferred.resolve(value); - }, function (exception) { - clearTimeout(timeoutId); - deferred.reject(exception); - }, deferred.notify); - - return deferred.promise; -}; - -/** - * Returns a promise for the given value (or promised value), some - * milliseconds after it resolved. Passes rejections immediately. - * @param {Any*} promise - * @param {Number} milliseconds - * @returns a promise for the resolution of the given promise after milliseconds - * time has elapsed since the resolution of the given promise. - * If the given promise rejects, that is passed immediately. - */ -Q.delay = function (object, timeout) { - if (timeout === void 0) { - timeout = object; - object = void 0; - } - return Q(object).delay(timeout); -}; - -Promise.prototype.delay = function (timeout) { - return this.then(function (value) { - var deferred = defer(); - setTimeout(function () { - deferred.resolve(value); - }, timeout); - return deferred.promise; - }); -}; - -/** - * Passes a continuation to a Node function, which is called with the given - * arguments provided as an array, and returns a promise. - * - * Q.nfapply(FS.readFile, [__filename]) - * .then(function (content) { - * }) - * - */ -Q.nfapply = function (callback, args) { - return Q(callback).nfapply(args); -}; - -Promise.prototype.nfapply = function (args) { - var deferred = defer(); - var nodeArgs = array_slice(args); - nodeArgs.push(deferred.makeNodeResolver()); - this.fapply(nodeArgs).fail(deferred.reject); - return deferred.promise; -}; - -/** - * Passes a continuation to a Node function, which is called with the given - * arguments provided individually, and returns a promise. - * @example - * Q.nfcall(FS.readFile, __filename) - * .then(function (content) { - * }) - * - */ -Q.nfcall = function (callback /*...args*/) { - var args = array_slice(arguments, 1); - return Q(callback).nfapply(args); -}; - -Promise.prototype.nfcall = function (/*...args*/) { - var nodeArgs = array_slice(arguments); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - this.fapply(nodeArgs).fail(deferred.reject); - return deferred.promise; -}; - -/** - * Wraps a NodeJS continuation passing function and returns an equivalent - * version that returns a promise. - * @example - * Q.nfbind(FS.readFile, __filename)("utf-8") - * .then(console.log) - * .done() - */ -Q.nfbind = -Q.denodeify = function (callback /*...args*/) { - if (callback === undefined) { - throw new Error("Q can't wrap an undefined function"); - } - var baseArgs = array_slice(arguments, 1); - return function () { - var nodeArgs = baseArgs.concat(array_slice(arguments)); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - Q(callback).fapply(nodeArgs).fail(deferred.reject); - return deferred.promise; - }; -}; - -Promise.prototype.nfbind = -Promise.prototype.denodeify = function (/*...args*/) { - var args = array_slice(arguments); - args.unshift(this); - return Q.denodeify.apply(void 0, args); -}; - -Q.nbind = function (callback, thisp /*...args*/) { - var baseArgs = array_slice(arguments, 2); - return function () { - var nodeArgs = baseArgs.concat(array_slice(arguments)); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - function bound() { - return callback.apply(thisp, arguments); - } - Q(bound).fapply(nodeArgs).fail(deferred.reject); - return deferred.promise; - }; -}; - -Promise.prototype.nbind = function (/*thisp, ...args*/) { - var args = array_slice(arguments, 0); - args.unshift(this); - return Q.nbind.apply(void 0, args); -}; - -/** - * Calls a method of a Node-style object that accepts a Node-style - * callback with a given array of arguments, plus a provided callback. - * @param object an object that has the named method - * @param {String} name name of the method of object - * @param {Array} args arguments to pass to the method; the callback - * will be provided by Q and appended to these arguments. - * @returns a promise for the value or error - */ -Q.nmapply = // XXX As proposed by "Redsandro" -Q.npost = function (object, name, args) { - return Q(object).npost(name, args); -}; - -Promise.prototype.nmapply = // XXX As proposed by "Redsandro" -Promise.prototype.npost = function (name, args) { - var nodeArgs = array_slice(args || []); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - this.dispatch("post", [name, nodeArgs]).fail(deferred.reject); - return deferred.promise; -}; - -/** - * Calls a method of a Node-style object that accepts a Node-style - * callback, forwarding the given variadic arguments, plus a provided - * callback argument. - * @param object an object that has the named method - * @param {String} name name of the method of object - * @param ...args arguments to pass to the method; the callback will - * be provided by Q and appended to these arguments. - * @returns a promise for the value or error - */ -Q.nsend = // XXX Based on Mark Miller's proposed "send" -Q.nmcall = // XXX Based on "Redsandro's" proposal -Q.ninvoke = function (object, name /*...args*/) { - var nodeArgs = array_slice(arguments, 2); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject); - return deferred.promise; -}; - -Promise.prototype.nsend = // XXX Based on Mark Miller's proposed "send" -Promise.prototype.nmcall = // XXX Based on "Redsandro's" proposal -Promise.prototype.ninvoke = function (name /*...args*/) { - var nodeArgs = array_slice(arguments, 1); - var deferred = defer(); - nodeArgs.push(deferred.makeNodeResolver()); - this.dispatch("post", [name, nodeArgs]).fail(deferred.reject); - return deferred.promise; -}; - -/** - * If a function would like to support both Node continuation-passing-style and - * promise-returning-style, it can end its internal promise chain with - * `nodeify(nodeback)`, forwarding the optional nodeback argument. If the user - * elects to use a nodeback, the result will be sent there. If they do not - * pass a nodeback, they will receive the result promise. - * @param object a result (or a promise for a result) - * @param {Function} nodeback a Node.js-style callback - * @returns either the promise or nothing - */ -Q.nodeify = nodeify; -function nodeify(object, nodeback) { - return Q(object).nodeify(nodeback); -} - -Promise.prototype.nodeify = function (nodeback) { - if (nodeback) { - this.then(function (value) { - Q.nextTick(function () { - nodeback(null, value); - }); - }, function (error) { - Q.nextTick(function () { - nodeback(error); - }); - }); - } else { - return this; - } -}; - -Q.noConflict = function() { - throw new Error("Q.noConflict only works when Q is used as a global"); -}; - -// All code before this point will be filtered from stack traces. -var qEndingLine = captureLine(); - -return Q; - -}); diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/queue.js b/StoneIsland/platforms/ios/cordova/node_modules/q/queue.js deleted file mode 100755 index 1505fd0b..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/q/queue.js +++ /dev/null @@ -1,35 +0,0 @@ - -var Q = require("./q"); - -module.exports = Queue; -function Queue() { - var ends = Q.defer(); - var closed = Q.defer(); - return { - put: function (value) { - var next = Q.defer(); - ends.resolve({ - head: value, - tail: next.promise - }); - ends.resolve = next.resolve; - }, - get: function () { - var result = ends.promise.get("head"); - ends.promise = ends.promise.get("tail"); - return result.fail(function (error) { - closed.resolve(error); - throw error; - }); - }, - closed: closed.promise, - close: function (error) { - error = error || new Error("Can't get value from closed queue"); - var end = {head: Q.reject(error)}; - end.tail = end; - ends.resolve(end); - return closed.promise; - } - }; -} - diff --git a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/LICENSE b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/LICENSE deleted file mode 100755 index 1b35ee9f..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2012, Artur Adib <aadib@mozilla.com> -All rights reserved. - -You may use this project under the terms of the New BSD license as follows: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Artur Adib nor the - names of the contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL ARTUR ADIB BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json deleted file mode 100755 index 24c80764..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "_from": "shelljs@^0.5.3", - "_id": "shelljs@0.5.3", - "_inBundle": true, - "_integrity": "sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=", - "_location": "/cordova-ios/shelljs", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "shelljs@^0.5.3", - "name": "shelljs", - "escapedName": "shelljs", - "rawSpec": "^0.5.3", - "saveSpec": null, - "fetchSpec": "^0.5.3" - }, - "_requiredBy": [ - "/cordova-ios", - "/cordova-ios/cordova-common" - ], - "_resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", - "_shasum": "c54982b996c76ef0c1e6b59fbdc5825f5b713113", - "_spec": "shelljs@^0.5.3", - "_where": "/Users/spindori/Documents/Cordova/cordova-ios", - "author": { - "name": "Artur Adib", - "email": "arturadib@gmail.com" - }, - "bin": { - "shjs": "./bin/shjs" - }, - "bugs": { - "url": "https://github.com/arturadib/shelljs/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "Portable Unix shell commands for Node.js", - "devDependencies": { - "jshint": "~2.1.11" - }, - "engines": { - "node": ">=0.8.0" - }, - "homepage": "http://github.com/arturadib/shelljs", - "keywords": [ - "unix", - "shell", - "makefile", - "make", - "jake", - "synchronous" - ], - "license": "BSD*", - "main": "./shell.js", - "name": "shelljs", - "optionalDependencies": {}, - "repository": { - "type": "git", - "url": "git://github.com/arturadib/shelljs.git" - }, - "scripts": { - "test": "node scripts/run-tests" - }, - "version": "0.5.3" -} diff --git a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js deleted file mode 100755 index bdeb5597..00000000 --- a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js +++ /dev/null @@ -1,159 +0,0 @@ -// -// ShellJS -// Unix shell commands on top of Node's API -// -// Copyright (c) 2012 Artur Adib -// http://github.com/arturadib/shelljs -// - -var common = require('./src/common'); - - -//@ -//@ All commands run synchronously, unless otherwise stated. -//@ - -//@include ./src/cd -var _cd = require('./src/cd'); -exports.cd = common.wrap('cd', _cd); - -//@include ./src/pwd -var _pwd = require('./src/pwd'); -exports.pwd = common.wrap('pwd', _pwd); - -//@include ./src/ls -var _ls = require('./src/ls'); -exports.ls = common.wrap('ls', _ls); - -//@include ./src/find -var _find = require('./src/find'); -exports.find = common.wrap('find', _find); - -//@include ./src/cp -var _cp = require('./src/cp'); -exports.cp = common.wrap('cp', _cp); - -//@include ./src/rm -var _rm = require('./src/rm'); -exports.rm = common.wrap('rm', _rm); - -//@include ./src/mv -var _mv = require('./src/mv'); -exports.mv = common.wrap('mv', _mv); - -//@include ./src/mkdir -var _mkdir = require('./src/mkdir'); -exports.mkdir = common.wrap('mkdir', _mkdir); - -//@include ./src/test -var _test = require('./src/test'); -exports.test = common.wrap('test', _test); - -//@include ./src/cat -var _cat = require('./src/cat'); -exports.cat = common.wrap('cat', _cat); - -//@include ./src/to -var _to = require('./src/to'); -String.prototype.to = common.wrap('to', _to); - -//@include ./src/toEnd -var _toEnd = require('./src/toEnd'); -String.prototype.toEnd = common.wrap('toEnd', _toEnd); - -//@include ./src/sed -var _sed = require('./src/sed'); -exports.sed = common.wrap('sed', _sed); - -//@include ./src/grep -var _grep = require('./src/grep'); -exports.grep = common.wrap('grep', _grep); - -//@include ./src/which -var _which = require('./src/which'); -exports.which = common.wrap('which', _which); - -//@include ./src/echo -var _echo = require('./src/echo'); -exports.echo = _echo; // don't common.wrap() as it could parse '-options' - -//@include ./src/dirs -var _dirs = require('./src/dirs').dirs; -exports.dirs = common.wrap("dirs", _dirs); -var _pushd = require('./src/dirs').pushd; -exports.pushd = common.wrap('pushd', _pushd); -var _popd = require('./src/dirs').popd; -exports.popd = common.wrap("popd", _popd); - -//@include ./src/ln -var _ln = require('./src/ln'); -exports.ln = common.wrap('ln', _ln); - -//@ -//@ ### exit(code) -//@ Exits the current process with the given exit code. -exports.exit = process.exit; - -//@ -//@ ### env['VAR_NAME'] -//@ Object containing environment variables (both getter and setter). Shortcut to process.env. -exports.env = process.env; - -//@include ./src/exec -var _exec = require('./src/exec'); -exports.exec = common.wrap('exec', _exec, {notUnix:true}); - -//@include ./src/chmod -var _chmod = require('./src/chmod'); -exports.chmod = common.wrap('chmod', _chmod); - - - -//@ -//@ ## Non-Unix commands -//@ - -//@include ./src/tempdir -var _tempDir = require('./src/tempdir'); -exports.tempdir = common.wrap('tempdir', _tempDir); - - -//@include ./src/error -var _error = require('./src/error'); -exports.error = _error; - - - -//@ -//@ ## Configuration -//@ - -exports.config = common.config; - -//@ -//@ ### config.silent -//@ Example: -//@ -//@ ```javascript -//@ var sh = require('shelljs'); -//@ var silentState = sh.config.silent; // save old silent state -//@ sh.config.silent = true; -//@ /* ... */ -//@ sh.config.silent = silentState; // restore old silent state -//@ ``` -//@ -//@ Suppresses all command output if `true`, except for `echo()` calls. -//@ Default is `false`. - -//@ -//@ ### config.fatal -//@ Example: -//@ -//@ ```javascript -//@ require('shelljs/global'); -//@ config.fatal = true; -//@ cp('this_file_does_not_exist', '/dev/null'); // dies here -//@ /* more commands... */ -//@ ``` -//@ -//@ If `true` the script will die on errors. Default is `false`. diff --git a/StoneIsland/platforms/ios/cordova/run b/StoneIsland/platforms/ios/cordova/run index 470384b5..9e6c8f91 100755 --- a/StoneIsland/platforms/ios/cordova/run +++ b/StoneIsland/platforms/ios/cordova/run @@ -19,45 +19,48 @@ under the License. */ - var args = process.argv; var Api = require('./Api'); var nopt = require('nopt'); // Handle help flag -if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { +if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) { require('./lib/run').help(); process.exit(0); } // Parse arguments (includes build params as well) var opts = nopt({ - 'verbose' : Boolean, - 'silent' : Boolean, - 'debug': Boolean, - 'release': Boolean, - 'nobuild': Boolean, - 'archs': String, - 'list': Boolean, - 'device': Boolean, - 'emulator': Boolean, - 'target' : String, - 'codeSignIdentity': String, - 'codeSignResourceRules': String, - 'provisioningProfile': String, - 'buildConfig' : String, - 'noSign' : Boolean -}, { 'd' : '--verbose' }, args); + verbose: Boolean, + silent: Boolean, + debug: Boolean, + release: Boolean, + nobuild: Boolean, + archs: String, + list: Boolean, + device: Boolean, + emulator: Boolean, + target: String, + codeSignIdentity: String, + codeSignResourceRules: String, + provisioningProfile: String, + automaticProvisioning: Boolean, + buildConfig: String, + noSign: Boolean +}, { d: '--verbose' }, args); // Make options compatible with PlatformApi build method spec opts.argv = opts.argv.remain; require('./loggingHelper').adjustLoggerLevel(opts); -new Api().run(opts).done(function() { +new Api().run(opts).then( + () => { console.log('** RUN SUCCEEDED **'); - }, function (err) { + }, + err => { var errorMessage = (err && err.stack) ? err.stack : err; console.error(errorMessage); process.exit(2); - }); + } +); diff --git a/StoneIsland/platforms/ios/cordova/version b/StoneIsland/platforms/ios/cordova/version index 979cba13..6bb657b4 100755 --- a/StoneIsland/platforms/ios/cordova/version +++ b/StoneIsland/platforms/ios/cordova/version @@ -26,10 +26,6 @@ */ // Coho updates this line -var VERSION="4.5.2"; +const Api = require('./Api'); -module.exports.version = VERSION; - -if (!module.parent) { - console.log(VERSION); -} +console.log(Api.version()); |
