You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by er...@apache.org on 2026/06/08 04:12:18 UTC

(cordova-browser) branch master updated: chore!: refactor & cleanup (#155)

This is an automated email from the ASF dual-hosted git repository.

erisu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-browser.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e4c0de  chore!: refactor & cleanup (#155)
4e4c0de is described below

commit 4e4c0de45fc64f84ce427bca26e507fc87176ec0
Author: エリス <er...@users.noreply.github.com>
AuthorDate: Mon Jun 8 13:12:12 2026 +0900

    chore!: refactor & cleanup (#155)
    
    * refactor: cleanup require blocks
    * refactor(Api): convert to class
    * refactor(Api): getPlatformInfo
    * refactor(Api): prepare
    * refactor(Api): _updateWww
    * refactor(Api): addPlugin
    * refactor(Api): removePlugin
    * refactor(Api)!: _getInstaller
    * refactor(Api)!: _getUninstaller
    * refactor(Api): _addModulesInfo
    * refactor(Api): _writePluginModules & _removeModulesInfo
    * refactor(Api): build, run, clean & requirements
    * refactor(Api): build
    * chore(Api): set async where needed
    * refactor(Api): dont allow changing of platform name
    * chore(Api): add static method version & match other platforms
    * chore!: remove unnecessary node shebang
    * refactor: module require order
    * refactor: cleanup events variable naming
    * refactor: use template literals where possible
    * refactor: use arrow functions where possible
    * chore!: update private method prefix '#_' to '#'
---
 lib/Api.js                   | 869 +++++++++++++++++++++----------------------
 lib/browser_handler.js       |   9 +-
 lib/browser_parser.js        |  15 +-
 lib/build.js                 |   5 +-
 lib/check_reqs.js            |   2 -
 lib/clean.js                 |   6 +-
 lib/create.js                |   9 +-
 lib/run.js                   |   9 +-
 lib/update.js                |   4 +-
 spec/browser_handler.spec.js |   3 +-
 spec/projectApi.spec.js      |   5 +-
 templates/cordova/version    |   5 +-
 12 files changed, 469 insertions(+), 472 deletions(-)

diff --git a/lib/Api.js b/lib/Api.js
index ac9f915..db3e97b 100644
--- a/lib/Api.js
+++ b/lib/Api.js
@@ -25,178 +25,181 @@
 const path = require('node:path');
 const fs = require('node:fs');
 
-const cdvcmn = require('cordova-common');
-const CordovaLogger = cdvcmn.CordovaLogger;
-const ConfigParser = cdvcmn.ConfigParser;
-const ActionStack = cdvcmn.ActionStack;
-const selfEvents = cdvcmn.events;
-const xmlHelpers = cdvcmn.xmlHelpers;
-const PlatformJson = cdvcmn.PlatformJson;
-const PlatformMunger = cdvcmn.ConfigChanges.PlatformMunger;
-const PluginInfoProvider = cdvcmn.PluginInfoProvider;
-const CordovaError = cdvcmn.CordovaError;
-const FileUpdater = cdvcmn.FileUpdater;
+const {
+    ActionStack,
+    ConfigChanges: { PlatformMunger },
+    ConfigParser,
+    CordovaLogger,
+    CordovaError,
+    events,
+    FileUpdater,
+    PlatformJson,
+    PluginInfoProvider,
+    xmlHelpers
+} = require('cordova-common');
 
 const { createProject } = require('./create');
+const VERSION = require('../package').version;
 
-const PLATFORM_NAME = 'browser';
+const PLATFORM = 'browser';
 
 function setupEvents (externalEventEmitter) {
     if (externalEventEmitter) {
         // This will make the platform internal events visible outside
-        selfEvents.forwardEventsTo(externalEventEmitter);
+        events.forwardEventsTo(externalEventEmitter);
         return externalEventEmitter;
     }
 
     // There is no logger if external emitter is not present,
     // so attach a console logger
-    CordovaLogger.get().subscribe(selfEvents);
-    return selfEvents;
+    CordovaLogger.get().subscribe(events);
+    return events;
 }
 
 /**
  * Logs all file operations via the verbose event stream, indented.
  */
 function logFileOp (message) {
-    selfEvents.emit('verbose', '  ' + message);
+    events.emit('verbose', `  ${message}`);
 }
 
 function dirExists (dir) {
     return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
 }
 
-function Api (platform, platformRootDir, events) {
-    this.platform = platform || PLATFORM_NAME;
-    this.root = platformRootDir;
-    this.events = setupEvents(events);
-    if (!dirExists(this.root) || !dirExists(path.join(this.root, 'cordova'))) {
-        throw new CordovaError('The provided path "' + this.root + '" is not a valid browser project.');
-    }
-    this._handler = require('./browser_handler');
-
-    this.locations = {
-        platformRootDir,
-        root: this.root,
-        www: path.join(this.root, 'www'),
-        res: path.join(this.root, 'res'),
-        platformWww: path.join(this.root, 'platform_www'),
-        configXml: path.join(this.root, 'config.xml'),
-        defaultConfigXml: path.join(this.root, 'cordova/defaults.xml'),
-        build: path.join(this.root, 'build'),
-        // NOTE: Due to platformApi spec we need to return relative paths here
-        cordovaJs: 'templates/project/assets/www/cordova.js',
-        cordovaJsSrc: 'cordova-js-src'
-    };
-
-    this._platformJson = PlatformJson.load(this.root, platform);
-    this._pluginInfoProvider = new PluginInfoProvider();
-    this._munger = new PlatformMunger(platform, this.root, this._platformJson, this._pluginInfoProvider);
-}
-
-Api.createPlatform = function (dest, config, options, events) {
-    events = setupEvents(events);
+class Api {
+    constructor (platform, platformRootDir, externalEventEmitter) {
+        this.platform = PLATFORM;
+        this.root = platformRootDir;
+        this.events = setupEvents(externalEventEmitter);
+        if (!dirExists(this.root) || !dirExists(path.join(this.root, 'cordova'))) {
+            throw new CordovaError(`The provided path "${this.root}" is not a valid browser project.`);
+        }
+        this._handler = require('./browser_handler');
+
+        this.locations = {
+            platformRootDir,
+            root: this.root,
+            www: path.join(this.root, 'www'),
+            res: path.join(this.root, 'res'),
+            platformWww: path.join(this.root, 'platform_www'),
+            configXml: path.join(this.root, 'config.xml'),
+            defaultConfigXml: path.join(this.root, 'cordova/defaults.xml'),
+            build: path.join(this.root, 'build'),
+            // NOTE: Due to platformApi spec we need to return relative paths here
+            cordovaJs: 'templates/project/assets/www/cordova.js',
+            cordovaJsSrc: 'cordova-js-src'
+        };
 
-    const name = config.name().normalize('NFD');
+        this._platformJson = PlatformJson.load(this.root, this.platform);
+        this._pluginInfoProvider = new PluginInfoProvider();
+        this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
+    }
 
-    try {
-        // we create the project using our scripts in this platform
-        return createProject(dest, config.packageName(), name, options, config)
-            .then(function () {
-                // after platform is created we return Api instance based on new Api.js location
-                // Api.js has been copied to the new project
-                // This is required to correctly resolve paths in the future api calls
-                const PlatformApi = require(path.resolve(dest, 'cordova/Api'));
-                return new PlatformApi('browser', dest, events);
-            });
-    } catch (e) {
-        events.emit('error', 'createPlatform is not callable from the browser project API.');
-        throw (e);
+    static async createPlatform (dest, config, options, externalEventEmitter) {
+        externalEventEmitter = setupEvents(externalEventEmitter);
+
+        const name = config.name().normalize('NFD');
+
+        try {
+            // we create the project using our scripts in this platform
+            return createProject(dest, config.packageName(), name, options, config)
+                .then(function () {
+                    // after platform is created we return Api instance based on new Api.js location
+                    // Api.js has been copied to the new project
+                    // This is required to correctly resolve paths in the future api calls
+                    const PlatformApi = require(path.resolve(dest, 'cordova/Api'));
+                    return new PlatformApi('browser', dest, externalEventEmitter);
+                });
+        } catch (e) {
+            externalEventEmitter.emit('error', 'createPlatform is not callable from the browser project API.');
+            throw (e);
+        }
     }
-};
-
-Api.updatePlatform = function (dest, options, events) {
-    // console.log("test-platform:Api:updatePlatform");
-    // todo?: create projectInstance and fulfill promise with it.
-    return Promise.resolve();
-};
-
-Api.prototype.getPlatformInfo = function () {
-    // console.log("browser-platform:Api:getPlatformInfo");
-    // return PlatformInfo object
-    return {
-        locations: this.locations,
-        root: this.root,
-        name: this.platform,
-        version: { version: '1.0.0' }, // um, todo!
-        projectConfig: this.config
-    };
-};
-
-Api.prototype.prepare = async function (cordovaProject, options) {
-    // First cleanup current config and merge project's one into own
-    const defaultConfigPath = path.join(this.locations.platformRootDir, 'cordova',
-        'defaults.xml');
-    const ownConfigPath = this.locations.configXml;
-    const sourceCfg = cordovaProject.projectConfig;
-
-    // If defaults.xml is present, overwrite platform config.xml with it.
-    // Otherwise save whatever is there as defaults so it can be
-    // restored or copy project config into platform if none exists.
-    if (fs.existsSync(defaultConfigPath)) {
-        this.events.emit('verbose', 'Generating config.xml from defaults for platform "' + this.platform + '"');
-        fs.cpSync(defaultConfigPath, ownConfigPath, { force: true });
-    } else if (fs.existsSync(ownConfigPath)) {
-        this.events.emit('verbose', 'Generating defaults.xml from own config.xml for platform "' + this.platform + '"');
-        fs.cpSync(ownConfigPath, defaultConfigPath, { force: true });
-    } else {
-        this.events.emit('verbose', 'case 3"' + this.platform + '"');
-        fs.cpSync(sourceCfg.path, ownConfigPath, { force: true });
+
+    static async updatePlatform (dest, options, events) {
+        // console.log("test-platform:Api:updatePlatform");
+        // todo?: create projectInstance and fulfill promise with it.
+        return Promise.resolve();
     }
 
-    // merge our configs
-    this.config = new ConfigParser(ownConfigPath);
-    xmlHelpers.mergeXml(cordovaProject.projectConfig.doc.getroot(),
-        this.config.doc.getroot(),
-        this.platform, true);
-    this.config.write();
-
-    // Update own www dir with project's www assets and plugins' assets and js-files
-    this._updateWww(cordovaProject);
-
-    // Copy or Create manifest.json
-    // todo: move this to a manifest helper module
-    // output path
-    const manifestPath = path.join(this.locations.www, 'manifest.json');
-    const srcManifestPath = path.join(cordovaProject.locations.www, 'manifest.json');
-    if (fs.existsSync(srcManifestPath)) {
-        // just blindly copy it to our output/www
-        // todo: validate it? ensure all properties we expect exist?
-        this.events.emit('verbose', 'copying ' + srcManifestPath + ' => ' + manifestPath);
-        fs.cpSync(srcManifestPath, manifestPath, { force: true });
-    } else {
-        const manifestJson = {
-            background_color: '#FFF',
-            display: 'standalone'
+    getPlatformInfo () {
+        // console.log("browser-platform:Api:getPlatformInfo");
+        // return PlatformInfo object
+        return {
+            locations: this.locations,
+            root: this.root,
+            name: this.platform,
+            version: Api.version(),
+            projectConfig: this.config
         };
-        if (this.config) {
-            if (this.config.name()) {
-                manifestJson.name = this.config.name();
-            }
-            if (this.config.shortName()) {
-                manifestJson.short_name = this.config.shortName();
-            }
-            if (this.config.packageName()) {
-                manifestJson.version = this.config.packageName();
-            }
-            if (this.config.description()) {
-                manifestJson.description = this.config.description();
-            }
-            if (this.config.author()) {
-                manifestJson.author = this.config.author();
-            }
-            // icons
-            const icons = this.config.getStaticResources('browser', 'icon');
-            const manifestIcons = icons.map(function (icon) {
+    }
+
+    async prepare (cordovaProject, options) {
+        // First cleanup current config and merge project's one into own
+        const defaultConfigPath = path.join(this.locations.platformRootDir, 'cordova',
+            'defaults.xml');
+        const ownConfigPath = this.locations.configXml;
+        const sourceCfg = cordovaProject.projectConfig;
+
+        // If defaults.xml is present, overwrite platform config.xml with it.
+        // Otherwise save whatever is there as defaults so it can be
+        // restored or copy project config into platform if none exists.
+        if (fs.existsSync(defaultConfigPath)) {
+            this.events.emit('verbose', `Generating config.xml from defaults for platform "${this.platform}"`);
+            fs.cpSync(defaultConfigPath, ownConfigPath, { force: true });
+        } else if (fs.existsSync(ownConfigPath)) {
+            this.events.emit('verbose', `Generating defaults.xml from own config.xml for platform "${this.platform}"`);
+            fs.cpSync(ownConfigPath, defaultConfigPath, { force: true });
+        } else {
+            this.events.emit('verbose', `case 3"${this.platform}"`);
+            fs.cpSync(sourceCfg.path, ownConfigPath, { force: true });
+        }
+
+        // merge our configs
+        this.config = new ConfigParser(ownConfigPath);
+        xmlHelpers.mergeXml(cordovaProject.projectConfig.doc.getroot(),
+            this.config.doc.getroot(),
+            this.platform, true);
+        this.config.write();
+
+        // Update own www dir with project's www assets and plugins' assets and js-files
+        this.#updateWww(cordovaProject);
+
+        // Copy or Create manifest.json
+        // todo: move this to a manifest helper module
+        // output path
+        const manifestPath = path.join(this.locations.www, 'manifest.json');
+        const srcManifestPath = path.join(cordovaProject.locations.www, 'manifest.json');
+        if (fs.existsSync(srcManifestPath)) {
+            // just blindly copy it to our output/www
+            // todo: validate it? ensure all properties we expect exist?
+            this.events.emit('verbose', `copying ${srcManifestPath} => ${manifestPath}`);
+            fs.cpSync(srcManifestPath, manifestPath, { force: true });
+        } else {
+            const manifestJson = {
+                background_color: '#FFF',
+                display: 'standalone'
+            };
+            if (this.config) {
+                if (this.config.name()) {
+                    manifestJson.name = this.config.name();
+                }
+                if (this.config.shortName()) {
+                    manifestJson.short_name = this.config.shortName();
+                }
+                if (this.config.packageName()) {
+                    manifestJson.version = this.config.packageName();
+                }
+                if (this.config.description()) {
+                    manifestJson.description = this.config.description();
+                }
+                if (this.config.author()) {
+                    manifestJson.author = this.config.author();
+                }
+                // icons
+                const icons = this.config.getStaticResources('browser', 'icon');
+
                 // given a tag like this :
                 // <icon src="res/ios/icon.png" width="57" height="57" density="mdpi" />
                 /* configParser returns icons that look like this :
@@ -213,348 +216,336 @@ Api.prototype.prepare = async function (cordovaProject, options) {
                     "sizes": "128x128"
                 } ******/
                 // ?Is it worth looking at file extentions?
-                return {
+                const manifestIcons = icons.map(icon => ({
                     src: icon.src,
                     type: 'image/png',
-                    sizes: (icon.width + 'x' + icon.height)
-                };
-            });
-            manifestJson.icons = manifestIcons;
-
-            // orientation
-            // <preference name="Orientation" value="landscape" />
-            const oriPref = this.config.getGlobalPreference('Orientation');
-            if (oriPref) {
-                // if it's a supported value, use it
-                if (['landscape', 'portrait'].indexOf(oriPref) > -1) {
-                    manifestJson.orientation = oriPref;
-                } else { // anything else maps to 'any'
-                    manifestJson.orientation = 'any';
+                    sizes: `${icon.width}x${icon.height}`
+                }));
+                manifestJson.icons = manifestIcons;
+
+                // orientation
+                // <preference name="Orientation" value="landscape" />
+                const oriPref = this.config.getGlobalPreference('Orientation');
+                if (oriPref) {
+                    // if it's a supported value, use it
+                    if (['landscape', 'portrait'].indexOf(oriPref) > -1) {
+                        manifestJson.orientation = oriPref;
+                    } else { // anything else maps to 'any'
+                        manifestJson.orientation = 'any';
+                    }
                 }
-            }
 
-            // get start_url
-            const contentNode = this.config.doc.find('content') || { attrib: { src: 'index.html' } }; // sensible default
-            manifestJson.start_url = contentNode.attrib.src;
-
-            // now we get some values from start_url page ...
-            const startUrlPath = path.join(cordovaProject.locations.www, manifestJson.start_url);
-            if (fs.existsSync(startUrlPath)) {
-                const contents = fs.readFileSync(startUrlPath, 'utf-8');
-                // matches <meta name="theme-color" content="#FF0044">
-                const themeColorRegex = /<meta(?=[^>]*name="theme-color")\s[^>]*content="([^>]*)"/i;
-                const result = themeColorRegex.exec(contents);
-                let themeColor;
-                if (result && result.length >= 2) {
-                    themeColor = result[1];
-                } else { // see if there is a preference in config.xml
-                    // <preference name="StatusBarBackgroundColor" value="#000000" />
-                    themeColor = this.config.getGlobalPreference('StatusBarBackgroundColor');
-                }
-                if (themeColor) {
-                    manifestJson.theme_color = themeColor;
+                // get start_url
+                const contentNode = this.config.doc.find('content') || { attrib: { src: 'index.html' } }; // sensible default
+                manifestJson.start_url = contentNode.attrib.src;
+
+                // now we get some values from start_url page ...
+                const startUrlPath = path.join(cordovaProject.locations.www, manifestJson.start_url);
+                if (fs.existsSync(startUrlPath)) {
+                    const contents = fs.readFileSync(startUrlPath, 'utf-8');
+                    // matches <meta name="theme-color" content="#FF0044">
+                    const themeColorRegex = /<meta(?=[^>]*name="theme-color")\s[^>]*content="([^>]*)"/i;
+                    const result = themeColorRegex.exec(contents);
+                    let themeColor;
+                    if (result && result.length >= 2) {
+                        themeColor = result[1];
+                    } else { // see if there is a preference in config.xml
+                        // <preference name="StatusBarBackgroundColor" value="#000000" />
+                        themeColor = this.config.getGlobalPreference('StatusBarBackgroundColor');
+                    }
+                    if (themeColor) {
+                        manifestJson.theme_color = themeColor;
+                    }
                 }
             }
+            fs.writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 2), 'utf8');
         }
-        fs.writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 2), 'utf8');
-    }
 
-    // Copy munged config.xml to platform www dir
-    fs.cpSync(
-        this.locations.configXml,
-        path.join(this.locations.www, 'config.xml'),
-        { force: true, recursive: true }
-    );
-};
-
-// Replace the www dir with contents of platform_www and app www.
-Api.prototype._updateWww = function (cordovaProject) {
-    // add cordova www and platform_www to sourceDirs
-    const sourceDirs = [
-        path.relative(cordovaProject.root, cordovaProject.locations.www),
-        path.relative(cordovaProject.root, this.locations.platformWww)
-    ];
-
-    // If project contains 'merges' for our platform, use them as another overrides
-    const merges_path = path.join(cordovaProject.root, 'merges', 'browser');
-    if (fs.existsSync(merges_path)) {
-        selfEvents.emit('verbose', 'Found "merges/browser" folder. Copying its contents into the browser project.');
-        // add merges/browser to sourceDirs
-        sourceDirs.push(path.join('merges', 'browser'));
+        // Copy munged config.xml to platform www dir
+        fs.cpSync(
+            this.locations.configXml,
+            path.join(this.locations.www, 'config.xml'),
+            { force: true, recursive: true }
+        );
     }
 
-    // targetDir points to browser/www
-    const targetDir = path.relative(cordovaProject.root, this.locations.www);
-    selfEvents.emit('verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
-    FileUpdater.mergeAndUpdateDir(sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
-};
-
-Api.prototype.addPlugin = function (pluginInfo, installOptions) {
-    // console.log(new Error().stack);
-    if (!pluginInfo) {
-        return Promise.reject(new Error('The parameter is incorrect. The first parameter ' +
-            'should be valid PluginInfo instance'));
+    // Replace the www dir with contents of platform_www and app www.
+    #updateWww (cordovaProject) {
+        // add cordova www and platform_www to sourceDirs
+        const sourceDirs = [
+            path.relative(cordovaProject.root, cordovaProject.locations.www),
+            path.relative(cordovaProject.root, this.locations.platformWww)
+        ];
+
+        // If project contains 'merges' for our platform, use them as another overrides
+        const merges_path = path.join(cordovaProject.root, 'merges', 'browser');
+        if (fs.existsSync(merges_path)) {
+            events.emit('verbose', 'Found "merges/browser" folder. Copying its contents into the browser project.');
+            // add merges/browser to sourceDirs
+            sourceDirs.push(path.join('merges', 'browser'));
+        }
+
+        // targetDir points to browser/www
+        const targetDir = path.relative(cordovaProject.root, this.locations.www);
+        events.emit('verbose', `Merging and updating files from [${sourceDirs.join(', ')}] to ${targetDir}`);
+        FileUpdater.mergeAndUpdateDir(sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
     }
 
-    installOptions = installOptions || {};
-    installOptions.variables = installOptions.variables || {};
-    // CB-10108 platformVersion option is required for proper plugin installation
-    installOptions.platformVersion = installOptions.platformVersion ||
-        this.getPlatformInfo().version;
-
-    const self = this;
-    const actions = new ActionStack();
-    const projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
-
-    // gather all files needs to be handled during install
-    pluginInfo.getFilesAndFrameworks(this.platform)
-        .concat(pluginInfo.getAssets(this.platform))
-        .concat(pluginInfo.getJsModules(this.platform))
-        .forEach(function (item) {
-            actions.push(actions.createAction(
-                self._getInstaller(item.itemType),
-                [item, pluginInfo.dir, pluginInfo.id, installOptions, projectFile],
-                self._getUninstaller(item.itemType),
-                [item, pluginInfo.dir, pluginInfo.id, installOptions, projectFile]));
-        });
-
-    // run through the action stack
-    return actions.process(this.platform, this.root)
-        .then(function () {
-            if (projectFile) {
-                projectFile.write();
-            }
+    async addPlugin (pluginInfo, installOptions) {
+        // console.log(new Error().stack);
+        if (!pluginInfo) {
+            return Promise.reject(
+                new Error('The parameter is incorrect. The first parameter should be valid PluginInfo instance')
+            );
+        }
 
-            // Add PACKAGE_NAME variable into vars
-            if (!installOptions.variables.PACKAGE_NAME) {
-                installOptions.variables.PACKAGE_NAME = self._handler.package_name(self.root);
-            }
+        installOptions = installOptions || {};
+        installOptions.variables = installOptions.variables || {};
+        // CB-10108 platformVersion option is required for proper plugin installation
+        installOptions.platformVersion = installOptions.platformVersion ||
+            this.getPlatformInfo().version;
+
+        const actions = new ActionStack();
+        const projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
+
+        // gather all files needs to be handled during install
+        pluginInfo.getFilesAndFrameworks(this.platform)
+            .concat(pluginInfo.getAssets(this.platform))
+            .concat(pluginInfo.getJsModules(this.platform))
+            .forEach(item => {
+                actions.push(actions.createAction(
+                    this._getInstaller(item.itemType, item, pluginInfo.dir, pluginInfo.id, installOptions, projectFile),
+                    this._getUninstaller(item.itemType, item, pluginInfo.dir, pluginInfo.id, installOptions, projectFile)
+                ));
+            });
 
-            self._munger
-                // Ignore passed `is_top_level` option since platform itself doesn't know
-                // anything about managing dependencies - it's responsibility of caller.
-                .add_plugin_changes(pluginInfo, installOptions.variables, /* is_top_level= */true, /* should_increment= */true)
-                .save_all();
-
-            const targetDir = installOptions.usePlatformWww
-                ? self.getPlatformInfo().locations.platformWww
-                : self.getPlatformInfo().locations.www;
-
-            self._addModulesInfo(pluginInfo, targetDir);
-        });
-};
-
-Api.prototype.removePlugin = function (plugin, uninstallOptions) {
-    // console.log("NotImplemented :: browser-platform:Api:removePlugin ",plugin, uninstallOptions);
-
-    uninstallOptions = uninstallOptions || {};
-    // CB-10108 platformVersion option is required for proper plugin installation
-    uninstallOptions.platformVersion = uninstallOptions.platformVersion ||
-        this.getPlatformInfo().version;
-
-    const self = this;
-    const actions = new ActionStack();
-    const projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
-
-    // queue up plugin files
-    plugin.getFilesAndFrameworks(this.platform)
-        .concat(plugin.getAssets(this.platform))
-        .concat(plugin.getJsModules(this.platform))
-        .forEach(function (item) {
-            actions.push(actions.createAction(
-                self._getUninstaller(item.itemType), [item, plugin.dir, plugin.id, uninstallOptions, projectFile],
-                self._getInstaller(item.itemType), [item, plugin.dir, plugin.id, uninstallOptions, projectFile]));
-        });
-
-    // run through the action stack
-    return actions.process(this.platform, this.root)
-        .then(function () {
-            if (projectFile) {
-                projectFile.write();
-            }
+        // run through the action stack
+        return actions.process(this.platform, this.root)
+            .then(() => {
+                if (projectFile) {
+                    projectFile.write();
+                }
 
-            self._munger
-                // Ignore passed `is_top_level` option since platform itself doesn't know
-                // anything about managing dependencies - it's responsibility of caller.
-                .remove_plugin_changes(plugin, /* is_top_level= */true)
-                .save_all();
-
-            const targetDir = uninstallOptions.usePlatformWww
-                ? self.getPlatformInfo().locations.platformWww
-                : self.getPlatformInfo().locations.www;
-
-            self._removeModulesInfo(plugin, targetDir);
-            // Remove stale plugin directory
-            // TODO: this should be done by plugin files uninstaller
-            fs.rmSync(
-                path.resolve(self.root, 'Plugins', plugin.id),
-                { force: true, recursive: true }
-            );
-        });
-};
+                // Add PACKAGE_NAME variable into vars
+                if (!installOptions.variables.PACKAGE_NAME) {
+                    installOptions.variables.PACKAGE_NAME = this._handler.package_name(this.root);
+                }
+
+                this._munger
+                    // Ignore passed `is_top_level` option since platform itself doesn't know
+                    // anything about managing dependencies - it's responsibility of caller.
+                    .add_plugin_changes(pluginInfo, installOptions.variables, /* is_top_level= */true, /* should_increment= */true)
+                    .save_all();
 
-Api.prototype._getInstaller = function (type) {
-    const self = this;
-    return function (item, plugin_dir, plugin_id, options, project) {
-        const installer = self._handler[type];
+                const targetDir = installOptions.usePlatformWww
+                    ? this.getPlatformInfo().locations.platformWww
+                    : this.getPlatformInfo().locations.www;
+
+                this.#addModulesInfo(pluginInfo, targetDir);
+            });
+    }
+
+    async removePlugin (plugin, uninstallOptions) {
+        // console.log("NotImplemented :: browser-platform:Api:removePlugin ",plugin, uninstallOptions);
+
+        uninstallOptions = uninstallOptions || {};
+        // CB-10108 platformVersion option is required for proper plugin installation
+        uninstallOptions.platformVersion = uninstallOptions.platformVersion ||
+            this.getPlatformInfo().version;
+
+        const actions = new ActionStack();
+        const projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
+
+        // queue up plugin files
+        plugin.getFilesAndFrameworks(this.platform)
+            .concat(plugin.getAssets(this.platform))
+            .concat(plugin.getJsModules(this.platform))
+            .forEach(item => {
+                actions.push(actions.createAction(
+                    this._getUninstaller(item.itemType, item, plugin.dir, plugin.id, uninstallOptions, projectFile),
+                    this._getInstaller(item.itemType, item, plugin.dir, plugin.id, uninstallOptions, projectFile)
+                ));
+            });
+
+        // run through the action stack
+        return actions.process(this.platform, this.root)
+            .then(() => {
+                if (projectFile) {
+                    projectFile.write();
+                }
+
+                this._munger
+                    // Ignore passed `is_top_level` option since platform itself doesn't know
+                    // anything about managing dependencies - it's responsibility of caller.
+                    .remove_plugin_changes(plugin, /* is_top_level= */true)
+                    .save_all();
+
+                const targetDir = uninstallOptions.usePlatformWww
+                    ? this.getPlatformInfo().locations.platformWww
+                    : this.getPlatformInfo().locations.www;
+
+                this.#removeModulesInfo(plugin, targetDir);
+                // Remove stale plugin directory
+                // TODO: this should be done by plugin files uninstaller
+                fs.rmSync(
+                    path.resolve(this.root, 'Plugins', plugin.id),
+                    { force: true, recursive: true }
+                );
+            });
+    }
+
+    _getInstaller (type, item, plugin_dir, plugin_id, options, project) {
+        const installer = this._handler[type];
 
         if (!installer) {
-            console.log('unrecognized type ' + type);
+            console.log(`unrecognized type ${type}`);
         } else {
             const wwwDest = options.usePlatformWww
-                ? self.getPlatformInfo().locations.platformWww
-                : self._handler.www_dir(self.root);
+                ? this.getPlatformInfo().locations.platformWww
+                : this._handler.www_dir(this.root);
 
             if (type === 'asset') {
                 installer.install(item, plugin_dir, wwwDest);
             } else if (type === 'js-module') {
                 installer.install(item, plugin_dir, plugin_id, wwwDest);
             } else {
-                installer.install(item, plugin_dir, self.root, plugin_id, options, project);
+                installer.install(item, plugin_dir, this.root, plugin_id, options, project);
             }
         }
-    };
-};
+    }
 
-Api.prototype._getUninstaller = function (type) {
-    const self = this;
-    return function (item, plugin_dir, plugin_id, options, project) {
-        const installer = self._handler[type];
+    _getUninstaller (type, item, plugin_dir, plugin_id, options, project) {
+        const installer = this._handler[type];
 
         if (!installer) {
-            console.log('browser plugin uninstall: unrecognized type, skipping : ' + type);
+            console.log(`browser plugin uninstall: unrecognized type, skipping : ${type}`);
         } else {
             const wwwDest = options.usePlatformWww
-                ? self.getPlatformInfo().locations.platformWww
-                : self._handler.www_dir(self.root);
+                ? this.getPlatformInfo().locations.platformWww
+                : this._handler.www_dir(this.root);
 
-            if (['asset', 'js-module'].indexOf(type) > -1) {
+            if (['asset', 'js-module'].includes(type)) {
                 return installer.uninstall(item, wwwDest, plugin_id);
             } else {
-                return installer.uninstall(item, self.root, plugin_id, options, project);
+                return installer.uninstall(item, this.root, plugin_id, options, project);
             }
         }
-    };
-};
+    }
 
-/**
- * Removes the specified modules from list of installed modules and updates
- *   platform_json and cordova_plugins.js on disk.
- *
- * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
- *   needs to be added.
- * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
- *   should be written to.
- */
-Api.prototype._addModulesInfo = function (plugin, targetDir) {
-    const installedModules = this._platformJson.root.modules || [];
-
-    const installedPaths = installedModules.map(function (installedModule) {
-        return installedModule.file;
-    });
-
-    const modulesToInstall = plugin.getJsModules(this.platform)
-        .filter(function (moduleToInstall) {
-            return installedPaths.indexOf(moduleToInstall.file) === -1;
-        }).map(function (moduleToInstall) {
-            const moduleName = plugin.id + '.' + (moduleToInstall.name || moduleToInstall.src.match(/([^/]+)\.js/)[1]);
-            const obj = {
-                file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
-                id: moduleName,
-                pluginId: plugin.id
-            };
-            if (moduleToInstall.clobbers.length > 0) {
-                obj.clobbers = moduleToInstall.clobbers.map(function (o) { return o.target; });
-            }
-            if (moduleToInstall.merges.length > 0) {
-                obj.merges = moduleToInstall.merges.map(function (o) { return o.target; });
-            }
-            if (moduleToInstall.runs) {
-                obj.runs = true;
-            }
+    /**
+     * Removes the specified modules from list of installed modules and updates
+     *   platform_json and cordova_plugins.js on disk.
+     *
+     * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
+     *   needs to be added.
+     * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
+     *   should be written to.
+     */
+    #addModulesInfo (plugin, targetDir) {
+        const installedModules = this._platformJson.root.modules || [];
+        const installedPaths = installedModules.map(installedModule => installedModule.file);
+
+        const modulesToInstall = plugin.getJsModules(this.platform)
+            .filter(moduleToInstall => !installedPaths.includes(moduleToInstall.file))
+            .map(moduleToInstall => {
+                const moduleName = plugin.id + '.' + (moduleToInstall.name || moduleToInstall.src.match(/([^/]+)\.js/)[1]);
+                const obj = {
+                    file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
+                    id: moduleName,
+                    pluginId: plugin.id
+                };
+                if (moduleToInstall.clobbers.length > 0) {
+                    obj.clobbers = moduleToInstall.clobbers.map(o => o.target);
+                }
+                if (moduleToInstall.merges.length > 0) {
+                    obj.merges = moduleToInstall.merges.map(o => o.target);
+                }
+                if (moduleToInstall.runs) {
+                    obj.runs = true;
+                }
+
+                return obj;
+            });
 
-            return obj;
-        });
+        this._platformJson.root.modules = installedModules.concat(modulesToInstall);
+        if (!this._platformJson.root.plugin_metadata) {
+            this._platformJson.root.plugin_metadata = {};
+        }
+        this._platformJson.root.plugin_metadata[plugin.id] = plugin.version;
 
-    this._platformJson.root.modules = installedModules.concat(modulesToInstall);
-    if (!this._platformJson.root.plugin_metadata) {
-        this._platformJson.root.plugin_metadata = {};
+        this.#writePluginModules(targetDir);
+        this._platformJson.save();
     }
-    this._platformJson.root.plugin_metadata[plugin.id] = plugin.version;
 
-    this._writePluginModules(targetDir);
-    this._platformJson.save();
-};
-/**
- * Fetches all installed modules, generates cordova_plugins contents and writes
- *   it to file.
- *
- * @param   {String}  targetDir  Directory, where write cordova_plugins.js to.
- *   Ususally it is either <platform>/www or <platform>/platform_www
- *   directories.
- */
-Api.prototype._writePluginModules = function (targetDir) {
-    // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
-    let final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
-    final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, '    ') + ';\n';
-    final_contents += 'module.exports.metadata = \n';
-    final_contents += '// TOP OF METADATA\n';
-    final_contents += JSON.stringify(this._platformJson.root.plugin_metadata || {}, null, '    ') + '\n';
-    final_contents += '// BOTTOM OF METADATA\n';
-    final_contents += '});'; // Close cordova.define.
-
-    fs.mkdirSync(targetDir, { recursive: true });
-    fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
-};
+    /**
+     * Fetches all installed modules, generates cordova_plugins contents and writes
+     *   it to file.
+     *
+     * @param   {String}  targetDir  Directory, where write cordova_plugins.js to.
+     *   Ususally it is either <platform>/www or <platform>/platform_www
+     *   directories.
+     */
+    #writePluginModules (targetDir) {
+        // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
+        let final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
+        final_contents += `module.exports = ${JSON.stringify(this._platformJson.root.modules, null, '    ')};\n`;
+        final_contents += 'module.exports.metadata = \n';
+        final_contents += '// TOP OF METADATA\n';
+        final_contents += JSON.stringify(this._platformJson.root.plugin_metadata || {}, null, '    ') + '\n';
+        final_contents += '// BOTTOM OF METADATA\n';
+        final_contents += '});'; // Close cordova.define.
+
+        fs.mkdirSync(targetDir, { recursive: true });
+        fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
+    }
 
-/**
- * Removes the specified modules from list of installed modules and updates
- *   platform_json and cordova_plugins.js on disk.
- *
- * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
- *   needs to be removed.
- * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
- *   should be written to.
- */
-Api.prototype._removeModulesInfo = function (plugin, targetDir) {
-    const installedModules = this._platformJson.root.modules || [];
-    const modulesToRemove = plugin.getJsModules(this.platform)
-        .map(function (jsModule) {
-            return ['plugins', plugin.id, jsModule.src].join('/');
-        });
-
-    const updatedModules = installedModules
-        .filter(function (installedModule) {
-            return (modulesToRemove.indexOf(installedModule.file) === -1);
-        });
-
-    this._platformJson.root.modules = updatedModules;
-    if (this._platformJson.root.plugin_metadata) {
-        delete this._platformJson.root.plugin_metadata[plugin.id];
+    /**
+     * Removes the specified modules from list of installed modules and updates
+     *   platform_json and cordova_plugins.js on disk.
+     *
+     * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
+     *   needs to be removed.
+     * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
+     *   should be written to.
+     */
+    #removeModulesInfo (plugin, targetDir) {
+        const installedModules = this._platformJson.root.modules || [];
+        const modulesToRemove = plugin.getJsModules(this.platform)
+            .map(jsModule => ['plugins', plugin.id, jsModule.src].join('/'));
+
+        const updatedModules = installedModules.filter(
+            installedModule => !modulesToRemove.includes(installedModule.file)
+        );
+
+        this._platformJson.root.modules = updatedModules;
+        if (this._platformJson.root.plugin_metadata) {
+            delete this._platformJson.root.plugin_metadata[plugin.id];
+        }
+
+        this.#writePluginModules(targetDir);
+        this._platformJson.save();
     }
 
-    this._writePluginModules(targetDir);
-    this._platformJson.save();
-};
-
-Api.prototype.build = function (buildOptions) {
-    const self = this;
-    return require('./check_reqs').run()
-        .then(function () {
-            return require('./build').run.call(self, buildOptions);
-        });
-};
-
-Api.prototype.run = function (runOptions) {
-    return require('./run').run(runOptions);
-};
-
-Api.prototype.clean = function (cleanOptions) {
-    return require('./clean').run(cleanOptions);
-};
-
-Api.prototype.requirements = function () {
-    return require('./check_reqs').run();
-};
+    async build (buildOptions) {
+        return require('./check_reqs').run()
+            .then(() => require('./build').run(buildOptions));
+    }
+
+    async run (runOptions) {
+        return require('./run').run(runOptions);
+    }
+
+    async clean (cleanOptions) {
+        return require('./clean').run(cleanOptions);
+    }
+
+    async requirements () {
+        return require('./check_reqs').run();
+    }
+
+    static version () {
+        return VERSION;
+    }
+}
 
 module.exports = Api;
diff --git a/lib/browser_handler.js b/lib/browser_handler.js
index 94da890..fb786bb 100644
--- a/lib/browser_handler.js
+++ b/lib/browser_handler.js
@@ -19,7 +19,8 @@
 
 const path = require('node:path');
 const fs = require('node:fs');
-const events = require('cordova-common').events;
+
+const { events } = require('cordova-common');
 
 module.exports = {
     www_dir: function (project_dir) {
@@ -53,9 +54,9 @@ module.exports = {
             // Read in the file, prepend the cordova.define, and write it back out.
             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) { ' + scriptContent + '\n});\n';
+            scriptContent = `cordova.define("${moduleName}", function(require, exports, module) { ${scriptContent}\n});\n`;
 
             const moduleDestination = path.resolve(www_dir, 'plugins', plugin_id, jsModule.src);
             fs.mkdirSync(path.dirname(moduleDestination), { recursive: true });
@@ -64,7 +65,7 @@ module.exports = {
         uninstall: function (jsModule, www_dir, plugin_id) {
             const pluginRelativePath = path.join('plugins', plugin_id, jsModule.src);
             // common.removeFileAndParents(www_dir, pluginRelativePath);
-            console.log('js-module uninstall called : ' + pluginRelativePath);
+            console.log(`js-module uninstall called : ${pluginRelativePath}`);
         }
     },
     'source-file': {
diff --git a/lib/browser_parser.js b/lib/browser_parser.js
index 50a1822..4f9fd01 100644
--- a/lib/browser_parser.js
+++ b/lib/browser_parser.js
@@ -19,9 +19,12 @@
 
 const fs = require('node:fs');
 const path = require('node:path');
-const CordovaError = require('cordova-common').CordovaError;
-const events = require('cordova-common').events;
-const FileUpdater = require('cordova-common').FileUpdater;
+
+const {
+    CordovaError,
+    FileUpdater,
+    events
+} = require('cordova-common');
 
 function dirExists (dir) {
     return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
@@ -29,7 +32,7 @@ function dirExists (dir) {
 
 function browser_parser (project) {
     if (!dirExists(project) || !dirExists(path.join(project, 'cordova'))) {
-        throw new CordovaError('The provided path "' + project + '" is not a valid browser project.');
+        throw new CordovaError(`The provided path "${project}" is not a valid browser project.`);
     }
     this.path = project;
 }
@@ -44,7 +47,7 @@ browser_parser.prototype.www_dir = function () {
  * Logs all file operations via the verbose event stream, indented.
  */
 function logFileOp (message) {
-    events.emit('verbose', '  ' + message);
+    events.emit('verbose', `  ${message}`);
 }
 
 // Replace the www dir with contents of platform_www and app www.
@@ -67,7 +70,7 @@ browser_parser.prototype.update_www = function (cordovaProject, opts) {
 
     // targetDir points to browser/www
     const targetDir = path.relative(cordovaProject.root, my_www);
-    events.emit('verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+    events.emit('verbose', `Merging and updating files from [${sourceDirs.join(', ')}] to ${targetDir}`);
     FileUpdater.mergeAndUpdateDir(sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
 };
 
diff --git a/lib/build.js b/lib/build.js
index b3ce5e1..32c1dbc 100644
--- a/lib/build.js
+++ b/lib/build.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
@@ -20,6 +18,7 @@
 */
 
 const path = require('node:path');
+
 const check_reqs = require('./check_reqs');
 
 /**
@@ -33,5 +32,5 @@ module.exports.run = function () {
 module.exports.help = function () {
     console.log('Usage: cordova build browser');
     const wwwPath = path.resolve(path.join(__dirname, '../../www'));
-    console.log("Build will create the packaged app in '" + wwwPath + "'.");
+    console.log(`Build will create the packaged app in '${wwwPath}'.`);
 };
diff --git a/lib/check_reqs.js b/lib/check_reqs.js
index fc13f04..32feeea 100644
--- a/lib/check_reqs.js
+++ b/lib/check_reqs.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
diff --git a/lib/clean.js b/lib/clean.js
index c8f18ac..7ae5a4b 100644
--- a/lib/clean.js
+++ b/lib/clean.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
@@ -21,7 +19,9 @@
 
 const fs = require('node:fs');
 const path = require('node:path');
+
 const check_reqs = require('./check_reqs');
+
 const platformBuildDir = path.join('platforms', 'browser', 'www');
 
 const run = function () {
@@ -37,7 +37,7 @@ const run = function () {
             fs.rmSync(platformBuildDir, { recursive: true });
         }
     } catch (err) {
-        console.log('could not remove ' + platformBuildDir + ' : ' + err.message);
+        console.log(`could not remove ${platformBuildDir} : ${err.message}`);
     }
 };
 
diff --git a/lib/create.js b/lib/create.js
index f8ef75e..1b729b7 100644
--- a/lib/create.js
+++ b/lib/create.js
@@ -19,10 +19,15 @@
 
 const fs = require('node:fs');
 const path = require('node:path');
-const ROOT = path.join(__dirname, '..');
-const { CordovaError, events } = require('cordova-common');
+const {
+    CordovaError,
+    events
+} = require('cordova-common');
+
 const check_reqs = require('./check_reqs');
 
+const ROOT = path.join(__dirname, '..');
+
 // exported method to create a project, returns a promise that resolves with null
 module.exports.createProject = function (project_path, package_name, project_name, opts = {}, root_config) {
     project_path = path.relative(process.cwd(), project_path);
diff --git a/lib/run.js b/lib/run.js
index 748523d..d3c8da0 100644
--- a/lib/run.js
+++ b/lib/run.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
@@ -22,6 +20,7 @@
 const fs = require('node:fs');
 const path = require('node:path');
 const url = require('node:url');
+
 const cordovaServe = require('cordova-serve');
 
 module.exports.run = function (args) {
@@ -41,7 +40,7 @@ module.exports.run = function (args) {
             const manifest = require(manifestFilePath);
             startPage = manifest.start_url;
         } catch (err) {
-            console.log('failed to require manifest ... ' + err);
+            console.log(`failed to require manifest ... ${err}`);
         }
     }
 
@@ -55,8 +54,8 @@ module.exports.run = function (args) {
 
             const projectUrl = (new url.URL(`http://localhost:${server.port}/${startPage}`)).href;
 
-            console.log('startPage = ' + startPage);
-            console.log('Static file server running @ ' + projectUrl + '\nCTRL + C to shut down');
+            console.log(`startPage = ${startPage}`);
+            console.log(`Static file server running @ ${projectUrl}\nCTRL + C to shut down`);
             return server.launchBrowser({ target: args.target, url: projectUrl });
         })
         .catch(function (error) {
diff --git a/lib/update.js b/lib/update.js
index db712bf..7e62184 100644
--- a/lib/update.js
+++ b/lib/update.js
@@ -17,10 +17,12 @@
     under the License.
 */
 
-const create = require('./create');
 const fs = require('node:fs');
+
 const { CordovaError } = require('cordova-common');
 
+const create = require('./create');
+
 module.exports.help = function () {
     console.log('WARNING : Make sure to back up your project before updating!');
     console.log('Usage: update PathToProject ');
diff --git a/spec/browser_handler.spec.js b/spec/browser_handler.spec.js
index f63c115..e3cc39f 100644
--- a/spec/browser_handler.spec.js
+++ b/spec/browser_handler.spec.js
@@ -17,10 +17,11 @@
     under the License.
 */
 
-const browser_handler = require('../lib/browser_handler');
 const fs = require('node:fs');
 const path = require('node:path');
 
+const browser_handler = require('../lib/browser_handler');
+
 describe('Asset install tests', function () {
     let fsstatMock;
     const asset = {
diff --git a/spec/projectApi.spec.js b/spec/projectApi.spec.js
index 3342a71..bc18cb4 100644
--- a/spec/projectApi.spec.js
+++ b/spec/projectApi.spec.js
@@ -21,13 +21,12 @@ const path = require('node:path');
 const { Module } = require('node:module');
 const EventEmitter = require('node:events');
 const tmp = require('tmp');
+const { ConfigParser } = require('cordova-common');
+const Api = require('../lib/Api');
 
 process.env.NODE_PATH = path.resolve(__dirname, '../../');
 Module._initPaths();
 
-const { ConfigParser } = require('cordova-common');
-const Api = require('../lib/Api');
-
 tmp.setGracefulCleanup();
 
 function makeTempDir () {
diff --git a/templates/cordova/version b/templates/cordova/version
index 7b0de4c..43e2e9f 100755
--- a/templates/cordova/version
+++ b/templates/cordova/version
@@ -19,7 +19,6 @@
     under the License.
 */
 
-// Coho updates this line:
-const VERSION = '8.0.0-dev';
+const Api = require('./Api');
 
-console.log(VERSION);
+console.log(Api.version());


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org