├── .gitattributes ├── coverage └── blanket.js ├── test └── placeholder.js ├── commands ├── index.js ├── run.js ├── open.js ├── package.js ├── visualstudio.js ├── platform.js └── generate.js ├── .jshintrc ├── .github ├── ISSUE_TEMPLATE │ ├── question-.md │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── codeql.yml ├── platforms.json ├── .gitignore ├── LICENSE.txt ├── index.js ├── package.json ├── CONTRIBUTING.md ├── Gruntfile.js ├── pwabuilder.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Make sure that pwabuilder.js file will always have LF line endings on checkout. 2 | pwabuilder.js eol=lf -------------------------------------------------------------------------------- /coverage/blanket.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var srcDir = path.join(__dirname, '..', 'lib'); 3 | 4 | require('blanket')({ 5 | // Only files that match the pattern will be instrumented 6 | pattern: srcDir 7 | }); 8 | -------------------------------------------------------------------------------- /test/placeholder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('PLACEHOLDER', function () { 4 | describe('TO BE DETERMINED', function () { 5 | it('Original tests were moved to pwabuilder-lib. Should implement tests for remaining code.'); 6 | }); 7 | }); -------------------------------------------------------------------------------- /commands/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | generate: require('./generate'), 5 | package: require('./package'), 6 | run: require('./run'), 7 | open: require('./open'), 8 | visualstudio: require('./visualstudio'), 9 | platform: require('./platform') 10 | }; 11 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "indent": 2, 6 | "latedef": true, 7 | "newcap": true, 8 | "noarg": true, 9 | "sub": true, 10 | "undef": true, 11 | "unused": true, 12 | "boss": true, 13 | "eqnull": true, 14 | "node": true, 15 | "quotmark": "single", 16 | 17 | "globals": { 18 | "after": false, 19 | "before": false, 20 | "afterEach": false, 21 | "beforeEach": false, 22 | "describe": false, 23 | "it": false, 24 | "mocha": false, 25 | "expect": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /commands/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | 5 | var lib = require('pwabuilder-lib'); 6 | 7 | var log = lib.log, 8 | projectBuilder = lib.projectBuilder; 9 | 10 | function runApp (program) { 11 | 12 | if (program.args.length < 2) { 13 | return Q.reject(new Error('You must specify a platform.')); 14 | } 15 | 16 | var platform = program.args[1]; 17 | var projectDir = program.args.length < 3 ? process.cwd() : program.args[2]; 18 | return projectBuilder.runApp(platform, projectDir, program); 19 | } 20 | 21 | module.exports = runApp; 22 | -------------------------------------------------------------------------------- /commands/open.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | 5 | var lib = require('pwabuilder-lib'); 6 | 7 | var log = lib.log, 8 | projectBuilder = lib.projectBuilder; 9 | 10 | function openApp (program) { 11 | 12 | if (program.args.length < 2) { 13 | return Q.reject(new Error('You must specify a platform.')); 14 | } 15 | 16 | var platform = program.args[1]; 17 | var projectDir = program.args.length < 3 ? process.cwd() : program.args[2]; 18 | return projectBuilder.openApp(platform, projectDir, program); 19 | } 20 | 21 | module.exports = openApp; 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Question ' 3 | about: I have a question about something in PWABuilder-CLI 4 | title: "[Question] " 5 | labels: 'question :grey_question:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Question in detail** 11 | A clear and concise description of what you want to know or confused about. 12 | 13 | **Is your question related to a problem? Please describe.** 14 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions you've considered. 18 | 19 | **Additional context** 20 | Add any other details that will help understand the question. 21 | -------------------------------------------------------------------------------- /platforms.json: -------------------------------------------------------------------------------- 1 | { 2 | "windows10": { 3 | "packageName": "pwabuilder-windows10", 4 | "source": "pwabuilder-windows10" 5 | }, 6 | "android": { 7 | "packageName": "pwabuilder-android", 8 | "source": "pwabuilder-android" 9 | }, 10 | "macos": { 11 | "packageName": "pwabuilder-macos", 12 | "source": "pwabuilder-macos" 13 | }, 14 | "ios": { 15 | "packageName": "pwabuilder-cordova", 16 | "source": "pwabuilder-cordova" 17 | }, 18 | "web": { 19 | "packageName": "pwabuilder-web", 20 | "source": "pwabuilder-web" 21 | }, 22 | "edgeextension": { 23 | "packageName": "pwabuilder-edgeextension", 24 | "source": "pwabuilder-edgeextension" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Visual Studio 17 | launch.json 18 | .ntvs_analysis.dat 19 | *.njsproj 20 | *.suo 21 | *.sln 22 | .vs 23 | 24 | # Blanket coverage 25 | coverage.html 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (http://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directory 37 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 38 | node_modules 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: 'Create a report to help us improve PWABuilder! ' 4 | title: '' 5 | labels: 'bug :bug:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /commands/package.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var lib = require('pwabuilder-lib'); 4 | 5 | var log = lib.log, 6 | platformTools= lib.platformTools, 7 | projectBuilder = lib.projectBuilder; 8 | 9 | function packageApps(program, platforms) { 10 | if (!platforms) { 11 | platforms = program.platforms ? 12 | program.platforms.split(/[\s,]+/) : 13 | platformTools.listPlatforms(); 14 | } 15 | 16 | var projectDir = program.args.length < 2 ? process.cwd() : program.args[1]; 17 | return lib.projectTools.getProjectPlatforms(projectDir).then(function (projectPlatforms) { 18 | log.debug('Available platforms within project: ' + projectPlatforms); 19 | 20 | // exclude any platforms not present in the project 21 | platforms = platforms.filter(function (platform) { 22 | return projectPlatforms.indexOf(platform) >= 0; 23 | }); 24 | 25 | log.debug('Packaging the following platforms: ' + platforms); 26 | 27 | return projectBuilder.packageApps(platforms, projectDir, program); 28 | }); 29 | } 30 | 31 | module.exports = packageApps; -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | PWA Builder 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes # 2 | 3 | 4 | ## PR Type 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ## Describe the current behavior? 18 | 19 | 20 | 21 | ## Describe the new behavior? 22 | 23 | 24 | ## PR Checklist 25 | 26 | - [ ] Test: run `npm run test` and ensure that all tests pass 27 | - [ ] Target master branch (or an appropriate release branch if appropriate for a bug fix) 28 | - [ ] Ensure that your contribution follows [standard accessibility guidelines](https://docs.microsoft.com/en-us/microsoft-edge/accessibility/design). Use tools like https://webhint.io/ to validate your changes. 29 | 30 | 31 | ## Additional Information 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * **NOTE**: Use of pwabuilder as a library is now DEPRECATED. Use pwabuilder-lib instead. 3 | * 4 | * The top-level API for `pwabuilder`. Provides access to the key libraries in 5 | * pwabuilder so you can write your own tools using `pwabuilder` as a library. 6 | * 7 | * Usage 8 | * ----- 9 | * 10 | * var pwabuilder = require('pwabuilder-lib'); 11 | * 12 | */ 13 | 14 | var lib = require('pwabuilder-lib'); 15 | var libValidationContants = lib.constants.validation; 16 | 17 | // Maintain compatibility with original constant definitions 18 | var validationConstants = { 19 | levels: libValidationContants.levels, 20 | codes: libValidationContants.codes, 21 | manifestMembers: libValidationContants.manifestMembers, 22 | platforms: { 23 | all: 'all', 24 | android: 'android', 25 | ios: 'ios', 26 | windows: 'windows' 27 | }, 28 | platformDisplayNames: { 29 | all: 'All Platforms', 30 | android: 'Android', 31 | ios: 'iOS', 32 | windows: 'Windows' 33 | } 34 | }; 35 | 36 | module.exports = { 37 | manifestTools: lib.manifestTools, 38 | validationConstants: validationConstants, 39 | projectBuilder: lib.projectBuilder, 40 | projectTools: lib.projectTools 41 | }; 42 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 19 * * 0' 8 | 9 | jobs: 10 | CodeQL-Build: 11 | 12 | # CodeQL runs on ubuntu-latest and windows-latest 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | with: 19 | # We must fetch at least the immediate parents so that if this is 20 | # a pull request then we can checkout the head. 21 | fetch-depth: 2 22 | 23 | # If this run was triggered by a pull request event, then checkout 24 | # the head of the pull request instead of the merge commit. 25 | - run: git checkout HEAD^2 26 | if: ${{ github.event_name == 'pull_request' }} 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v1 31 | # Override language selection by uncommenting this and choosing your languages 32 | # with: 33 | # languages: go, javascript, csharp, python, cpp, java 34 | 35 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 36 | # If this step fails, then you should remove it and run the build manually (see below) 37 | - name: Autobuild 38 | uses: github/codeql-action/autobuild@v1 39 | 40 | # ℹ️ Command-line programs to run using the OS shell. 41 | # 📚 https://git.io/JvXDl 42 | 43 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 44 | # and modify them (or add more) to build your code if your project 45 | # uses a compiled language 46 | 47 | #- run: | 48 | # make bootstrap 49 | # make release 50 | 51 | - name: Perform CodeQL Analysis 52 | uses: github/codeql-action/analyze@v1 53 | -------------------------------------------------------------------------------- /commands/visualstudio.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | 5 | var lib = require('pwabuilder-lib'); 6 | 7 | var CustomError = lib.CustomError, 8 | exec = lib.processTools.exec, 9 | fileTools = lib.fileTools, 10 | log = lib.log; 11 | 12 | var open = require('./open'); 13 | 14 | function isWindows10Version (version) { 15 | return /^10/.test(version); 16 | } 17 | 18 | function getWindowsVersion (callback) { 19 | log.debug('Obtaining Windows version...'); 20 | exec('powershell', ['(Get-WmiObject win32_operatingsystem).version']).then(function (result) { 21 | return result.stdout.trim(); 22 | }) 23 | .catch (function (err) { 24 | return Q.reject(new CustomError('Failed to run the app for Windows platform.', err)); 25 | }) 26 | .nodeify(callback); 27 | } 28 | 29 | // implements the original behavior of the visualstudio command 30 | // open windows10 project, if available, otherwise, open the windows project 31 | function runApp(program) { 32 | 33 | log.warn('The \'visualstudio\' command is deprecated. Use \'pwabuilder open \' instead.'); 34 | 35 | var deferred = Q.defer(); 36 | 37 | var dir = process.cwd(); 38 | fileTools.searchFile(dir, 'App.jsproj', function (err, results) { 39 | Q.ninvoke(getWindowsVersion).then(function (version) { 40 | if (results && results.length > 0 && isWindows10Version(version)) { 41 | program.args.push('windows10'); 42 | return open(program).then(function () { 43 | deferred.resolve(); 44 | }); 45 | } 46 | 47 | fileTools.searchFile(dir, 'CordovaApp.sln', function (err, results) { 48 | if (results && results.length > 0) { 49 | program.args.push('windows'); 50 | return open(program).then(function () { 51 | deferred.resolve(); 52 | }); 53 | } 54 | }); 55 | }); 56 | }); 57 | 58 | return deferred.promise; 59 | } 60 | 61 | module.exports = runApp; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pwabuilder", 3 | "version": "2.0.3-rc.0", 4 | "description": "Node.js Tool for App Generation", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/manifoldjs/ManifoldJS.git" 8 | }, 9 | "engines": { 10 | "node": ">=0.12.0" 11 | }, 12 | "engineStrict": true, 13 | "author": { 14 | "name": "TBD", 15 | "email": "TBD", 16 | "url": "TBD" 17 | }, 18 | "license": "MIT", 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "https://github.com/manifoldjs/ManifoldJS/blob/master/LICENSE.txt" 23 | } 24 | ], 25 | "keywords": [ 26 | "convert manifest", 27 | "manifest", 28 | "W3C", 29 | "Firefox OS", 30 | "Windows 10", 31 | "Chrome OS", 32 | "Android", 33 | "iOS" 34 | ], 35 | "dependencies": { 36 | "commander": "^2.9.0", 37 | "pwabuilder-cordova": "^2.0.0-rc.3", 38 | "pwabuilder-edgeextension": "^2.0.0-rc", 39 | "pwabuilder-lib": "^2.0.4-RC.2", 40 | "pwabuilder-web": "^2.0.0-rc.3", 41 | "pwabuilder-windows10": "^2.0.4-rc.4", 42 | "pwabuilder-macos": "^0.3.11", 43 | "q": "^1.4.1" 44 | }, 45 | "devDependencies": { 46 | "blanket": "1.1.6", 47 | "grunt": "^1.0.3", 48 | "grunt-cli": "^1.3.2", 49 | "grunt-contrib-jshint": "^2.0.0", 50 | "grunt-contrib-nodeunit": "^2.0.0", 51 | "grunt-contrib-watch": "^1.1.0", 52 | "grunt-mocha-test": "^0.12.7", 53 | "grunt-sync": "^0.6.2", 54 | "jshint-stylish": "^1.0.0", 55 | "jshint-teamcity": "^1.0.6", 56 | "load-grunt-tasks": "^4.0.0", 57 | "mocha": "^5.2.0", 58 | "mocha-teamcity-reporter": "0.0.4", 59 | "should": "^5.0.1", 60 | "time-grunt": "^1.0.0", 61 | "travis-cov": "^0.2.5" 62 | }, 63 | "scripts": { 64 | "test": "grunt", 65 | "debug-tests": "mocha --debug-brk", 66 | "setup": "npm install && npm-install-peers" 67 | }, 68 | "bin": "pwabuilder.js", 69 | "config": { 70 | "travis-cov": { 71 | "threshold": 80 72 | } 73 | }, 74 | "bugs": { 75 | "url": "https://github.com/manifoldjs/ManifoldJS/issues" 76 | }, 77 | "homepage": "https://github.com/manifoldjs/ManifoldJS" 78 | } 79 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to PWA Builder 2 | 3 | ## Join in the Fun 4 | 5 | PWA Builder is a community project. Our goal is to leverage community tools when possible, build for the platforms the Web Developer community will target, and solicit contributes from the community at large. We would love to have some help from our developers. You can contribute in a number of ways: 6 | 7 | 1. **Report a Bug**: We know we have them, you know we have them. Go to GitHub and help us [identify them](https://github.com/manifoldjs/ManifoldJS/issues). 8 | 2. **Fix a Bug or add a feature**: We happily accept code contributions that make our framework better. We have a few code contribution requirements that need to be met (see contribution guidelines below). 9 | 3. **Support a new platform**: Are there other platforms that your targeting that support (or have a polyfill for) hosted web apps? Contribute the code to support additional platforms (see contribute guidelines below). 10 | 11 | 12 | ## Contribution Guidelines 13 | 14 | 1. Code contribution must have an issue tracking it in the issue tracker that has been approved (Status = Active) by the PWA Builder team. Your pull request should include a link to the bug that you are fixing 15 | 2. You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project’s license, and that the work being submitted is under appropriate copyright. (docx: [Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190), pdf: [Microsoft Contribution License Agreement.pdf](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=921298) ). 16 | 3. Contribution should be done through a pull request: 17 | 18 | 1. Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR) 19 | 2. Have clear commit messages ("bug fix" and "new feature" are reserved for the core team :P ) 20 | 21 | 4. Should include a simple test case for you change (that passes :) ). Test cases should utilize existing test frameworks (mocha.js, should.js) 22 | -------------------------------------------------------------------------------- /commands/platform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'); 5 | 6 | var Q = require('q'); 7 | 8 | var lib = require('pwabuilder-lib'); 9 | 10 | var log = lib.log, 11 | platformTools = lib.platformTools, 12 | utils = lib.utils; 13 | 14 | // registers a new platform module 15 | function addPlatform (program) { 16 | if (program.args.length < 3) { 17 | return Q.reject(new Error('You must specify a platform ID.')); 18 | } 19 | 20 | if (program.args.length < 4) { 21 | return Q.reject(new Error('You must specify a package source for the platform. This can be an npm package, a GitHub URL, or a local path.')); 22 | } 23 | 24 | var platformId = program.args[2].toLowerCase(); 25 | var source = program.args[3]; 26 | 27 | return platformTools.addPlatform(platformId, source).then(function () { 28 | log.info('The \'' + platformId + '\' platform was registered successfully.'); 29 | }); 30 | } 31 | 32 | // removes a registered platform module 33 | function removePlatform (program) { 34 | if (program.args.length < 3) { 35 | return Q.reject(new Error('You must specify a platform ID.')); 36 | } 37 | 38 | var platformId = program.args[2].toLowerCase(); 39 | 40 | return platformTools.removePlatform(platformId).then(function () { 41 | log.info('The \'' + platformId + '\' platform was unregistered successfully.'); 42 | }); 43 | } 44 | 45 | function listPlatforms (program) { 46 | try { 47 | var platforms = platformTools.listPlatforms(); 48 | log.write('Available platforms are: ' + platforms.join(', ')); 49 | return Q.resolve(); 50 | } 51 | catch (err) { 52 | return Q.reject(err); 53 | } 54 | } 55 | 56 | function platformCommands (program) { 57 | if (program.args.length < 2) { 58 | return Q.reject(new Error('You must specify a platform operation: add, remove, or list.')); 59 | } 60 | 61 | var command = program.args[1].toLowerCase(); 62 | switch (command) { 63 | case 'add': 64 | return addPlatform(program); 65 | 66 | case 'remove': 67 | return removePlatform(program); 68 | 69 | case 'list': 70 | return listPlatforms(program); 71 | 72 | default: 73 | return Q.reject(new Error('Unknown option \'' + command + '\' specified.')); 74 | } 75 | } 76 | 77 | module.exports = platformCommands; 78 | 79 | 80 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | // Show elapsed time at the end 5 | require('time-grunt')(grunt); 6 | // Load all grunt tasks 7 | require('load-grunt-tasks')(grunt); 8 | 9 | grunt.initConfig({ 10 | jshint: { 11 | options: { 12 | jshintrc: '.jshintrc', 13 | reporter: require('jshint-stylish') 14 | }, 15 | gruntfile: { 16 | src: ['Gruntfile.js'] 17 | }, 18 | js: { 19 | src: ['*.js', 'lib/**/*.js'] 20 | }, 21 | test: { 22 | src: ['test/**/*.js'] 23 | }, 24 | teamcity: { 25 | options: { 26 | reporter: require('jshint-teamcity') 27 | }, 28 | src: ['*.js', 'lib/**/*.js', 'test/**/*.js', 'Gruntfile.js'] 29 | }, 30 | }, 31 | mochaTest: { 32 | test: { 33 | options: { 34 | reporter: 'spec', 35 | require: 'coverage/blanket' 36 | }, 37 | src: ['test/**/*.js'] 38 | }, 39 | 'html-cov': { 40 | options: { 41 | reporter: 'html-cov', 42 | quiet: true, 43 | captureFile: 'coverage.html' 44 | }, 45 | src: ['lib/**/*.js'] 46 | }, 47 | // The travis-cov reporter will fail the tests if the 48 | // coverage falls below the threshold configured in package.json 49 | 'travis-cov': { 50 | options: { 51 | reporter: 'travis-cov' 52 | }, 53 | src: ['lib/**/*.js'] 54 | }, 55 | 'teamcity-test': { 56 | options: { 57 | reporter: 'mocha-teamcity-reporter' 58 | }, 59 | src: ['test/**/*.js'] 60 | } 61 | }, 62 | watch: { 63 | gruntfile: { 64 | files: '<%= jshint.gruntfile.src %>', 65 | tasks: ['jshint:gruntfile'] 66 | }, 67 | js: { 68 | files: '<%= jshint.js.src %>', 69 | tasks: ['jshint:js', 'mochaTest'] 70 | }, 71 | test: { 72 | files: '<%= jshint.test.src %>', 73 | tasks: ['jshint:test', 'mochaTest'] 74 | }, 75 | windows10: { 76 | files: ['../pwabuilder-windows10/lib/*.js'], 77 | tasks: ['sync:windows10'] 78 | }, 79 | lib: { 80 | files: ['../pwabuilder-lib/lib/*.js', '../pwabuilder-lib/lib/manifestTools/*.js'], 81 | tasks: ['sync:lib'] 82 | } 83 | }, 84 | sync: { 85 | windows10: { 86 | files: [{ 87 | src: ['../pwabuilder-windows10/lib/*.js'], 88 | dest: 'node_modules/pwabuilder-windows10' 89 | }], 90 | verbose: true, 91 | failOnError: true, 92 | updateAndDelete: false 93 | }, 94 | lib: { 95 | files: [{ 96 | src: ['../pwabuilder-lib/lib/*.js','../pwabuilder-lib/lib/manifestTools/*.js'], 97 | dest: 'node_modules/pwabuilder-lib' 98 | }], 99 | verbose: true, 100 | failOnError: true, 101 | updateAndDelete: false 102 | } 103 | } 104 | }); 105 | 106 | grunt.registerTask('jshint-all', ['jshint:js', 'jshint:test', 'jshint:gruntfile']); 107 | grunt.registerTask('tests-all', ['mochaTest:test', 'mochaTest:html-cov', 'mochaTest:travis-cov']); 108 | 109 | grunt.registerTask('default', ['jshint-all', 'tests-all']); 110 | 111 | grunt.registerTask('teamcity-tests', ['mochaTest:teamcity-test']); 112 | grunt.registerTask('teamcity-jshint', ['jshint:teamcity']); 113 | 114 | grunt.registerTask('teamcity-build', ['teamcity-jshint', 'teamcity-tests']); 115 | 116 | grunt.registerTask('development', ['watch']); 117 | grunt.registerTask('forceSync', ['sync:windows10', 'sync:lib']); 118 | }; 119 | -------------------------------------------------------------------------------- /commands/generate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var url = require('url'), 4 | path = require('path'); 5 | 6 | var Q = require('q'); 7 | 8 | var lib = require('pwabuilder-lib'); 9 | 10 | var log = lib.log, 11 | manifestTools = lib.manifestTools, 12 | platformTools = lib.platformTools, 13 | projectBuilder = lib.projectBuilder, 14 | utils = lib.utils; 15 | 16 | var build = require('./package'); 17 | 18 | function getW3cManifest(siteUrl, manifestLocation, manifestFormat, callback) { 19 | function resolveStartURL(err, manifestInfo) { 20 | if (err) { 21 | return callback(err, manifestInfo); 22 | } 23 | 24 | if (manifestInfo.format === lib.constants.BASE_MANIFEST_FORMAT) { 25 | return manifestTools.validateAndNormalizeStartUrl(siteUrl, manifestInfo, callback); 26 | } else { 27 | return callback(undefined, manifestInfo); 28 | } 29 | } 30 | 31 | if (siteUrl) { 32 | var parsedSiteUrl = url.parse(siteUrl); 33 | if (!parsedSiteUrl.hostname) { 34 | return callback(new Error('The site URL is not a valid URL.')); 35 | } 36 | } 37 | 38 | if (manifestLocation) { 39 | var parsedManifestUrl = url.parse(manifestLocation); 40 | if (parsedManifestUrl && parsedManifestUrl.host) { 41 | // download manifest from remote location 42 | log.info('Downloading manifest from ' + manifestLocation + '...'); 43 | manifestTools.downloadManifestFromUrl(manifestLocation, manifestFormat, resolveStartURL); 44 | } else { 45 | // read local manifest file 46 | log.info('Reading manifest file ' + manifestLocation + '...'); 47 | manifestTools.getManifestFromFile(manifestLocation, manifestFormat, resolveStartURL); 48 | } 49 | } else if (siteUrl) { 50 | // scan a site to retrieve its manifest 51 | log.info('Scanning ' + siteUrl + ' for manifest...'); 52 | manifestTools.getManifestFromSite(siteUrl, manifestFormat, resolveStartURL); 53 | } else { 54 | return callback(new Error('A site URL or manifest should be specified.')); 55 | } 56 | } 57 | 58 | function generateApp(program) { 59 | 60 | var siteUrl = program.args[0]; 61 | var rootDir = program.directory ? path.resolve(program.directory) : process.cwd(); 62 | 63 | var deferred = Q.defer(); 64 | 65 | function callback (err, manifestInfo) { 66 | if (err) { 67 | return deferred.reject(err); 68 | } 69 | 70 | // Fix #145: don't require a short name 71 | manifestInfo.content.short_name = manifestInfo.content.short_name || 72 | manifestInfo.content.name || 73 | manifestInfo.default.short_name; 74 | 75 | // if specified as a parameter, override the app's short name 76 | if (program.shortname) { 77 | manifestInfo.content.short_name = program.shortname; 78 | } 79 | 80 | log.debug('Manifest contents:\n' + JSON.stringify(manifestInfo.content, null, 4)); 81 | 82 | // add generatedFrom value to manifestInfo for telemetry 83 | manifestInfo.generatedFrom = 'CLI'; 84 | 85 | var platforms = []; 86 | if (program.platforms) { 87 | platforms = program.platforms.split(/[\s,]+/); 88 | } else { 89 | platforms = platformTools.listPlatforms(); 90 | // Remove edgeextension from the default platforms for W3C manifests 91 | if (manifestInfo.format === lib.constants.BASE_MANIFEST_FORMAT) { 92 | var edgeIndex = platforms.indexOf('edgeextension'); 93 | if (edgeIndex > -1) { 94 | log.debug('Removing Edge Extension platform. The W3C manifest format is not currently supported by this platform.'); 95 | platforms.splice(edgeIndex, 1); 96 | } 97 | } 98 | } 99 | 100 | // Create the apps for the specified platforms 101 | return projectBuilder.createApps(manifestInfo, rootDir, platforms, program).then(function (projectDir) { 102 | if (program.build) { 103 | program.args[1] = projectDir; 104 | return build(program, platforms).catch(function (err) { 105 | log.warn('One or more platforms could not be built successfully. Correct any errors and then run pwabuilder package [project-directory] [options] to build the applications.'); 106 | // return deferred.reject(err); 107 | }); 108 | } 109 | }) 110 | .then(function () { 111 | log.info('The application(s) are ready.'); 112 | return deferred.resolve(); 113 | }) 114 | .catch(function (err) { 115 | return deferred.reject(err); 116 | }); 117 | }; 118 | 119 | getW3cManifest(siteUrl, program.manifest, program.forceManifestFormat, callback); 120 | 121 | return deferred.promise; 122 | }; 123 | 124 | module.exports = generateApp; -------------------------------------------------------------------------------- /pwabuilder.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var Q = require('q'); 5 | 6 | var lib = require('pwabuilder-lib'); 7 | 8 | var log = lib.log, 9 | packageTools = lib.packageTools, 10 | platformTools = lib.platformTools, 11 | manifestTools = lib.manifestTools, 12 | validations = lib.validations; 13 | 14 | var commands = require('./commands'); 15 | 16 | // Get the available formats for the --forceManifestFormat parameter 17 | var availableManifestFormats = manifestTools.listAvailableManifestFormats(); 18 | 19 | function checkParameters(program) { 20 | var unknownArgs = 0; 21 | if (program.args.length > 0) { 22 | var command = program.args[0].toLowerCase(); 23 | switch (command) { 24 | case 'run': 25 | unknownArgs = 3; 26 | program.run = true; 27 | break; 28 | case 'package': 29 | unknownArgs = 2; 30 | program.package = true; 31 | break; 32 | case 'platform': 33 | unknownArgs = 4; 34 | program.platform = true; 35 | break; 36 | case 'open': 37 | unknownArgs = 3; 38 | program.open = true; 39 | break; 40 | case 'visualstudio': 41 | unknownArgs = 1; 42 | program.visualstudio = true; 43 | break; 44 | default: 45 | unknownArgs = 1; 46 | break; 47 | } 48 | } else { 49 | if (!program.manifest) { 50 | return 'You must specify either the web site URL or the location of a W3C manifest (-m | --manifest).'; 51 | } 52 | } 53 | 54 | if (program.args.length > unknownArgs) { 55 | return 'Unexpected parameters - [' + program.args.slice(unknownArgs).join() + '].'; 56 | } 57 | 58 | // check platforms 59 | // TODO: loading registered platforms twice, by calling platformsValid and to generate the usage text. Consolidate! 60 | if (program.platforms) { 61 | var platforms = program.platforms.split(/[\s,]+/); 62 | if (!validations.platformsValid(platforms)) { 63 | return 'Invalid platform(s) specified.'; 64 | } 65 | } 66 | 67 | // check log level 68 | if (program.loglevel) { 69 | if (!validations.logLevelValid(program.loglevel)) { 70 | return 'Invalid loglevel specified. Valid values are: debug, info, warn, error.'; 71 | } 72 | } 73 | 74 | if (program.forceManifestFormat) { 75 | if (!validations.manifestFormatValid(program.forceManifestFormat)) { 76 | return 'Invalid manifest format specified. Valid values are: ' + availableManifestFormats.join(', ') + '.'; 77 | } 78 | } 79 | } 80 | 81 | // get the list of registered platforms 82 | var availablePlatforms = platformTools.listPlatforms(); 83 | 84 | // dynamically generates the help text with the list of registered 85 | // platforms and splits it into multiple lines so that it doesn't 86 | // break the layout of the usage text 87 | function getPlatformHelpText() { 88 | // offset of the column where the parameter help text starts 89 | var columnOffset = 38; 90 | 91 | // maximum width of the help text 92 | var maxWidth = 80; 93 | 94 | return availablePlatforms.reduce(function (list, platform) { 95 | var segmentLength = list.length - list.lastIndexOf('\n') - 1; 96 | if (segmentLength > maxWidth - columnOffset) { 97 | list += '\n'; 98 | } 99 | 100 | return list + '[' + (list ? ',' : '') + platform + ']'; 101 | }, '').replace(/\n/g, '\n' + new Array(columnOffset - 1).join(' ')); 102 | } 103 | 104 | var program = require('commander') 105 | .usage(' [options]' + 106 | '\n pwabuilder -m [options]' + 107 | '\n options:' + 108 | '\n -d | --directory, -s | --short-name, -l | --loglevel, -p | --platforms' + 109 | '\n -i | --image, -m | --manifest, -f | --forceManifestFormat, -c | --crosswalk' + 110 | '\n -or-' + 111 | '\n pwabuilder package [project-directory] [options]' + 112 | '\n options:' + 113 | '\n -l | --loglevel, -p | --platforms, -S | --Sign, -W | --DotWeb, -a | --AutoPublish' + 114 | '\n' + 115 | '\n -or-' + 116 | '\n pwabuilder platform add [options]' + 117 | '\n pwabuilder platform remove [options]' + 118 | '\n pwabuilder platform list [options]' + 119 | '\n options:' + 120 | '\n -l | --loglevel' + 121 | '\n' + 122 | '\n -or-' + 123 | '\n pwabuilder run [project-directory] [options]' + 124 | '\n options:' + 125 | '\n -l | --loglevel' + 126 | '\n' + 127 | '\n -or-' + 128 | '\n pwabuilder open [project-directory] [options]' + 129 | '\n options:' + 130 | '\n -l | --loglevel') 131 | .option('-d, --directory ', 'path to the generated project files') 132 | .option('-s, --shortname ', 'application short name') 133 | .option('-l, --loglevel ', 'debug|info|warn|error', 'warn') 134 | .option('-p, --platforms ', getPlatformHelpText()) 135 | .option('-m, --manifest ', 'location of the W3C Web App manifest\n ' + 136 | 'file (URL or local path)') 137 | .option('-i, --image ', 'local path to the image file used to\n ' + 138 | 'generate missing icons in the manifest') 139 | .option('-c, --crosswalk', 'enable Crosswalk for Android', false) 140 | .option('-S, --Sign', 'return a signed package for Windows 10', false) 141 | .option('-w, --webAppToolkit', 'adds the Web App Toolkit cordova plugin', false) 142 | .option('-f, --forceManifestFormat ', availableManifestFormats.join('|')) 143 | .option('-W, --DotWeb', 'generate a .web package for Windows 10', false) 144 | .option('-a, --AutoPublish', 'auto-publish a package for Windows 10', false) 145 | .parse(process.argv); 146 | 147 | if (!process.argv.slice(2).length) { 148 | program.help(); 149 | } 150 | 151 | var validationResult = checkParameters(program); 152 | if (validationResult) { 153 | log.error(validationResult); 154 | process.exit(1); 155 | } 156 | 157 | global.logLevel = program.loglevel; 158 | log.setLevel(global.logLevel); 159 | 160 | if (process.env.NODE_ENV === 'development') { 161 | Q.longStackSupport = true; 162 | } 163 | packageTools.checkForUpdate(function (err, updateAvailable) { 164 | if (!err && updateAvailable) { 165 | log.write(); 166 | log.write('*******************************************************************************'); 167 | log.write('A new version of pwabuilder is available (v' + updateAvailable + ').'); 168 | log.write('We recommend that you upgrade.'); 169 | log.write('*******************************************************************************'); 170 | log.write(); 171 | } 172 | 173 | var command; 174 | if (program.run) { 175 | command = commands.run(program); 176 | } 177 | else if (program.open) { 178 | command = commands.open(program); 179 | } 180 | else if (program.visualstudio) { 181 | command = commands.visualstudio(program); 182 | } 183 | else if (program.package) { 184 | command = commands.package(program); 185 | } 186 | else if (program.platform) { 187 | command = commands.platform(program); 188 | } 189 | else { 190 | command = commands.generate(program); 191 | } 192 | 193 | command.catch(function (err) { 194 | var errmsg = err.getMessage(); 195 | if (log.getLevel() !== log.levels.DEBUG) { 196 | errmsg += '\nFor more information, run pwabuilder with the diagnostics level set to debug (e.g. pwabuilder [...] -l debug)'; 197 | } 198 | 199 | log.error(errmsg); 200 | }); 201 | }); 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATION NOTICE 2 | 3 | This CLI for PWABuilder is no longer maintained. Please use [PWABuilder.com](https://www.pwabuilder.com) instead. If you need to open an issue for PWABuilder-related things, please do so at https://github.com/pwa-builder/PWABuilder/issues 4 | 5 | # PWA Builder CLI 6 | 7 | This tool is used to create hosted web applications based on a [W3C Web App manifest](http://www.w3.org/TR/appmanifest/). 8 | 9 | ## Installation 10 | 11 | ```` 12 | npm install -g pwabuilder 13 | ```` 14 | 15 | ## Documentation 16 | To get started, visit our [wiki](https://github.com/manifoldjs/manifoldJS/wiki). 17 | 18 | ## Command Line Interface 19 | 20 | ### Usage 21 | 22 | ```` 23 | pwabuilder [options] 24 | ```` 25 | -or- 26 | 27 | ```` 28 | pwabuilder [options] 29 | ```` 30 | 31 | ### Options 32 | 33 | | **      Option      ** | **Description** | 34 | | ----------------- | --------------- | 35 | | `website-url` | URL of the hosted website. This parameter is not required if a manifest location is specified with the *-m* option | 36 | | `-d, --directory` | **(optional)** Path to the generated project files (default value: current directory) | 37 | | `-s, --shortname` | **(optional)** Application short name. When specified, it overrides the short_name value of the manifest | 38 | | `-l, --loglevel` | **(optional)** Tracing log level options. Available log levels: _debug,info,warn,error_ (default value: _warn_) | 39 | | `-p, --platforms` | **(optional)** Platforms to generate. Supported platforms: _windows,windows10,android,ios,web_ (default value: all platforms) | 40 | | `-m, --manifest` | **(optional)** Location of the W3C Web App manifest file (URL or local path). If not specified, the tool looks for a manifest in the site URL. Otherwise, a new manifest will be created pointing to the site URL. | 41 | | `-i, --image` | **(optional)** Local path to the image file used to generate missing icons in the manifest | 42 | | `-f, --forceManifestFormat` | **(optional)** Allows to specify the manifest format and skip the automatic detection. Can be used when the manifest contains additional, non-standard members. | 43 | | `-c, --crosswalk` | **(optional)** Enable Crosswalk for Android. Crosswalk is a web runtime that can be used to replace the stock WebView used by Android Cordova apps. Crosswalk is based on Google Chromium with Cordova API support and has better HTML5 feature support compared to the default WebView available in Android. | 44 | | `-w, --webAppToolkit` | **(optional)** Adds the [Web App Toolkit](https://github.com/manifoldjs/Web-App-ToolKit) cordova plugin. The Web App Toolkit is a plugin for creating Windows, Android and iOS apps based on existing web content. It depends on the Hosted Web App Plugin. Used in the right way, it can facilitate the creation of compelling extensions to your web content for users across platforms. | 45 | | `-S, --Sign` | **(deprecated --optional - for _package_ command)** Return a signed package for Windows 10. | 46 | | `-W, --DotWeb` | **(deprecated --optional - for _package_ command)** Generate a .web package for Windows 10. | 47 | | `-a, --AutoPublish` | **(deprecated --optional - for _package_ command)** Auto-publish a package for Windows 10. | 48 | 49 | ### Commands 50 | 51 | | **            Command          ** | **Description** | 52 | | ------------------------- | --------------- | 53 | | `package [directory] [options]` | Creates a package for supported platforms (_windows10_, _android_, _iOS_) for uploading to the Store. In some cases, like Windows 10, data must be pulled from the store and updated in the manifest before it can be uploaded. __directory__ is the root path where to look for the target platforms (defaults to the current location). **options:** _-l \| --loglevel, -p \| --platforms, -S \| --Sign, -W \| --DotWeb, -a \| --AutoPublish_ | 54 | | `platform add [options]` | Adds a new platform. **platform-id** is the platform to be added. **source** could be either npm package, a GitHub reporitory or a local path to the platform source code. **options:** _-l \| --loglevel_ | 55 | | `platform remove [options]` | Removes an existing platform. **platform-id** is the platform to be removed. **options:** _-l \| --loglevel_ | 56 | | `platform list [options]` | List the existing platforms. **options:** _-l \| --loglevel_ | 57 | | `run [directory] [options]` | Launches the app of the specified platform. Currently, _android_, _ios_, _windows_ and _windows10_ platforms are supported by this command. __directory__ is the root path where to look for the target platforms (defaults to the current location). **options:** _-l \| --loglevel_ | 58 | | `open [directory] [options]` | (for Windows only) Opens the project file of the generated Windows 8.1 / Windows 10 app in Visual Studio. __directory__ is the root path where to look for the target platforms (defaults to the current location). **options:** _-l \| --loglevel_ | 59 | 60 | ### Example 61 | **Creating a new hosted web application** 62 | ```` 63 | pwabuilder http://shiftr.azurewebsites.net -d C:\Projects -l info -p windows10,android 64 | ```` 65 | **Packaging a Windows 10 app for submission to the Store** 66 | ```` 67 | pwabuilder package -p windows10 -l debug 68 | ```` 69 | 70 | ## Client Library 71 | 72 | ### Manifest Module 73 | 74 | ```` 75 | var manifestTools = require('manifestTools'); 76 | ```` 77 | 78 | #### getManifestFromSite(siteUrl, callback) 79 | 80 | Retrieves a manifest from a website. It looks for a manifest meta tag in the HTML content of the specified website URL; if no manifest is found, a new W3C manifest is retrieved with default `start_name` and `short_name` values. 81 | 82 | `siteUrl` is the URL of the website that hosts the manifest. 83 | 84 | `callback(err, manifestInfo)` returns an error or the manifest object in `manifestInfo`. 85 | 86 | #### getManifestFromFile(filePath, callback) 87 | 88 | Retrieves a manifest from a local path. 89 | 90 | `siteUrl` is the path there the manifest file is located. 91 | 92 | `callback(err, manifestInfo)` returns an error or the manifest object in `manifestInfo`. 93 | 94 | 95 | #### writeToFile(manifestInfo, filePath, callback) 96 | 97 | Writes manifest info to the specified path. 98 | `manifestInfo` Manifest data in JSON format. 99 | 100 | `filePath` The path to write to. 101 | 102 | `callback(err, validationResults)` returns an error or an array of validation results. 103 | 104 | #### fetchManifestUrlFromSite(siteUrl, callback) 105 | If found, gets the manifest URL from the specified website URL. 106 | 107 | `siteUrl` is the URL of the website. 108 | 109 | `callback(err, content)` returns an error or a content object with start_url and short_name members. 110 | 111 | #### downloadManifestFromUrl(manifestUrl, callback) 112 | Downloads the manifest from the specified URL. 113 | 114 | `manifestUrl` is the URL of the manifest. 115 | 116 | `callback(err, manifestInfo)` returns an error or the manifest object in `manifestInfo`. 117 | 118 | #### validateAndNormalizeStartUrl(siteUrl, manifestInfo, callback) 119 | Validates the format of the manifest is a W3C manifest format. 120 | 121 | `siteUrl` is the URL of the website. 122 | 123 | `manifestInfo` is the manifest's data in JSON format. 124 | 125 | `callback` returns an error or the manifest object in `manifestInfo`. 126 | 127 | #### convertTo(manifestInfo, outputFormat, callback) 128 | Converts the manifest data to the specified output format. 129 | 130 | `manifestInfo` is the manifest's data in JSON format. 131 | 132 | `outputformat` is the format to which the manifest will be converted. 133 | 134 | `callback(err, manifestInfo)` returns an error or the manifest object in `manifestInfo`. 135 | 136 | #### validateManifest(manifestInfo, targetPlatforms, callback) 137 | Makes sure the manifest is valid for the specified target platforms. 138 | 139 | `manifestInfo` is the manifest's data in JSON format. 140 | 141 | `targetPlatforms` are the platforms to validate against. 142 | 143 | `callback(err, validationResults)` returns an error or an array of validation results. 144 | 145 | #### manifestInfo format 146 | 147 | `manifestInfo.content` stores the manifest content. 148 | 149 | `manifestInfo.format` specifies the type of manifest (possible values: `W3C`, `undefined`). 150 | 151 | --- 152 | 153 | ### Builder Module 154 | ```` 155 | var projectBuilder = require('projectBuilder'); 156 | ```` 157 | #### createApps(w3cManifestInfo, rootDir, platforms, options, callback) 158 | Generates the applications for the specified platforms. 159 | 160 | `w3cManifestInfo` is the manifest's data in JSON format. 161 | 162 | `rootDir` is the root directory where the apps will be generated. 163 | 164 | `platforms` a string array specifying one or more target platforms: _windows10,windows,android,ios,web_. 165 | 166 | `options` an object with one or more properties that customize the generated application: 167 | 168 | - `crosswalk` (boolean) enable Crosswalk in the Cordova Android app 169 | - `webAppToolkit` (boolean) adds the Web App Toolkit cordova plugin 170 | 171 | `callback(err)` returns an error, if any. 172 | 173 | --- 174 | 175 | ### Project Tools module 176 | ```` 177 | var projectTools = require('projectTools'); 178 | ```` 179 | #### runApp(platform, callback) 180 | Execute the app for the chosen platform. 181 | 182 | `platform` The app will execute for the selected platform. 183 | 184 | `callback` returns an error, if any. 185 | 186 | #### openVisualStudio(callback) 187 | Opens the Visual Studio project. 188 | 189 | `callback` returns an error, if any. 190 | 191 | --- 192 | ## Unit Tests 193 | 194 | In the terminal, install the Grunt task runner: 195 | 196 | ```` 197 | npm install -g grunt-cli 198 | ```` 199 | 200 | In order to run tests and jshint, execute the following command: 201 | 202 | ```` 203 | grunt 204 | ```` 205 | 206 | ## Supported Input Manifests 207 | 208 | - [W3C Web App](http://www.w3.org/TR/appmanifest/) 209 | - [Chrome Hosted Apps](https://developer.chrome.com/apps/about_apps) 210 | 211 | We plan to support the following manifest files in the future: 212 | 213 | - [Web App Template](http://wat-docs.azurewebsites.net/JsonWindows) 214 | - [Firefox Open Web Apps](https://developer.mozilla.org/Apps/Build/Manifest) 215 | 216 | ## Navigation Scope 217 | 218 | The W3C manifest defines a scope that restricts the URLs to which the application can navigate. PWA Builder supports the scope setting for the Android, iOS and Windows platforms (more details [here](https://github.com/manifoldjs/ManifoldCordova#navigation-scope)). 219 | 220 | ## Changelog 221 | 222 | Releases are documented in [GitHub](https://github.com/manifoldjs/ManifoldJS/releases). 223 | 224 | ## Known Issues 225 | - Creating the directory shortcuts to the Cordova platform-specific projects may fail when running in the Windows environment. The tool reports **_"WARNING: Failed to create shortcut for Cordova platform: XXXX."__** where **_XXXX_** is **_ios_**, **_windows_**, or **_android_**. 226 | This is caused by an issue in Node.js which has been fixed in more recent releases. To resolve this issue, upgrade Node.js to the latest version. 227 | 228 | - Adding the **windows** platform in the Linux and Mac OS environments fails. The tool reports **_"WARNING: Failed to add the Cordova platforms: XXXX."_** where **_XXXX_** includes **_windows_**. 229 | This is caused by an issue in the Windows platform for Cordova. Depending on the cordova-windows version, running the tool can show one of two errors: **"_Cannot find module 'Q'."_** or **"_No such file or directory."_**. Until this problem is fixed by Cordova, we've removed the windows platform from the default list when creating the app in Linux or Mac OS. 230 | 231 | - Error when building an iOS application for projects generated in a Windows machine and then copied to an OS X machine. Xcode reports "**_Shell Script Invocation Error - Command /bin/sh failed with exit code 126_**". This happens when the execution permission (+x) is lost on some scripts when copying between the different file systems. 232 | 233 | To resolve this, open a Terminal window in OS X and execute the following command to restore the executable bit on the script. 234 | ``` 235 | chmod +x [path to the PWA Builder project]/cordova/platforms/ios/cordova/lib/copy-www-build-step.sh 236 | ``` 237 | 238 | - Issues in Visual Studio 2015 RC with the Windows solution generated by Cordova: 239 | - Opening the **CordovaApp.sln** solution file might hang Visual Studio while loading the Windows 8 project. As a workaround, remove the Windows 8 project file from the solution. 240 | - When building the solution, Visual Studio reports the following error in the Windows 10 project: **_"'ValidateAppxManifest' failed. Unspecified error"_**. As a workaround, clean and rebuild the solution. 241 | 242 | ## License 243 | 244 | > PWA Builder 245 | 246 | > Copyright (c) Microsoft Corporation 247 | 248 | > All rights reserved. 249 | 250 | > MIT License 251 | 252 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 253 | 254 | > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 255 | 256 | > THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257 | --------------------------------------------------------------------------------