Full Code of apache/cordova-browser for AI

master 6e93ff817b13 cached
43 files
116.2 KB
28.0k tokens
15 symbols
1 requests
Download .txt
Repository: apache/cordova-browser
Branch: master
Commit: 6e93ff817b13
Files: 43
Total size: 116.2 KB

Directory structure:
gitextract_zo_vyim0/

├── .asf.yaml
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.md
│   │   ├── FEATURE_REQUEST.md
│   │   └── SUPPORT_QUESTION.md
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       └── release-audit.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── .ratignore
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── RELEASENOTES.md
├── bin/
│   ├── lib/
│   │   ├── check_reqs.js
│   │   ├── create.js
│   │   └── update.js
│   └── template/
│       ├── cordova/
│       │   ├── Api.js
│       │   ├── browser_handler.js
│       │   ├── browser_parser.js
│       │   ├── defaults.xml
│       │   ├── lib/
│       │   │   ├── build.js
│       │   │   ├── clean.js
│       │   │   └── run.js
│       │   └── version
│       └── www/
│           ├── css/
│           │   └── index.css
│           ├── index.html
│           ├── js/
│           │   └── index.js
│           └── manifest.json
├── cordova-js-src/
│   ├── confighelper.js
│   ├── exec.js
│   └── platform.js
├── eslint.config.js
├── licence_checker.yml
├── package.json
└── spec/
    ├── browser_handler.spec.js
    ├── create.spec.js
    ├── projectApi.spec.js
    └── support/
        └── jasmine.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .asf.yaml
================================================
# 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.

notifications:
  commits:              commits@cordova.apache.org
  issues:               issues@cordova.apache.org
  pullrequests_status:  issues@cordova.apache.org
  pullrequests_comment: issues@cordova.apache.org


================================================
FILE: .gitattributes
================================================
# 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.

* text eol=lf

# source code
*.php text
*.css text
*.sass text
*.scss text
*.less text
*.styl text
*.js text
*.coffee text
*.json text
*.htm text
*.html text
*.xml text
*.svg text
*.txt text
*.ini text
*.inc text
*.pl text
*.rb text
*.py text
*.scm text
*.sql text
*.sh text
*.bat text

# templates
*.ejs text
*.hbt text
*.jade text
*.haml text
*.hbs text
*.dot text
*.tmpl text
*.phtml text

# server config
.htaccess text

# git config
.gitattributes text
.gitignore text
.gitconfig text

# code analysis config
.jshintrc text
.jscsrc text
.jshintignore text
.csslintrc text

# misc config
*.yaml text
*.yml text
.editorconfig text

# build config
*.npmignore text
*.bowerrc text

# Heroku
Procfile text
.slugignore text

# Documentation
*.md text
LICENSE text
AUTHORS text


#
## These files are binary and should be left untouched
#

# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary


================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.md
================================================
---
name: 🐛 Bug Report
about: If something isn't working as expected.

---

# Bug Report

## Problem

### What is expected to happen?



### What does actually happen?



## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->



### Command or Code
<!-- What command or code is needed to reproduce the problem? -->



### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->



### Version information
<!-- 
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins 
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->



## Checklist
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->

- [ ] I searched for existing GitHub issues
- [ ] I updated all Cordova tooling to most recent version
- [ ] I included all the necessary information above


================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
================================================
---
name: 🚀 Feature Request
about: A suggestion for a new functionality

---

# Feature Request

## Motivation Behind Feature
<!-- Why should this feature be implemented? What problem does it solve? -->



## Feature Description
<!-- 
Describe your feature request in detail
Please provide any code examples or screenshots of what this feature would look like
Are there any drawbacks? Will this break anything for existing users? 
-->



## Alternatives or Workarounds
<!-- 
Describe alternatives or workarounds you are currently using 
Are there ways to do this with existing functionality?
-->




================================================
FILE: .github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
================================================
---
name: 💬 Support Question
about: If you have a question, please check out our Slack or StackOverflow!

---

<!------------^ Click "Preview" for a nicer view! -->

Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_.
For usage and support questions, please check out the resources below. Thanks!

---

You can get answers to your usage and support questions about **Apache Cordova** on:

