Current behavior:
During installation of cordova-plugin-firebasex, it runs the after_prepare.js script. If a plugin defined in config.xml has exactly one variable defined, like this:
<plugin name="cordova.plugins.diagnostic" spec="~5.0.0">
<variable name="ANDROID_SUPPORT_VERSION" value="28.+" />
</plugin>
Then the script will throw an error and cordova will not complete its installation:
Executing script found in plugin cordova-plugin-firebasex for hook "after_prepare": plugins/cordova-plugin-firebasex/scripts/after_prepare.js
(plugin.variable || []).forEach is not a function
TypeError: (plugin.variable || []).forEach is not a function
at /Users/cordova-developer/dev/cordova-plugin-firebasex-test/plugins/cordova-plugin-firebasex/scripts/after_prepare.js:49:33
at Array.forEach (<anonymous>)
at parsePluginVariables (/Users/cordova-developer/dev/cordova-plugin-firebasex-test/plugins/cordova-plugin-firebasex/scripts/after_prepare.js:48:34)
at module.exports (/Users/cordova-developer/dev/cordova-plugin-firebasex-test/plugins/cordova-plugin-firebasex/scripts/after_prepare.js:73:3)
at runScriptViaModuleLoader (/Users/cordova-developer/.nvm/versions/node/v12.13.0/lib/node_modules/cordova/node_modules/cordova-lib/src/hooks/HooksRunner.js:181:32)
at runScript (/Users/cordova-developer/.nvm/versions/node/v12.13.0/lib/node_modules/cordova/node_modules/cordova-lib/src/hooks/HooksRunner.js:157:16)
at /Users/cordova-developer/.nvm/versions/node/v12.13.0/lib/node_modules/cordova/node_modules/cordova-lib/src/hooks/HooksRunner.js:125:20
If I add a second fake variable to the plugin with only one variable, then the after_prepare.js script runs without errors. Like this:
<plugin name="cordova.plugins.diagnostic" spec="~5.0.0">
<variable name="ANDROID_SUPPORT_VERSION" value="28.+" />
<variable name="fake_variable_for_cordova_plugin_firebasex_7_0_0_support" value="ok" />
</plugin>
I think this is related to the xml-js conversion process. If if there are two or more child nodes of the same type, they become an array. But if there is only one child node of that type, it becomes an object. (See the Compact JSON example at the top of the page and compare <title> and <todo> conversion.)
Another drawback of compact output is the resultant element can be an object or an array and therefore makes the client code a little awkward in terms of the extra check needed on object type before processing. (source)
Expected behavior:
The after_prepare script should handle various config.xml files smoothly.
Steps to reproduce:
npm installnpx cordova prepare ios --verbose and the above error should appearEnvironment information
$ cordova -v
9.0.0 ([email protected])
$ cordova platform ls
Installed platforms:
ios 5.0.1
Available platforms:
android ^8.0.0
browser ^6.0.0
electron ^1.0.0
osx ^5.0.0
windows ^7.0.0
$ cordova plugin ls
cordova-custom-config 5.1.0 "cordova-custom-config"
cordova-plugin-androidx 1.0.2 "cordova-plugin-androidx"
cordova-plugin-androidx-adapter 1.1.0 "cordova-plugin-androidx-adapter"
cordova-plugin-customfcmreceiver 1.0.0 "Custom FCM Receiver"
cordova-plugin-firebasex 7.0.0 "Google Firebase Plugin"
cordova-plugin-whitelist 1.3.4 "Whitelist"
cordova.plugins.diagnostic 5.0.1 "Diagnostic"
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.6
BuildVersion: 17G9016
$ node -v
v12.13.0
Related code:
The related code is this plugin.variable line in after_prepare.js. It assumes that plugin.variable is always an array or undefined, but it can also be an object if there is exactly one variable defined.
var parsePluginVariables = function(){
var config = Utilities.parseConfigXml();
(config.widget.plugin || []).forEach(function(plugin){
(plugin.variable || []).forEach(function(variable){
if((plugin._attributes.name === PLUGIN_ID || plugin._attributes.id === PLUGIN_ID) && variable._attributes.name && variable._attributes.value){
pluginVariables[variable._attributes.name] = variable._attributes.value;
}
});
});
var packageJSON = Utilities.parsePackageJson();
if(packageJSON.cordova && packageJSON.cordova.plugins){
for(const pluginId in packageJSON.cordova.plugins){
if(pluginId === PLUGIN_ID){
for(const varName in packageJSON.cordova.plugins[pluginId]){
var varValue = packageJSON.cordova.plugins[pluginId][varName];
pluginVariables[varName] = varValue;
}
}
}
}
};
Nearly the same thing happens if there is only one plugin configuration present in config.xml. I just opened a PR #219 to fix this issue.
Resolved by #219 (thanks to @mahnuh)
Most helpful comment
Nearly the same thing happens if there is only one plugin configuration present in config.xml. I just opened a PR #219 to fix this issue.