| /* |
| * 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. |
| * |
| */ |
| |
| var fs = require('fs-extra'); |
| var path = require('path'); |
| var endent = require('endent'); |
| var mungeutil = require('./ConfigChanges/munge-util'); |
| |
| function PlatformJson (filePath, platform, root) { |
| this.filePath = filePath; |
| this.platform = platform; |
| this.root = fix_munge(root || {}); |
| } |
| |
| PlatformJson.load = function (plugins_dir, platform) { |
| var filePath = path.join(plugins_dir, platform + '.json'); |
| var root = null; |
| if (fs.existsSync(filePath)) { |
| root = JSON.parse(fs.readFileSync(filePath, 'utf-8')); |
| } |
| return new PlatformJson(filePath, platform, root); |
| }; |
| |
| PlatformJson.prototype.save = function () { |
| fs.outputJsonSync(this.filePath, this.root, { spaces: 2 }); |
| }; |
| |
| /** |
| * Indicates whether the specified plugin is installed as a top-level (not as |
| * dependency to others) |
| * @method function |
| * @param {String} pluginId A plugin id to check for. |
| * @return {Boolean} true if plugin installed as top-level, otherwise false. |
| */ |
| PlatformJson.prototype.isPluginTopLevel = function (pluginId) { |
| return this.root.installed_plugins[pluginId]; |
| }; |
| |
| /** |
| * Indicates whether the specified plugin is installed as a dependency to other |
| * plugin. |
| * @method function |
| * @param {String} pluginId A plugin id to check for. |
| * @return {Boolean} true if plugin installed as a dependency, otherwise false. |
| */ |
| PlatformJson.prototype.isPluginDependent = function (pluginId) { |
| return this.root.dependent_plugins[pluginId]; |
| }; |
| |
| /** |
| * Indicates whether plugin is installed either as top-level or as dependency. |
| * @method function |
| * @param {String} pluginId A plugin id to check for. |
| * @return {Boolean} true if plugin installed, otherwise false. |
| */ |
| PlatformJson.prototype.isPluginInstalled = function (pluginId) { |
| return this.isPluginTopLevel(pluginId) || |
| this.isPluginDependent(pluginId); |
| }; |
| |
| PlatformJson.prototype.addPlugin = function (pluginId, variables, isTopLevel) { |
| var pluginsList = isTopLevel |
| ? this.root.installed_plugins |
| : this.root.dependent_plugins; |
| |
| pluginsList[pluginId] = variables; |
| |
| return this; |
| }; |
| |
| /** |
| * @chaining |
| * Generates and adds metadata for provided plugin into associated <platform>.json file |
| * |
| * @param {PluginInfo} pluginInfo A pluginInfo instance to add metadata from |
| * @returns {this} Current PlatformJson instance to allow calls chaining |
| */ |
| PlatformJson.prototype.addPluginMetadata = function (pluginInfo) { |
| var installedModules = this.root.modules || []; |
| |
| var installedPaths = installedModules.map(function (installedModule) { |
| return installedModule.file; |
| }); |
| |
| var modulesToInstall = pluginInfo.getJsModules(this.platform) |
| .map(function (module) { |
| return new ModuleMetadata(pluginInfo.id, module); |
| }) |
| .filter(function (metadata) { |
| // Filter out modules which are already added to metadata |
| return !installedPaths.includes(metadata.file); |
| }); |
| |
| this.root.modules = installedModules.concat(modulesToInstall); |
| |
| this.root.plugin_metadata = this.root.plugin_metadata || {}; |
| this.root.plugin_metadata[pluginInfo.id] = pluginInfo.version; |
| |
| return this; |
| }; |
| |
| PlatformJson.prototype.removePlugin = function (pluginId, isTopLevel) { |
| var pluginsList = isTopLevel |
| ? this.root.installed_plugins |
| : this.root.dependent_plugins; |
| |
| delete pluginsList[pluginId]; |
| |
| return this; |
| }; |
| |
| /** |
| * @chaining |
| * Removes metadata for provided plugin from associated file |
| * |
| * @param {PluginInfo} pluginInfo A PluginInfo instance to which modules' metadata |
| * we need to remove |
| * |
| * @returns {this} Current PlatformJson instance to allow calls chaining |
| */ |
| PlatformJson.prototype.removePluginMetadata = function (pluginInfo) { |
| var modulesToRemove = pluginInfo.getJsModules(this.platform) |
| .map(function (jsModule) { |
| return ['plugins', pluginInfo.id, jsModule.src].join('/'); |
| }); |
| |
| var installedModules = this.root.modules || []; |
| this.root.modules = installedModules |
| .filter(function (installedModule) { |
| // Leave only those metadatas which 'file' is not in removed modules |
| return !modulesToRemove.includes(installedModule.file); |
| }); |
| |
| if (this.root.plugin_metadata) { |
| delete this.root.plugin_metadata[pluginInfo.id]; |
| } |
| |
| return this; |
| }; |
| |
| PlatformJson.prototype.addInstalledPluginToPrepareQueue = function (pluginDirName, vars, is_top_level, force) { |
| this.root.prepare_queue.installed.push({ plugin: pluginDirName, vars: vars, topLevel: is_top_level, force: force }); |
| }; |
| |
| PlatformJson.prototype.addUninstalledPluginToPrepareQueue = function (pluginId, is_top_level) { |
| this.root.prepare_queue.uninstalled.push({ plugin: pluginId, id: pluginId, topLevel: is_top_level }); |
| }; |
| |
| /** |
| * Moves plugin, specified by id to top-level plugins. If plugin is top-level |
| * already, then does nothing. |
| * @method function |
| * @param {String} pluginId A plugin id to make top-level. |
| * @return {PlatformJson} PlatformJson instance. |
| */ |
| PlatformJson.prototype.makeTopLevel = function (pluginId) { |
| var plugin = this.root.dependent_plugins[pluginId]; |
| if (plugin) { |
| delete this.root.dependent_plugins[pluginId]; |
| this.root.installed_plugins[pluginId] = plugin; |
| } |
| return this; |
| }; |
| |
| /** |
| * Generates a metadata for all installed plugins and js modules. The resultant |
| * string is ready to be written to 'cordova_plugins.js' |
| * |
| * @returns {String} cordova_plugins.js contents |
| */ |
| PlatformJson.prototype.generateMetadata = function () { |
| const stringify = o => JSON.stringify(o, null, 2); |
| return endent` |
| cordova.define('cordova/plugin_list', function(require, exports, module) { |
| module.exports = ${stringify(this.root.modules)}; |
| module.exports.metadata = ${stringify(this.root.plugin_metadata)}; |
| }); |
| `; |
| }; |
| |
| /** |
| * @chaining |
| * Generates and then saves metadata to specified file. Doesn't check if file exists. |
| * |
| * @param {String} destination File metadata will be written to |
| * @return {PlatformJson} PlatformJson instance |
| */ |
| PlatformJson.prototype.generateAndSaveMetadata = function (destination) { |
| fs.outputFileSync(destination, this.generateMetadata()); |
| |
| return this; |
| }; |
| |
| // convert a munge from the old format ([file][parent][xml] = count) to the current one |
| function fix_munge (root) { |
| root.prepare_queue = root.prepare_queue || { installed: [], uninstalled: [] }; |
| root.config_munge = root.config_munge || { files: {} }; |
| root.installed_plugins = root.installed_plugins || {}; |
| root.dependent_plugins = root.dependent_plugins || {}; |
| |
| var munge = root.config_munge; |
| if (!munge.files) { |
| var new_munge = { files: {} }; |
| for (var file in munge) { |
| for (var selector in munge[file]) { |
| for (var xml_child in munge[file][selector]) { |
| var val = parseInt(munge[file][selector][xml_child]); |
| for (var i = 0; i < val; i++) { |
| mungeutil.deep_add(new_munge, [file, selector, { xml: xml_child, count: val }]); |
| } |
| } |
| } |
| } |
| root.config_munge = new_munge; |
| } |
| |
| return root; |
| } |
| |
| /** |
| * @constructor |
| * @class ModuleMetadata |
| * |
| * Creates a ModuleMetadata object that represents module entry in 'cordova_plugins.js' |
| * file at run time |
| * |
| * @param {String} pluginId Plugin id where this module installed from |
| * @param (JsModule|Object) jsModule A js-module entry from PluginInfo class to generate metadata for |
| */ |
| function ModuleMetadata (pluginId, jsModule) { |
| if (!pluginId) throw new TypeError('pluginId argument must be a valid plugin id'); |
| if (!jsModule.src && !jsModule.name) throw new TypeError('jsModule argument must contain src or/and name properties'); |
| |
| this.id = pluginId + '.' + (jsModule.name || jsModule.src.match(/([^/]+)\.js/)[1]); |
| this.file = ['plugins', pluginId, jsModule.src].join('/'); |
| this.pluginId = pluginId; |
| |
| if (jsModule.clobbers && jsModule.clobbers.length > 0) { |
| this.clobbers = jsModule.clobbers.map(function (o) { return o.target; }); |
| } |
| if (jsModule.merges && jsModule.merges.length > 0) { |
| this.merges = jsModule.merges.map(function (o) { return o.target; }); |
| } |
| if (jsModule.runs) { |
| this.runs = true; |
| } |
| } |
| |
| module.exports = PlatformJson; |