* Slack Community Chat: https://cordova.slack.com (you can sign-up at http://slack.cordova.io/)
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova`

---

If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels:

* **Ionic Framework**
  * [Ionic Community Forum](https://forum.ionicframework.com/)
  * [Ionic Worldwide Slack](https://ionicworldwide.herokuapp.com/)
* **PhoneGap**
  * [PhoneGap Developer Community](https://forums.adobe.com/community/phonegap)


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
Please have a look at the issue templates you get when you click "New issue" in the GitHub UI.
We very much prefer issues created by using one of these templates.
-->

### Issue Type
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->

- [ ] Bug Report
- [ ] Feature Request
- [ ] Support Question

## Description

## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->

### Command or Code
<!-- What command or code is needed to reproduce the problem? -->

### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->



### Version information
<!-- 
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins 
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->



## Checklist
<!-- Please check the boxes by putting an `x` in the `[ ]` like so: `[x]` -->

- [ ] I searched for already existing GitHub issues about this
- [ ] I updated all Cordova tooling to their most recent version
- [ ] I included all the necessary information above


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Please make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick reference, for complete details please see our Contributor Guidelines:

http://cordova.apache.org/contribute/contribute_guidelines.html

Thanks!
-->

### Platforms affected



### Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->



### Description
<!-- Describe your changes in detail -->



### Testing
<!-- Please describe in detail how you tested your changes. -->



### Checklist

- [ ] I've run the tests to see all new and existing tests pass
- [ ] I added automated test coverage as appropriate for this change
- [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`)
- [ ] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct [keyword to close issues using keywords](https://help.github.com/articles/closing-issues-using-keywords/))
- [ ] I've updated the documentation if necessary


================================================
FILE: .github/workflows/ci.yml
================================================
# 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.

name: Node CI

on:
  push:
    branches-ignore:
      - 'dependabot/**'
  pull_request:
    branches:
      - '*'

permissions:
  contents: read
  security-events: write

jobs:
  test:
    name: NodeJS ${{ matrix.node-version }} on ${{ matrix.os }}

    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        node-version: [20.x, 22.x, 24.x]
        os: [ubuntu-latest, windows-latest, macos-15]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Environment Information
        run: |
          node --version
          npm --version

      # "bin/template/www/cordova.js" is ignored because it is a generated file.
      # It contains mixed content from the npm package "cordova-js" and "./cordova-js-src".
      # The report might not be resolvable because of the external package.
      # If the report is related to this repository, it would be detected when scanning "./cordova-js-src".
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript
          queries: security-and-quality
          config: |
            paths-ignore:
              - coverage
              - node_modules
              - bin/template/www/cordova.js

      - name: npm install and test
        run: |
          npm i
          npm t
        env:
          CI: true

      - uses: github/codeql-action/analyze@v3

      # v4.6.0
      - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238
        if: success()
        with:
          name: ${{ runner.os }} node.js ${{ matrix.node-version }}
          token: ${{ secrets.CORDOVA_CODECOV_TOKEN }}
          fail_ci_if_error: false


================================================
FILE: .github/workflows/release-audit.yml
================================================
# 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.

name: Release Auditing

on:
  push:
    branches-ignore:
      - 'dependabot/**'
  pull_request:
    branches:
      - '*'

permissions:
  contents: read

jobs:
  test:
    name: Audit Licenses
    runs-on: ubuntu-latest
    steps:
      # Checkout project
      - uses: actions/checkout@v6

      # Check license headers (v2.0.0)
      - uses: erisu/apache-rat-action@46fb01ce7d8f76bdcd7ab10e7af46e1ea95ca01c

      # Setup environment with node
      - uses: actions/setup-node@v6
        with:
          node-version: 24

      # Install node packages
      - name: npm install packages
        run: npm ci

      # Check node package licenses (v2.0.1)
      - uses: erisu/license-checker-action@99cffa11264fe545fd0baa6c13bca5a00ae608f2
        with:
          license-config: 'licence_checker.yml'
          include-asf-category-a: true


================================================
FILE: .gitignore
================================================
# 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.

# System
.DS_Store

# IDE
.vscode

# npm
npm-debug.log
node_modules/

# Testing, code coverage, and linting output
coverage/
.nyc_output/
temp

# Output of 'npm pack'
*.tgz

# Other
bin/template/www/cordova.js


================================================
FILE: .npmignore
================================================
# 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.

# Config related files
.*

# Testing, code coverage, and linting
coverage
spec
eslint.config.js
licence_checker.yml

# Logging
logs
*.log
npm-debug.log*

# Output of 'npm pack'
*.tgz

# others
cordova-js-src


================================================
FILE: .npmrc
================================================
# 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.

registry=https://registry.npmjs.org


================================================
FILE: .ratignore
================================================
# 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.

.git/
coverage/
node_modules/
VERSION


================================================
FILE: CONTRIBUTING.md
================================================
<!--
#
# 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.
#
-->

# Contributing to Apache Cordova

Anyone can contribute to Cordova. And we need your contributions.

There are multiple ways to contribute: report bugs, improve the docs, and
contribute code.
  
For instructions on this, start with the
[contribution overview](http://cordova.apache.org/contribute/).

The details are explained there, but the important items are:
 - Check for Github issues that corresponds to your contribution and link or create them if necessary.
 - Run the tests so your patch doesn't break existing functionality.

We look forward to your contributions!



================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   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.


================================================
FILE: NOTICE
================================================
Apache Cordova
Copyright 2012-2015 The Apache Software Foundation

This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).


================================================
FILE: README.md
================================================
<!--
#
# 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.
#
-->

[![Node CI](https://github.com/apache/cordova-browser/workflows/Node%20CI/badge.svg?branch=master)](https://github.com/apache/cordova-browser/actions?query=branch%3Amaster)
[![codecov.io](https://codecov.io/github/apache/cordova-browser/coverage.svg?branch=master)](https://codecov.io/github/apache/cordova-browser?branch=master)

# Cordova Browser

Target modern web browsers to build Apache Cordova based applications.

# Goals

- Browser targeted deployment
- Surfacing native platform incompatibilities from the open web platform

# PWA support

## cordova-browser now includes support for progressive web apps (PWAs)

- if your project supplies a `manifest.json` in the `www/` dir, it will be used
    - a `manifest.json` will be generated otherwise
- if your js code registers a service worker, it will also be used




================================================
FILE: RELEASENOTES.md
================================================
<!--
#
# 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.
#
-->

## Release Notes for Cordova Browser ##

### 7.0.0 (May 13, 2023)

#### Breaking Changes

* [GH-121](https://github.com/apache/cordova-browser/pull/121) Minimum NodeJS Required: 16.13.0
* [GH-115](https://github.com/apache/cordova-browser/pull/115) Update ShellJS to 0.8.5.
* [GH-78](https://github.com/apache/cordova-browser/pull/78) feat: Replace `Q` with native Promises.

#### Other Notable Changes

* [GH-117](https://github.com/apache/cordova-browser/pull/117) Added `.npmrc` file to ensure the official NPM registry is used during development and deployments.
* [GH-107](https://github.com/apache/cordova-browser/pull/107) Enabled `package-lock.json` file.
* [GH-119](https://github.com/apache/cordova-browser/pull/119) Added NodeJS 20 to our test matrix.
* [GH-118](https://github.com/apache/cordova-browser/pull/118) Updated ESLint config to match better match Apache Cordova's coding style standards.
* [GH-80](https://github.com/apache/cordova-browser/pull/80) Enabled CodeCov test coverage
* [GH-113](https://github.com/apache/cordova-browser/pull/113) Migrated to GitHub Action workflows for our testing CI.

For a full list of changes, see the [commit history](https://github.com/apache/cordova-browser/compare/rel/6.0.0...4669c4dce952c658ba7eb951ebfcae35b96a56ea)

### 6.0.0 (Feb 01, 2019)
* [GH-70](https://github.com/apache/cordova-browser/pull/70) Browser Platform Release Preparation (Cordova 9)
* [GH-68](https://github.com/apache/cordova-browser/pull/68) Copy node_modules if the directory exists
* [GH-63](https://github.com/apache/cordova-browser/pull/63) Dependency bump cordova-common@^3.0.0
* [CB-13740](https://issues.apache.org/jira/browse/CB-13740) Return expected promise resolving with array
* [GH-59](https://github.com/apache/cordova-browser/pull/59) Remove Bundled Dependencies
* [CB-14073](https://issues.apache.org/jira/browse/CB-14073) **Browser**: Drop Node 4, Added Node 10
* [CB-14252](https://issues.apache.org/jira/browse/CB-14252) Allow to send --silent arg to run command to disable output (#57)
* [CB-13999](https://issues.apache.org/jira/browse/CB-13999) (browser) - Reading `config.xml` respects base href (#52)
* [GH-50](https://github.com/apache/cordova-browser/pull/50) corrected path for `config.xml`
* [CB-13689](https://issues.apache.org/jira/browse/CB-13689) Updated RELEASENOTES and Version for release 5.0.3

### 5.0.2 (Dec 18, 2017)
* [CB-13689](https://issues.apache.org/jira/browse/CB-13689): Updated checked-in node_modules
* [CB-13562](https://issues.apache.org/jira/browse/CB-13562): fixed asset tag when adding push plugin to **Browser**

### 5.0.1 (Oct 16, 2017)
* [CB-13444](https://issues.apache.org/jira/browse/CB-13444) Updated checked-in `node_modules`
* [CB-13435](https://issues.apache.org/jira/browse/CB-13435) fix merges directory support for **Browser**
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) ignoring `cordova.js` for `eslint`

### 5.0.0 (Aug 24, 2017)
* [CB-13214](https://issues.apache.org/jira/browse/CB-13214) Updated `cordova-serve` dependnecy to 2.0.0. `cordova serve` command now opens system default browser instead of a new instance of `chrome`. A specific target can still be passed in. 
* [CB-13214](https://issues.apache.org/jira/browse/CB-13214) Updated checked-in `node_modules`
* [CB-13188](https://issues.apache.org/jira/browse/CB-13188) fixed issues with run and build scripts. 
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895): set up `eslint` and remove `jshint`
* [CB-11181](https://issues.apache.org/jira/browse/CB-11181) add default favicon
* [CB-11710](https://issues.apache.org/jira/browse/CB-11710) Add missing 'clean.bat' file
* remove old `xhr-activex` **Windows** code, update to use `pagevisibility` instead of `webkitpagevisibility`
* [CB-12804](https://issues.apache.org/jira/browse/CB-12804): `manifest.json` added to **Browser** during create. Adding basic PWA support
* [CB-12762](https://issues.apache.org/jira/browse/CB-12762) Point repo items to github mirrors
* Clean up PRs. Closes #2. Closes #25
* [CB-12617](https://issues.apache.org/jira/browse/CB-12617) : removed node 0.x support and added engineStrict. This closes #27
* [CB-12847](https://issues.apache.org/jira/browse/CB-12847) added `bugs` entry to `package.json`.
* [CB-12527](https://issues.apache.org/jira/browse/CB-12527) large refactor. Implemented `PlatformApi`
* [CB-12114](https://issues.apache.org/jira/browse/CB-12114) added travis and appveyor files
* Add github pull request template

### 4.0.0 (Aug 13, 2015)
* updated version in version script
* added `.ratignore` and added missing AL header to readme
* removed other platform screens from template
* updated to 4.0.0-dev
* [CB-8965](https://issues.apache.org/jira/browse/CB-8965) Copy `cordova-js-src` directory to platform folder during create
* Adds LICENSE and NOTICE files.
* [CB-9350](https://issues.apache.org/jira/browse/CB-9350) 'cordova run browser' throws an exception.
* Update 'cordova run browser' command to use cordova-serve module.
* [CB-8417](https://issues.apache.org/jira/browse/CB-8417) update platform specific js from cordovajs
* [CB-8760](https://issues.apache.org/jira/browse/CB-8760) platform list shows wrong version for browser platform.
* [CB-8182](https://issues.apache.org/jira/browse/CB-8182) port `cordova serve` to `cordova run browser`
* [CB-8182](https://issues.apache.org/jira/browse/CB-8182) add dependency on `mime` library
* [CB-8196](https://issues.apache.org/jira/browse/CB-8196) Browser platform `run` should default source file to index.html even if it's missing in the config.xml
* [CB-8223](https://issues.apache.org/jira/browse/CB-8223) Expose config.xml in the Browser platform
* [CB-8417](https://issues.apache.org/jira/browse/CB-8417) renamed platform_modules into cordova-js-src
* [CB-8417](https://issues.apache.org/jira/browse/CB-8417) moved platform specific js into platform
* [CB-8224](https://issues.apache.org/jira/browse/CB-8224) Add support to launch a specified browser using --target switch. Support for multiple browsers on Windows, Mac and Linux
* Add Windows specific shim wrappers for shjs - auto-generated by npm install
* [CB-8206](https://issues.apache.org/jira/browse/CB-8206) Browser platform: Add support for update
* --user-data-dir working on windows
* [CB-7978](https://issues.apache.org/jira/browse/CB-7978) Cleaning code and creating temporary dir - Using path.resolve and path.join instead of concatenating paths - Fixing error when temporary dir already exists by using shelljs instead of fs
* [CB-7978](https://issues.apache.org/jira/browse/CB-7978) Cleaning code and creating temporary dir - Cleaning code - Declaring variables only when needed - Creating chrome for Cordova temp dir prior using it by std and err
* [CB-7978](https://issues.apache.org/jira/browse/CB-7978) Fixed launching chrome in Linux

### 3.6.0 ###
* Update JS snapshot to version 3.6.0 (via coho)
* Set VERSION to 3.6.0 (via coho)
* added run.bat file
* added windows run support, still a few issues
* No longer need to kill Chrome for mac
* added create.bat for windows support
* Removed old dependency from source
* Fixed issue with npm cache when adding browser
* Fixed directory structure
* Creating browser project
* [CB-6818](https://issues.apache.org/jira/browse/CB-6818) Add license for CONTRIBUTING.md
* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md


================================================
FILE: bin/lib/check_reqs.js
================================================
#!/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.
*/

// add methods as we determine what are the requirements

module.exports.run = function () {
    // caller expects a promise resolved with an array of conditions
    return Promise.resolve([]);
};


================================================
FILE: bin/lib/create.js
================================================
#!/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.
*/

const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..', '..');
const events = require('cordova-common').events;
const check_reqs = require('./check_reqs');

// exported method to create a project, returns a promise that resolves with null
module.exports.createProject = function (project_path, package_name, project_name) {
/*
    // create the dest and the standard place for our api to live
    // platforms/platformName/cordova/Api.js
*/

    events.emit('log', 'Creating Cordova project for cordova-browser:');
    events.emit('log', '\tPath: ' + project_path);
    events.emit('log', '\tName: ' + project_name);

    // Set default values for path, package and name
    project_path = project_path || 'CordovaExample';

    // Check if project already exists
    if (fs.existsSync(project_path)) {
        events.emit('error', 'Oops, destination already exists! Delete it and try again');
    } else {
        fs.mkdirSync(project_path);
    }

    // Check that requirements are met and proper targets are installed
    if (!check_reqs.run()) {
        // TODO: use events.emit
        events.emit('error', 'Please make sure you meet the software requirements in order to build a browser cordova project');
    }

    // copy template/* to project_path directory ( recursive )
    fs.cpSync(path.join(ROOT, 'bin/template'), project_path, { recursive: true });

    // TODO: stop copying cordova-browser logic into platforms/browser/
    // recreate our node_modules structure in the new project
    const nodeModulesDir = path.join(ROOT, 'node_modules');
    if (fs.existsSync(nodeModulesDir)) {
        fs.cpSync(nodeModulesDir, path.join(project_path, 'cordova/node_modules'), { recursive: true });
    }

    // copy check_reqs file
    fs.cpSync(
        path.join(ROOT, 'bin/lib/check_reqs.js'),
        path.join(project_path, 'cordova/lib/check_reqs.js')
    );

    // create platform_www dir if it does not exist yet
    const platform_www = path.join(project_path, 'platform_www');
    fs.mkdirSync(platform_www, { recursive: true });

    // copy cordova js file to platform_www
    fs.cpSync(
        path.join(ROOT, 'bin/template/www/cordova.js'),
        path.join(platform_www, 'cordova.js')
    );

    // copy favicon file to platform_www
    fs.cpSync(
        path.join(ROOT, 'bin/template/www/favicon.ico'),
        path.join(platform_www, 'favicon.ico')
    );

    // load manifest to write name/shortname
    const manifest = require(path.join(ROOT, 'bin/template/www', 'manifest.json'));
    manifest.name = project_name;
    manifest.short_name = project_name;
    // copy manifest file to platform_www
    fs.writeFileSync(path.join(platform_www, 'manifest.json'),
        JSON.stringify(manifest, null, 2), 'utf-8');

    return Promise.resolve();
};


================================================
FILE: bin/lib/update.js
================================================
/*
    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 create = require('./create');
const fs = require('node:fs');
const { CordovaError } = require('cordova-common');

module.exports.help = function () {
    console.log('WARNING : Make sure to back up your project before updating!');
    console.log('Usage: update PathToProject ');
    console.log('    PathToProject : The path the project you would like to update.');
    console.log('examples:');
    console.log('    update C:\\Users\\anonymous\\Desktop\\MyProject');
};

module.exports.run = function (argv) {
    const projectPath = argv[2];

    // If the specified project path is not valid then reject promise.
    if (!fs.existsSync(projectPath)) {
        return Promise.reject(new CordovaError(`Browser platform does not exist here: ${projectPath}`));
    }

    console.log('Removing existing browser platform.');
    fs.rmSync(projectPath, { recursive: true, force: true });

    // Create Project returns a resolved promise.
    return create.createProject(projectPath);
};


================================================
FILE: bin/template/cordova/Api.js
================================================
/*
    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 file is found by cordova-lib when you attempt to
    'cordova platform add PATH' where path is this repo.
*/

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 PLATFORM_NAME = 'browser';

function setupEvents (externalEventEmitter) {
    if (externalEventEmitter) {
        // This will make the platform internal events visible outside
        selfEvents.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;
}

/**
 * Logs all file operations via the verbose event stream, indented.
 */
function logFileOp (message) {
    selfEvents.emit('verbose', '  ' + message);
}

function dirExists (dir) {
    return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
}

function Api (platform, platformRootDir, events) {
    this.platform = platform || PLATFORM_NAME;

    // MyApp/platforms/browser
    this.root = path.resolve(__dirname, '..');
    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: 'bin/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) {
    const creator = require('../../lib/create');
    events = setupEvents(events);

    let name = 'HelloCordova';
    let id = 'io.cordova.hellocordova';
    if (config) {
        name = config.name();
        id = config.packageName();
    }

    let result;
    try {
        // we create the project using our scripts in this platform
        result = creator.createProject(dest, id, name, options)
            .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);
    }
    return result;
};

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 });
    }

    // 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');
            const manifestIcons = icons.map(function (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 :
                {   src: 'res/ios/icon.png',
                    target: undefined,
                    density: 'mdpi',
                    platform: null,
                    width: 57,
                    height: 57
                } ******/
                /* manifest expects them to be like this :
                {   "src": "images/touch/icon-128x128.png",
                    "type": "image/png",
                    "sizes": "128x128"
                } ******/
                // ?Is it worth looking at file extentions?
                return {
                    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';
                }
            }

            // 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');
    }

    // 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'));
    }

    // 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'));
    }

    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();
            }

            // Add PACKAGE_NAME variable into vars
            if (!installOptions.variables.PACKAGE_NAME) {
                installOptions.variables.PACKAGE_NAME = self._handler.package_name(self.root);
            }

            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();
            }

            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 }
            );
        });
};

Api.prototype._getInstaller = function (type) {
    const self = this;
    return function (item, plugin_dir, plugin_id, options, project) {
        const installer = self._handler[type];

        if (!installer) {
            console.log('unrecognized type ' + type);
        } else {
            const wwwDest = options.usePlatformWww
                ? self.getPlatformInfo().locations.platformWww
                : self._handler.www_dir(self.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);
            }
        }
    };
};

Api.prototype._getUninstaller = function (type) {
    const self = this;
    return function (item, plugin_dir, plugin_id, options, project) {
        const installer = self._handler[type];

        if (!installer) {
            console.log('browser plugin uninstall: unrecognized type, skipping : ' + type);
        } else {
            const wwwDest = options.usePlatformWww
                ? self.getPlatformInfo().locations.platformWww
                : self._handler.www_dir(self.root);

            if (['asset', 'js-module'].indexOf(type) > -1) {
                return installer.uninstall(item, wwwDest, plugin_id);
            } else {
                return installer.uninstall(item, self.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;
            }

            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._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');
};

/**
 * 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];
    }

    this._writePluginModules(targetDir);
    this._platformJson.save();
};

Api.prototype.build = function (buildOptions) {
    const self = this;
    return require('./lib/check_reqs').run()
        .then(function () {
            return require('./lib/build').run.call(self, buildOptions);
        });
};

Api.prototype.run = function (runOptions) {
    return require('./lib/run').run(runOptions);
};

Api.prototype.clean = function (cleanOptions) {
    return require('./lib/clean').run(cleanOptions);
};

Api.prototype.requirements = function () {
    return require('./lib/check_reqs').run();
};

module.exports = Api;


================================================
FILE: bin/template/cordova/browser_handler.js
================================================
/*
    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 path = require('node:path');
const fs = require('node:fs');
const events = require('cordova-common').events;

module.exports = {
    www_dir: function (project_dir) {
        return path.join(project_dir, 'www');
    },
    package_name: function (project_dir) {
        // this method should the id from root config.xml => <widget id=xxx
        // return common.package_name(project_dir, this.www_dir(project_dir));
        // console.log('package_name called with ' + project_dir);
        let pkgName = 'io.cordova.hellocordova';
        const widget_id_regex = /(?:<widget\s+id=['"])(\S+)(?:['"])/;

        const configPath = path.join(project_dir, 'config.xml');
        if (fs.existsSync(configPath)) {
            const configStr = fs.readFileSync(configPath, 'utf8');
            const res = configStr.match(widget_id_regex);
            if (res && res.length > 1) {
                pkgName = res[1];
            }
        }
        return pkgName;
    },
    'js-module': {
        install: function (jsModule, plugin_dir, plugin_id, www_dir) {
            // Copy the plugin's files into the www directory.
            const moduleSource = path.resolve(plugin_dir, jsModule.src);
            // Get module name based on existing 'name' attribute or filename
            // Must use path.extname/path.basename instead of path.parse due to CB-9981
            const moduleName = plugin_id + '.' + (jsModule.name || path.basename(jsModule.src, path.extname(jsModule.src)));

            // 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 = '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 });
            fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
        },
        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);
        }
    },
    'source-file': {
        install: function (obj, plugin_dir, project_dir, plugin_id, options) {
            // var dest = path.join(obj.targetDir, path.basename(obj.src));
            // common.copyFile(plugin_dir, obj.src, project_dir, dest);
            console.log('install called');
        },
        uninstall: function (obj, project_dir, plugin_id, options) {
            // var dest = path.join(obj.targetDir, path.basename(obj.src));
            // common.removeFile(project_dir, dest);
            console.log('uninstall called');
        }
    },
    'header-file': {
        install: function (obj, plugin_dir, project_dir, plugin_id, options) {
            events.emit('verbose', 'header-fileinstall is not supported for browser');
        },
        uninstall: function (obj, project_dir, plugin_id, options) {
            events.emit('verbose', 'header-file.uninstall is not supported for browser');
        }
    },
    'resource-file': {
        install: function (obj, plugin_dir, project_dir, plugin_id, options) {
            events.emit('verbose', 'resource-file.install is not supported for browser');
        },
        uninstall: function (obj, project_dir, plugin_id, options) {
            events.emit('verbose', 'resource-file.uninstall is not supported for browser');
        }
    },
    framework: {
        install: function (obj, plugin_dir, project_dir, plugin_id, options) {
            events.emit('verbose', 'framework.install is not supported for browser');
        },
        uninstall: function (obj, project_dir, plugin_id, options) {
            events.emit('verbose', 'framework.uninstall is not supported for browser');
        }
    },
    'lib-file': {
        install: function (obj, plugin_dir, project_dir, plugin_id, options) {
            events.emit('verbose', 'lib-file.install is not supported for browser');
        },
        uninstall: function (obj, project_dir, plugin_id, options) {
            events.emit('verbose', 'lib-file.uninstall is not supported for browser');
        }
    },
    asset: {
        install: function (asset, plugin_dir, wwwDest) {
            const src = path.join(plugin_dir, asset.src);
            const dest = path.join(wwwDest, asset.target);
            const destDir = path.parse(dest).dir;
            if (destDir !== '' && !fs.existsSync(destDir)) {
                fs.mkdirSync(destDir, { recursive: true });
            }

            if (fs.statSync(src).isDirectory()) {
                fs.cpSync(src, dest, { recursive: true, force: true });
            } else {
                fs.cpSync(src, dest, { force: true });
            }
        },
        uninstall: function (asset, wwwDest, plugin_id) {
            fs.rmSync(path.join(wwwDest, asset.target), { recursive: true, force: true });
            fs.rmSync(path.join(wwwDest, 'plugins', plugin_id), { recursive: true, force: true });
        }
    }
};


================================================
FILE: bin/template/cordova/browser_parser.js
================================================
/*
    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 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;

function dirExists (dir) {
    return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
}

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.');
    }
    this.path = project;
}

module.exports = browser_parser;

browser_parser.prototype.www_dir = function () {
    return path.join(this.path, 'www');
};

/**
 * Logs all file operations via the verbose event stream, indented.
 */
function logFileOp (message) {
    events.emit('verbose', '  ' + message);
}

// Replace the www dir with contents of platform_www and app www.
browser_parser.prototype.update_www = function (cordovaProject, opts) {
    const platform_www = path.join(this.path, 'platform_www');
    const my_www = this.www_dir();
    // add cordova www and platform_www to sourceDirs
    const sourceDirs = [
        path.relative(cordovaProject.root, cordovaProject.locations.www),
        path.relative(cordovaProject.root, platform_www)
    ];

    // 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, my_www);
    events.emit('verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
    FileUpdater.mergeAndUpdateDir(sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
};

browser_parser.prototype.config_xml = function () {
    return path.join(this.path, 'config.xml');
};

browser_parser.prototype.update_project = async function (cfg) {
    // Copy munged config.xml to platform www dir
    fs.cpSync(this.config_xml(), this.www_dir(), { recursive: true, force: true });
};


================================================
FILE: bin/template/cordova/defaults.xml
================================================
<?xml version='1.0' encoding='utf-8'?>
<!--
    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.
-->
<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

</widget>


================================================
FILE: bin/template/cordova/lib/build.js
================================================
#!/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.
*/

const path = require('node:path');
const check_reqs = require('./check_reqs');

/**
 * run
 *   Creates a zip file int platform/build folder
 */
module.exports.run = function () {
    return check_reqs.run();
};

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 + "'.");
};


================================================
FILE: bin/template/cordova/lib/clean.js
================================================
#!/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.
*/

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 () {
    // TODO: everything calls check_reqs ... why?
    // Check that requirements are (still) met
    if (!check_reqs.run()) {
        console.error('Please make sure you meet the software requirements in order to clean an browser cordova project');
        process.exit(2);
    }

    try {
        if (fs.existsSync(platformBuildDir)) {
            fs.rmSync(platformBuildDir, { recursive: true });
        }
    } catch (err) {
        console.log('could not remove ' + platformBuildDir + ' : ' + err.message);
    }
};

module.exports.run = run;
// just on the off chance something is still calling cleanProject, we will leave this here for a while
module.exports.cleanProject = function () {
    console.log('lib/clean will soon only export a `run` command, please update to not call `cleanProject`.');
    return run();
};


================================================
FILE: bin/template/cordova/lib/run.js
================================================
#!/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.
*/

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) {
    // defaults
    args.port = args.port || 8000;
    args.target = args.target || 'default'; // make default the system browser
    args.noLogOutput = args.silent || false;

    const wwwPath = path.join(__dirname, '../../www');
    const manifestFilePath = path.resolve(path.join(wwwPath, 'manifest.json'));

    let startPage;

    // get start page from manifest
    if (fs.existsSync(manifestFilePath)) {
        try {
            const manifest = require(manifestFilePath);
            startPage = manifest.start_url;
        } catch (err) {
            console.log('failed to require manifest ... ' + err);
        }
    }

    const server = cordovaServe();
    server.servePlatform('browser', { port: args.port, noServerInfo: true, noLogOutput: args.noLogOutput })
        .then(function () {
            if (!startPage) {
                // failing all else, set the default
                startPage = 'index.html';
            }

            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');
            return server.launchBrowser({ target: args.target, url: projectUrl });
        })
        .catch(function (error) {
            console.log(error.message || error.toString());
            if (server.server) {
                server.server.close();
            }
        });
};


================================================
FILE: bin/template/cordova/version
================================================
#!/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.
*/

// Coho updates this line:
const VERSION = '8.0.0-dev';

console.log(VERSION);


================================================
FILE: bin/template/www/css/index.css
================================================
/*
    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.
*/

* {
    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
}

body {
    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
    background-color:#E4E4E4;
    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-webkit-gradient(
        linear,
        left top,
        left bottom,
        color-stop(0, #A7A7A7),
        color-stop(0.51, #E4E4E4)
    );
    background-attachment:fixed;
    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
    font-size:12px;
    height:100%;
    margin:0px;
    padding:0px;
    text-transform:uppercase;
    width:100%;
}

/* Portrait layout (default) */
.app {
    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
    position:absolute;             /* position in the center of the screen */
    left:50%;
    top:50%;
    height:50px;                   /* text area height */
    width:225px;                   /* text area width */
    text-align:center;
    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
                                   /* offset horizontal: half of text area width */
}

/* Landscape layout (with min-width) */
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
    .app {
        background-position:left center;
        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
                                      /* offset horizontal: half of image width and text area width */
    }
}

h1 {
    font-size:24px;
    font-weight:normal;
    margin:0px;
    overflow:visible;
    padding:0px;
    text-align:center;
}

.event {
    border-radius:4px;
    -webkit-border-radius:4px;
    color:#FFFFFF;
    font-size:12px;
    margin:0px 30px;
    padding:2px 0px;
}

.event.listening {
    background-color:#333333;
    display:block;
}

.event.received {
    background-color:#4B946A;
    display:none;
}

@keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
@-webkit-keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
.blink {
    animation:fade 3000ms infinite;
    -webkit-animation:fade 3000ms infinite;
}


================================================
FILE: bin/template/www/index.html
================================================
<!DOCTYPE html>
<!--
    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.
-->
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="theme-color" content="#2196F3"/>
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        <link rel="manifest" href="manifest.json">
        <title>Hello World</title>
    </head>
    <body>
        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
        <script type="text/javascript">
            app.initialize();
        </script>
    </body>
</html>


================================================
FILE: bin/template/www/js/index.js
================================================
/*
    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 app = {
    // Application Constructor
    initialize: function () {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function () {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function () {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function (id) {
        const parentElement = document.getElementById(id);
        const listeningElement = parentElement.querySelector('.listening');
        const receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
    }
};


================================================
FILE: bin/template/www/manifest.json
================================================
{
  "name": "My App",
  "short_name":"My Ap",
  "description": "Description of your app from template",
  "start_url": "index.html",
  "scope":"index.html",
  "icons": [{
    "src": "img/logo.png",
    "sizes": "192x192",
    "type": "image/png"
  }, {
    "src": "img/splash.png",
    "sizes": "512x512",
    "type": "image/png"
  }],
  "default_locale": "en",
  "display": "standalone",
  "background_color":"#FFF",
  "theme_color":"#000",
  "orientation": "landscape"
}

================================================
FILE: cordova-js-src/confighelper.js
================================================
/*
    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.
*/

let config;

function Config (xhr) {
    function loadPreferences (xhr) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(xhr.responseText, 'application/xml');

        const preferences = doc.getElementsByTagName('preference');
        return Array.prototype.slice.call(preferences);
    }

    this.xhr = xhr;
    this.preferences = loadPreferences(this.xhr);
}

function readConfig (success, error) {
    const xhr = new XMLHttpRequest();

    if (typeof config !== 'undefined') {
        success(config);
    }

    function fail (msg) {
        console.error(msg);

        if (error) {
            error(msg);
        }
    }

    const xhrStatusChangeHandler = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200 || xhr.status === 304 || xhr.status === 0 /* file:// */) {
                config = new Config(xhr);
                success(config);
            } else {
                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);
            }
        }
    };

    xhr.addEventListener('load', xhrStatusChangeHandler);

    try {
        xhr.open('get', 'config.xml', true);
        xhr.send();
    } catch (e) {
        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));
    }
}

/**
 * Reads a preference value from config.xml.
 * Returns preference value or undefined if it does not exist.
 * @param {String} preferenceName Preference name to read */
Config.prototype.getPreferenceValue = function getPreferenceValue (preferenceName) {
    const preferenceItem = this.preferences && this.preferences.filter(function (item) {
        return item.attributes.name && item.attributes.name.value === preferenceName;
    });

    if (preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {
        return preferenceItem[0].attributes.value.value;
    }
};

exports.readConfig = readConfig;


================================================
FILE: cordova-js-src/exec.js
================================================
/*
    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.
*/

/* jslint sloppy:true, plusplus:true */
/* global require, module, console */

const cordova = require('cordova');
const execProxy = require('cordova/exec/proxy');

/**
 * Execute a cordova command.  It is up to the native side whether this action
 * is synchronous or asynchronous.  The native side can return:
 *      Synchronous: PluginResult object as a JSON string
 *      Asynchronous: Empty string ""
 * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
 * depending upon the result of the action.
 *
 * @param {Function} success    The success callback
 * @param {Function} fail       The fail callback
 * @param {String} service      The name of the service to use
 * @param {String} action       Action to be run in cordova
 * @param {String[]} [args]     Zero or more arguments to pass to the method
 */
module.exports = function (success, fail, service, action, args) {
    const proxy = execProxy.get(service, action);

    args = args || [];

    if (proxy) {
        const callbackId = service + cordova.callbackId++;

        if (typeof success === 'function' || typeof fail === 'function') {
            cordova.callbacks[callbackId] = { success, fail };
        }
        try {
            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or
            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }
            const onSuccess = function (result, callbackOptions) {
                callbackOptions = callbackOptions || {};
                let callbackStatus;
                // covering both undefined and null.
                // strict null comparison was causing callbackStatus to be undefined
                // and then no callback was called because of the check in cordova.callbackFromNative
                // see CB-8996 Mobilespec app hang on windows
                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {
                    callbackStatus = callbackOptions.status;
                } else {
                    callbackStatus = cordova.callbackStatus.OK;
                }
                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,
                    {
                        status: callbackStatus,
                        message: result,
                        keepCallback: callbackOptions.keepCallback || false
                    });
            };
            const onError = function (err, callbackOptions) {
                callbackOptions = callbackOptions || {};
                let callbackStatus;
                // covering both undefined and null.
                // strict null comparison was causing callbackStatus to be undefined
                // and then no callback was called because of the check in cordova.callbackFromNative
                // note: status can be 0
                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {
                    callbackStatus = callbackOptions.status;
                } else {
                    callbackStatus = cordova.callbackStatus.OK;
                }
                cordova.callbackError(callbackOptions.callbackId || callbackId,
                    {
                        status: callbackStatus,
                        message: err,
                        keepCallback: callbackOptions.keepCallback || false
                    });
            };
            proxy(onSuccess, onError, args);
        } catch (e) {
            console.log('Exception calling native with command :: ' + service + ' :: ' + action + ' ::exception=' + e);
        }
    } else {
        console.log('Error: exec proxy not found for :: ' + service + ' :: ' + action);

        if (typeof fail === 'function') {
            fail('Missing Command Error');
        }
    }
};


================================================
FILE: cordova-js-src/platform.js
================================================
/*
    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.
*/

module.exports = {
    id: 'browser',
    cordovaVersion: '4.2.0', // cordova-js

    bootstrap: function () {
        const modulemapper = require('cordova/modulemapper');
        const channel = require('cordova/channel');

        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');

        channel.onNativeReady.fire();

        document.addEventListener('visibilitychange', function () {
            if (document.hidden) {
                channel.onPause.fire();
            } else {
                channel.onResume.fire();
            }
        });

    // End of bootstrap
    }
};


================================================
FILE: eslint.config.js
================================================
/*
    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 { defineConfig, globalIgnores } = require('eslint/config');
const nodeConfig = require('@cordova/eslint-config/node');
const nodeTestConfig = require('@cordova/eslint-config/node-tests');
const browserConfig = require('@cordova/eslint-config/browser');

module.exports = defineConfig([
    globalIgnores([
        '**/coverage/',
        'bin/template/www/cordova.js'
    ]),
    ...nodeConfig.map(config => ({
        files: [
            '**/*.js',
            'bin/template/cordova/version'
        ],
        ...config
    })),
    ...nodeTestConfig.map(config => ({
        files: ['spec/**/*.js'],
        ...config
    })),
    ...browserConfig.map(config => ({
        files: [
            'cordova-js-src/**/*.js',
            'bin/template/www/**/*.js'
        ],
        ...config,
        languageOptions: {
            ...(config?.languageOptions || {}),
            globals: {
                ...(config.languageOptions?.globals || {}),
                require: 'readonly',
                module: 'readonly'
            }
        }
    }))
]);


================================================
FILE: licence_checker.yml
================================================
# 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.

# Empty for the release audit workflow.
# The `license-config` is required even if there are no custom configs


================================================
FILE: package.json
================================================
{
  "name": "cordova-browser",
  "version": "8.0.0-dev",
  "description": "cordova-browser release",
  "main": "bin/template/cordova/Api.js",
  "repository": "github:apache/cordova-browser",
  "bugs": "https://github.com/apache/cordova-browser/issues",
  "keywords": [
    "cordova",
    "browser",
    "apache"
  ],
  "scripts": {
    "prepare": "cordova-js build > bin/template/www/cordova.js",
    "cover": "c8 jasmine",
    "lint": "eslint .",
    "lint:fix": "npm run lint -- --fix",
    "jasmine": "jasmine",
    "test": "npm run lint && npm run cover"
  },
  "dependencies": {
    "cordova-common": "^6.0.0",
    "cordova-serve": "^4.0.1"
  },
  "devDependencies": {
    "@cordova/eslint-config": "^6.0.1",
    "c8": "^11.0.0",
    "cordova-js": "^6.1.0",
    "jasmine": "^6.1.0",
    "tmp": "^0.2.5"
  },
  "author": "Apache Software Foundation",
  "license": "Apache-2.0",
  "engines": {
    "node": "^20.17.0 || >=22.9.0"
  },
  "c8": {
    "include": [
      "bin/lib/**",
      "bin/templates/cordova/**"
    ],
    "reporter": [
      "lcov",
      "text"
    ]
  }
}


================================================
FILE: spec/browser_handler.spec.js
================================================
/*
    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 browser_handler = require('../bin/template/cordova/browser_handler');
const fs = require('node:fs');
const path = require('node:path');

describe('Asset install tests', function () {
    let fsstatMock;
    const asset = {
        itemType: 'asset',
        src: path.join('someSrc', 'ServiceWorker.js'),
        target: 'ServiceWorker.js'
    };
    const assetWithPath = {
        itemType: 'asset',
        src: path.join('someSrc', 'reformat.js'),
        target: path.join('js', 'deepdown', 'reformat.js')
    };
    const assetWithPath2 = {
        itemType: 'asset',
        src: path.join('someSrc', 'reformat.js'),
        target: path.join('js', 'deepdown', 'reformat2.js')
    };

    const plugin_dir = 'pluginDir';
    const wwwDest = 'dest';

    it('if src is a directory, should be called with cpSync recursive force', function () {
        const cp = spyOn(fs, 'cpSync').and.callFake(() => {});
        fsstatMock = {
            isDirectory: function () {
                return true;
            }
        };
        spyOn(fs, 'statSync').and.returnValue(fsstatMock);
        browser_handler.asset.install(asset, plugin_dir, wwwDest);
        expect(cp).toHaveBeenCalledWith(jasmine.any(String), path.join('dest', asset.target), {
            recursive: true,
            force: true
        });
    });
    it('if src is not a directory and asset has no path, should be called with cp, -f', function () {
        const cp = spyOn(fs, 'cpSync').and.callFake(() => {});
        const mkdir = spyOn(fs, 'mkdirSync');
        spyOn(fs, 'existsSync').and.returnValue(true);
        fsstatMock = {
            isDirectory: function () {
                return false;
            }
        };
        spyOn(fs, 'statSync').and.returnValue(fsstatMock);
        browser_handler.asset.install(asset, plugin_dir, wwwDest);
        expect(mkdir).not.toHaveBeenCalled();
        expect(cp).toHaveBeenCalledWith(path.join('pluginDir', asset.src), path.join('dest', asset.target), {
            force: true
        });
    });
    it('if src is not a directory and asset has a path, should be called with cp, -f', function () {
        /*
            Test that a dest directory gets created if it does not exist
        */
        const cp = spyOn(fs, 'cpSync').and.callFake(() => {});
        const mkdir = spyOn(fs, 'mkdirSync');
        fsstatMock = {
            isDirectory: function () {
                return false;
            }
        };
        spyOn(fs, 'statSync').and.returnValue(fsstatMock);

        browser_handler.asset.install(assetWithPath, plugin_dir, wwwDest);
        expect(mkdir).toHaveBeenCalledWith(path.join('dest', 'js', 'deepdown'), {
            recursive: true
        });
        expect(cp).toHaveBeenCalledWith(path.join('pluginDir', assetWithPath.src), path.join('dest', assetWithPath.target), {
            force: true
        });
        /*
            Now test that a second call to the same dest folder skips mkdir because the first asset call should have created it.
        */
        spyOn(fs, 'existsSync').and.returnValue(true);
        browser_handler.asset.install(assetWithPath2, plugin_dir, wwwDest);
        expect(mkdir.calls.count()).toBe(1); // not called again
    });
});


================================================
FILE: spec/create.spec.js
================================================
/*
    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 fs = require('node:fs');
const path = require('node:path');
const tmp = require('tmp');
const create = require('../bin/lib/create');

tmp.setGracefulCleanup();

function makeTempDir () {
    const tempdir = tmp.dirSync({ unsafeCleanup: true });
    return path.join(tempdir.name, `cordova-browser-create-test-${Date.now()}`);
}

/**
 * Verifies that some of the project file exists. Not all will be tested.
 * E.g. App's resource directory, xcodeproj, xcworkspace, and CordovaLib.
 *
 * @param {String} tmpDir
 * @param {String} projectName
 */
function verifyProjectFiles (tmpDir, projectName) {
    expect(fs.existsSync(path.join(tmpDir, 'www'))).toBe(true);
    expect(fs.existsSync(path.join(tmpDir, 'platform_www'))).toBe(true);
}

/**
 * Runs various project creation checks.
 *
 * @param {String} tmpDir
 * @param {String} packageName
 * @param {String} projectName
 * @returns {Promise}
 */
async function verifyCreatedProject (tmpDir, packageName, projectName) {
    await create.createProject(tmpDir, packageName, projectName)
        .then(() => verifyProjectFiles(tmpDir, projectName));
}

function verifyManifestFiles (tmpDir, projectName) {
    const manifestPath = path.join(tmpDir, 'platform_www/manifest.json');
    expect(fs.existsSync(manifestPath)).toBe(true);
    const manifestObj = require(manifestPath);
    expect(manifestObj.name).toBe(projectName);
    // start_url
    expect(manifestObj.start_url).toBe('index.html');
    // display
    expect(manifestObj.display).toBe('standalone');
    // description
    expect(manifestObj.description).toBeDefined();
    // background_color
    expect(manifestObj.background_color).toBeDefined();
    // theme_color
    expect(manifestObj.theme_color).toBeDefined();
    // scope
    expect(manifestObj.scope).toBeDefined();
    // orientation
    expect(manifestObj.orientation).toBeDefined();
    // icons
    expect(manifestObj.icons).toBeDefined();
    expect(Array.isArray(manifestObj.icons)).toBe(true);
    expect(manifestObj.icons.length).toBeDefined();
    expect(manifestObj.icons.length).toBeGreaterThan(0);
}

describe('create', () => {
    let tmpDir;

    beforeEach(function () {
        tmpDir = makeTempDir();
    });

    afterEach(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });

    it('create project with ascii name, no spaces', function () {
        const projectName = 'testcreate';
        const packageName = 'com.test.app1';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('create project with ascii name, and spaces', function () {
        const projectName = 'test create';
        const packageName = 'com.test.app2';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('create project with unicode name, no spaces', function () {
        const projectName = '応応応応用用用用';
        const packageName = 'com.test.app3';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('create project with unicode name, and spaces', function () {
        const projectName = '応応応応 用用用用';
        const packageName = 'com.test.app4';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('create project with ascii+unicode name, no spaces', function () {
        const projectName = '応応応応hello用用用用';
        const packageName = 'com.test.app5';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('create project with ascii+unicode name, and spaces', function () {
        const projectName = '応応応応 hello 用用用用';
        const packageName = 'com.test.app6';
        return verifyCreatedProject(tmpDir, packageName, projectName);
    });

    it('should have manifest.json', function () {
        const projectName = 'testcreate';
        const packageName = 'com.test.app1';
        return verifyCreatedProject(tmpDir, packageName, projectName)
            .then(() => verifyManifestFiles(tmpDir, projectName));
    });
});


================================================
FILE: spec/projectApi.spec.js
================================================
/*
    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 path = require('node:path');
const EventEmitter = require('node:events');

const Api = require('../bin/template/cordova/Api');
const create = require('../bin/lib/create');

describe('can get the Api', function () {
    it('should be defined', function () {
        expect(Api).toBeDefined();
    });

    it('should export static createPlatform function', function () {
        expect(Api.createPlatform).toBeDefined();
        expect(typeof Api.createPlatform).toBe('function');
    });

    it('should export static updatePlatform function', function () {
        expect(Api.updatePlatform).toBeDefined();
        expect(typeof Api.updatePlatform).toBe('function');
    });

    describe('static createPlatform method', () => {
        it('should create a platform app and return the Api', () => {
            // Trick function under test to load our Api after calling createProject
            const testDir = path.join(__dirname, '../bin/template');
            const testOpts = {};
            spyOn(create, 'createProject').and.returnValue(Promise.resolve());

            return Api.createPlatform(testDir, null, testOpts, new EventEmitter()).then(api => {
                expect(api).toBeInstanceOf(Api);
                expect(create.createProject).toHaveBeenCalledWith(
                    testDir, jasmine.any(String), jasmine.any(String), testOpts
                );
            });
        });
    });
});

describe('project level Api', function () {
    const testApi = new Api();

    it('can be created', function () {
        expect(testApi).toBeDefined();
    });

    it('has a requirements method', function () {
        expect(testApi.requirements).toBeDefined();
        expect(typeof testApi.requirements).toBe('function');
    });

    it('has a clean method', function () {
        expect(testApi.clean).toBeDefined();
        expect(typeof testApi.clean).toBe('function');
    });

    it('has a run method', function () {
        expect(testApi.run).toBeDefined();
        expect(typeof testApi.run).toBe('function');
    });

    it('has a build method', function () {
        expect(testApi.build).toBeDefined();
        expect(typeof testApi.build).toBe('function');
    });

    it('has a removePlugin method', function () {
        expect(testApi.removePlugin).toBeDefined();
        expect(typeof testApi.removePlugin).toBe('function');
    });

    it('has a addPlugin method', function () {
        expect(testApi.addPlugin).toBeDefined();
        expect(typeof testApi.addPlugin).toBe('function');
    });

    it('has a prepare method', function () {
        expect(testApi.prepare).toBeDefined();
        expect(typeof testApi.prepare).toBe('function');
    });

    it('has a getPlatformInfo method', function () {
        expect(testApi.getPlatformInfo).toBeDefined();
        expect(typeof testApi.getPlatformInfo).toBe('function');
    });
});

// Static methods
// Static method: createPlatform
// returns promise fulfilled with Api
// emits error using provided emmitter on error

// Static method: updatePlatform
// returns a promise fulfilled with an Api
// emits error using provided emmitter on error

// Instance methods
// requirements, clean, run, build, removePlugin, addPlugin, prepare, getPlatformInfo


================================================
FILE: spec/support/jasmine.json
================================================
{
    "spec_dir": "spec",
    "spec_files": [
    	"*[sS]pec.js"
    ],
    "helpers": [
    ],
    "stopSpecOnExpectationFailure": false,
    "random": false
}
Download .txt
gitextract_zo_vyim0/

├── .asf.yaml
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.md
│   │   ├── FEATURE_REQUEST.md
│   │   └── SUPPORT_QUESTION.md
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       └── release-audit.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── .ratignore
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── RELEASENOTES.md
├── bin/
│   ├── lib/
│   │   ├── check_reqs.js
│   │   ├── create.js
│   │   └── update.js
│   └── template/
│       ├── cordova/
│       │   ├── Api.js
│       │   ├── browser_handler.js
│       │   ├── browser_parser.js
│       │   ├── defaults.xml
│       │   ├── lib/
│       │   │   ├── build.js
│       │   │   ├── clean.js
│       │   │   └── run.js
│       │   └── version
│       └── www/
│           ├── css/
│           │   └── index.css
│           ├── index.html
│           ├── js/
│           │   └── index.js
│           └── manifest.json
├── cordova-js-src/
│   ├── confighelper.js
│   ├── exec.js
│   └── platform.js
├── eslint.config.js
├── licence_checker.yml
├── package.json
└── spec/
    ├── browser_handler.spec.js
    ├── create.spec.js
    ├── projectApi.spec.js
    └── support/
        └── jasmine.json
Download .txt
SYMBOL INDEX (15 symbols across 5 files)

FILE: bin/lib/create.js
  constant ROOT (line 24) | const ROOT = path.join(__dirname, '..', '..');

FILE: bin/template/cordova/Api.js
  constant PLATFORM_NAME (line 40) | const PLATFORM_NAME = 'browser';
  function setupEvents (line 42) | function setupEvents (externalEventEmitter) {
  function logFileOp (line 58) | function logFileOp (message) {
  function dirExists (line 62) | function dirExists (dir) {
  function Api (line 66) | function Api (platform, platformRootDir, events) {

FILE: bin/template/cordova/browser_parser.js
  function dirExists (line 26) | function dirExists (dir) {
  function browser_parser (line 30) | function browser_parser (project) {
  function logFileOp (line 46) | function logFileOp (message) {

FILE: cordova-js-src/confighelper.js
  function Config (line 22) | function Config (xhr) {
  function readConfig (line 35) | function readConfig (success, error) {

FILE: spec/create.spec.js
  function makeTempDir (line 27) | function makeTempDir () {
  function verifyProjectFiles (line 39) | function verifyProjectFiles (tmpDir, projectName) {
  function verifyCreatedProject (line 52) | async function verifyCreatedProject (tmpDir, packageName, projectName) {
  function verifyManifestFiles (line 57) | function verifyManifestFiles (tmpDir, projectName) {
Condensed preview — 43 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (125K chars).
[
  {
    "path": ".asf.yaml",
    "chars": 1002,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".gitattributes",
    "chars": 1909,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.md",
    "chars": 995,
    "preview": "---\nname: 🐛 Bug Report\nabout: If something isn't working as expected.\n\n---\n\n# Bug Report\n\n## Problem\n\n### What is expect"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.md",
    "chars": 598,
    "preview": "---\nname: 🚀 Feature Request\nabout: A suggestion for a new functionality\n\n---\n\n# Feature Request\n\n## Motivation Behind Fe"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md",
    "chars": 959,
    "preview": "---\nname: 💬 Support Question\nabout: If you have a question, please check out our Slack or StackOverflow!\n\n---\n\n<!-------"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1191,
    "preview": "<!--\nPlease have a look at the issue templates you get when you click \"New issue\" in the GitHub UI.\nWe very much prefer "
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1118,
    "preview": "<!--\nPlease make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 2573,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".github/workflows/release-audit.yml",
    "chars": 1627,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".gitignore",
    "chars": 996,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".npmignore",
    "chars": 994,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".npmrc",
    "chars": 822,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".ratignore",
    "chars": 824,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1375,
    "preview": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the N"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "NOTICE",
    "chars": 168,
    "preview": "Apache Cordova\nCopyright 2012-2015 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apach"
  },
  {
    "path": "README.md",
    "chars": 1623,
    "preview": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the N"
  },
  {
    "path": "RELEASENOTES.md",
    "chars": 8214,
    "preview": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/lib/check_reqs.js",
    "chars": 1038,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/lib/create.js",
    "chars": 3675,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/lib/update.js",
    "chars": 1812,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/cordova/Api.js",
    "chars": 23018,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/cordova/browser_handler.js",
    "chars": 6262,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/cordova/browser_parser.js",
    "chars": 3183,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/cordova/defaults.xml",
    "chars": 1008,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<!--\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more c"
  },
  {
    "path": "bin/template/cordova/lib/build.js",
    "chars": 1288,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/template/cordova/lib/clean.js",
    "chars": 1873,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/template/cordova/lib/run.js",
    "chars": 2511,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/template/cordova/version",
    "chars": 920,
    "preview": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license a"
  },
  {
    "path": "bin/template/www/css/index.css",
    "chars": 3733,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/www/index.html",
    "chars": 1885,
    "preview": "<!DOCTYPE html>\n<!--\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agre"
  },
  {
    "path": "bin/template/www/js/index.js",
    "chars": 1940,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "bin/template/www/manifest.json",
    "chars": 472,
    "preview": "{\n  \"name\": \"My App\",\n  \"short_name\":\"My Ap\",\n  \"description\": \"Description of your app from template\",\n  \"start_url\": \""
  },
  {
    "path": "cordova-js-src/confighelper.js",
    "chars": 2828,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "cordova-js-src/exec.js",
    "chars": 4741,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "cordova-js-src/platform.js",
    "chars": 1428,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "eslint.config.js",
    "chars": 1885,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "licence_checker.yml",
    "chars": 897,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": "package.json",
    "chars": 1081,
    "preview": "{\n  \"name\": \"cordova-browser\",\n  \"version\": \"8.0.0-dev\",\n  \"description\": \"cordova-browser release\",\n  \"main\": \"bin/temp"
  },
  {
    "path": "spec/browser_handler.spec.js",
    "chars": 4058,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "spec/create.spec.js",
    "chars": 4834,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "spec/projectApi.spec.js",
    "chars": 4082,
    "preview": "/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the N"
  },
  {
    "path": "spec/support/jasmine.json",
    "chars": 160,
    "preview": "{\n    \"spec_dir\": \"spec\",\n    \"spec_files\": [\n    \t\"*[sS]pec.js\"\n    ],\n    \"helpers\": [\n    ],\n    \"stopSpecOnExpectati"
  }
]

About this extraction

This page contains the full source code of the apache/cordova-browser GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 43 files (116.2 KB), approximately 28.0k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!