├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .husky
└── pre-commit
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── certificates
├── favicon.png
├── index.css
├── index.html
└── index.js
├── certs.md
├── ionic-start
├── .gitignore
├── README.md
├── angular.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.ts
│ │ └── utilities
│ │ │ ├── dom.ts
│ │ │ ├── messages.ts
│ │ │ ├── template.ts
│ │ │ └── vscode.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── android.svg
│ │ ├── apple.svg
│ │ ├── blank.svg
│ │ ├── capacitor.svg
│ │ ├── chevron-down.svg
│ │ ├── ionic.svg
│ │ ├── list.svg
│ │ ├── logo-angular.svg
│ │ ├── logo-capacitor.svg
│ │ ├── logo-react.svg
│ │ ├── logo-vue.svg
│ │ ├── my-first-app.svg
│ │ ├── sidemenu.svg
│ │ ├── star-outline.svg
│ │ ├── star.svg
│ │ ├── tabs.svg
│ │ └── web.svg
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.css
│ └── tests.ts
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json
├── log-client
└── index.html
├── media
├── ionic.png
└── ionic.svg
├── package-lock.json
├── package.json
├── plugin-explorer
├── .gitignore
├── README.md
├── angular.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.ts
│ │ ├── plugin-info.ts
│ │ ├── plugin.component.css
│ │ ├── plugin.component.ts
│ │ ├── plugin.service.ts
│ │ ├── star.component.ts
│ │ └── utilities
│ │ │ ├── dom.ts
│ │ │ ├── messages.ts
│ │ │ └── vscode.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── android.svg
│ │ ├── apple.svg
│ │ ├── capacitor.svg
│ │ ├── chevron-down.svg
│ │ ├── cordova.svg
│ │ ├── star-outline.svg
│ │ └── star.svg
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.css
│ └── tests.ts
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json
├── resources
├── dark
│ ├── add.svg
│ ├── android.svg
│ ├── angular.svg
│ ├── apple.svg
│ ├── beaker.svg
│ ├── box.svg
│ ├── build-anim.svg
│ ├── build.svg
│ ├── capacitor.svg
│ ├── checkbox.svg
│ ├── checkmark.svg
│ ├── circle-filled.svg
│ ├── comment.svg
│ ├── cordova.svg
│ ├── debug-alt-small-anim.svg
│ ├── debug-alt-small.svg
│ ├── debug.svg
│ ├── dependency.svg
│ ├── edit.svg
│ ├── error.svg
│ ├── file-media.svg
│ ├── files.svg
│ ├── globe-select.svg
│ ├── globe.svg
│ ├── info.svg
│ ├── ionic.svg
│ ├── lightbulb.svg
│ ├── live-select.svg
│ ├── live.svg
│ ├── more.svg
│ ├── nexus-select.svg
│ ├── nexus.svg
│ ├── react.svg
│ ├── refresh.svg
│ ├── run-anim.svg
│ ├── run.svg
│ ├── settings-gear.svg
│ ├── sync-anim.svg
│ ├── sync.svg
│ ├── vscode-select.svg
│ ├── vscode.svg
│ ├── vue.svg
│ └── warning.svg
├── light
│ ├── add.svg
│ ├── android.svg
│ ├── angular.svg
│ ├── apple.svg
│ ├── beaker.svg
│ ├── box.svg
│ ├── build-anim.svg
│ ├── build.svg
│ ├── capacitor.svg
│ ├── checkbox.svg
│ ├── checkmark.svg
│ ├── circle-filled.svg
│ ├── comment.svg
│ ├── cordova.svg
│ ├── debug-alt-small-anim.svg
│ ├── debug-alt-small.svg
│ ├── debug.svg
│ ├── dependency.svg
│ ├── edit.svg
│ ├── error.svg
│ ├── file-media.svg
│ ├── files.svg
│ ├── globe-select.svg
│ ├── globe.svg
│ ├── info.svg
│ ├── ionic.svg
│ ├── lightbulb.svg
│ ├── more.svg
│ ├── nexus-select.svg
│ ├── nexus.svg
│ ├── react.svg
│ ├── refresh.svg
│ ├── run-anim.svg
│ ├── run.svg
│ ├── settings-gear.svg
│ ├── sync-anim.svg
│ ├── sync.svg
│ ├── vscode-select.svg
│ ├── vscode.svg
│ ├── vue.svg
│ └── warning.svg
├── log-language.xml
└── qrious.min.js
├── roadmap.md
├── src
├── advanced-actions.ts
├── analyze-size.ts
├── analyzer.ts
├── android-debug-bridge.ts
├── android-debug-list.ts
├── android-debug-models.ts
├── android-debug-provider.ts
├── android-debug.ts
├── angular-generate.ts
├── audit.ts
├── build-configuration.ts
├── cap-project.ts
├── capacitor-add.ts
├── capacitor-build.ts
├── capacitor-config-file.ts
├── capacitor-configure.ts
├── capacitor-device.ts
├── capacitor-migrate.ts
├── capacitor-open.ts
├── capacitor-platform.ts
├── capacitor-pwa.ts
├── capacitor-run.ts
├── capacitor-sync.ts
├── command-name.ts
├── command-title.ts
├── context-variables.ts
├── discovery.ts
├── editor-preview.ts
├── error-handler.ts
├── extension.ts
├── features.ts
├── gradle-to-json.ts
├── ignore.ts
├── imports-angular.ts
├── imports-auto-fix.ts
├── imports-icons.ts
├── ionic-auth.ts
├── ionic-build.ts
├── ionic-devserver-provider.ts
├── ionic-export.ts
├── ionic-init.ts
├── ionic-projects-provider.ts
├── ionic-serve.ts
├── ionic-start-templates.ts
├── ionic-start.ts
├── ionic-tree-provider.ts
├── live-reload.ts
├── log-server-scripts.ts
├── log-server.ts
├── log-settings.ts
├── logging.ts
├── messages.ts
├── monorepo.ts
├── monorepos-lerna.ts
├── monorepos-npm.ts
├── monorepos-nx.ts
├── monorepos-pnpm.ts
├── nexus-browser.ts
├── node-commands.ts
├── npm-info-data.ts
├── npm-info.ts
├── npm-model.ts
├── package-info.ts
├── package-lock.ts
├── peer-dependencies.ts
├── peer-dependency-cleanup.ts
├── plugin-explorer.ts
├── plugin-summary.ts
├── prettier.ts
├── privacy-manifest.ts
├── process-list.ts
├── process-packages.ts
├── project.ts
├── quick-fix.ts
├── recommend.ts
├── recommendation.ts
├── rules-angular-json.ts
├── rules-angular-migrate.ts
├── rules-angular-toolkit.ts
├── rules-browserslist.ts
├── rules-capacitor-migration.ts
├── rules-capacitor-plugins.ts
├── rules-capacitor.ts
├── rules-cordova.ts
├── rules-deprecated-plugins.ts
├── rules-ionic-native.ts
├── rules-package-upgrade.ts
├── rules-packages.ts
├── rules-web-project.ts
├── scripts.ts
├── source-map-server.ts
├── splash-icon.ts
├── strip-json-comments.ts
├── tasks.ts
├── telemetry.ts
├── tip.ts
├── update-minor.ts
├── utilities.ts
├── web-configuration.ts
├── web-debug.ts
├── workspace-state.ts
└── xcode.ts
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | vscode.proposed.d.ts
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /**@type {import('eslint').Linter.Config} */
2 | // eslint-disable-next-line no-undef
3 | module.exports = {
4 | root: true,
5 | parser: '@typescript-eslint/parser',
6 | plugins: [
7 | '@typescript-eslint',
8 | ],
9 | extends: [
10 | 'eslint:recommended',
11 | 'plugin:@typescript-eslint/recommended',
12 | ],
13 | rules: {
14 | 'semi': [2, "always"],
15 | '@typescript-eslint/no-unused-vars': 0,
16 | '@typescript-eslint/no-explicit-any': 0,
17 | '@typescript-eslint/explicit-module-boundary-types': 0,
18 | '@typescript-eslint/no-non-null-assertion': 0,
19 | '@typescript-eslint/no-namespace': 0,
20 | 'no-inner-declarations': 0,
21 | }
22 | };
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3 |
4 | name: Build Ionic VS Code Extension
5 |
6 | on:
7 | push:
8 | branches: ['main']
9 | pull_request:
10 | branches: ['main']
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Setup
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: 22.x
23 |
24 | - name: Install dependencies
25 | run: |
26 | npm install
27 | cd plugin-explorer
28 | npm install
29 | cd ../ionic-start
30 | npm install
31 | npm install -g @vscode/vsce
32 |
33 | - name: Lint
34 | run: |
35 | npm run lint
36 |
37 | - name: Build
38 | run: |
39 | npm run build
40 |
41 | - name: Upload release bundle
42 | uses: actions/upload-artifact@v4
43 | with:
44 | name: ionic.vsix
45 | path: ./ionic-*.vsix
46 | retention-days: 60
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | yarn.lock
4 | .DS_Store
5 | npm-debug.log
6 | Thumbs.db
7 | .vs/
8 | *.vsix
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx pretty-quick --staged
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "dbaeumer.vscode-eslint"
8 | ]
9 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Run Extension",
6 | "type": "extensionHost",
7 | "request": "launch",
8 | "runtimeExecutable": "${execPath}",
9 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
10 | "outFiles": ["${workspaceFolder}/out/**/*.js"],
11 | "preLaunchTask": "npm: watch"
12 | },
13 | {
14 | "name": "Run Extension Tests",
15 | "type": "extensionHost",
16 | "request": "launch",
17 | "runtimeExecutable": "${execPath}",
18 | "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test"],
19 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
20 | "preLaunchTask": "npm: watch"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false, // set this to true to hide the "out" folder with the compiled JS files
5 | "plugin-explorer": false,
6 | "ionic-start": false
7 | },
8 | "search.exclude": {
9 | "out": true // set this to false to include "out" folder in search results
10 | },
11 | "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
12 | "typescript.tsc.autoDetect": "off",
13 | "editor.insertSpaces": false
14 | }
15 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | roadmap.md
2 | site/videos/**
3 | site/**
4 | **/*.vsix
5 | plugin-explorer/.angular
6 | plugin-explorer/node_modules
7 | plugin-explorer/src
8 | plugin-explorer/*.json
9 | plugin-explorer/*.js
10 | plugin-explorer/*.md
11 | ionic-start/**
12 | !ionic-start/build/**
13 | plugin-explorer/*.json
14 | plugin-explorer/*.js
15 | plugin-explorer/*.md
16 | node_modules/typescript
17 | node_modules/chevotrain
18 | node_modules/handlebars
19 | node_modules/esbuild
20 | node_modules/esbuild-darwin-64
21 | node_modules/eslint
22 | node_modules/rollup
23 | node_modules/@typescript-eslint
24 | node_modules/@types
25 | node_modules/**/*.md
26 | node_modules/**/*.txt
27 | node_modules/**/*.html
28 | node_modules/conventional-changelog
29 | node_modules/.bin
30 | node_modules/native-run
31 | node_modules/**/LICENSE
32 | log-client/node_modules
33 | log-client/*.ts
34 | log-client/*.map
35 | .husky
36 | **/*.ts
37 | **/*.jar
38 | !node_modules/@trapezedev/**/*.jar
39 | **/*.map
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | Optionally install Volta: https://docs.volta.sh/guide/getting-started
4 |
5 | Ensure Visual Studio Extension Manager:
6 |
7 | - `npm install -g @vscode/vsce`
8 |
9 | For this project install dependencies:
10 |
11 | - `npm install`
12 |
13 | # Debugging
14 |
15 | - Press F5 in VSCode to start debugging the extension. It will open a VS Code window with the extension installed.
16 |
17 | # Testing the build
18 |
19 | To create a test build of the extension (ie create a `.vsix` file):
20 |
21 | - `npm run build`
22 | - Install the built `.vsix` file in VS Code
23 |
24 | # Building the plugin manager
25 |
26 | The Plugin Manager is an Angular application that works with the VS Code extension to search for and display plugins. You can build it
27 | by opening this project with the VS Code extension and clicking `Scripts` > `build`. Alternatively, you can `cd plugin-explorer`, `npm install`, and `npm run build`. This will compile the app to the right folder, and when you run the VS Code extension it will display
28 | it when visiting packages.
29 |
30 | # Publishing
31 |
32 | Make sure Visual Studio Extension Manager is installed (`npm install -g vsce`).
33 |
34 | Run
35 |
36 | - `vsce package`
37 | - A packaged with name `Ionic-0.0.1.vsix` will be created which can be installed or published to the marketplace.
38 |
39 | You can upload to the marketplace with `vsce publish` or you can manually upload the .vsix file [here](https://marketplace.visualstudio.com/manage/publishers/ionic).
40 |
41 | # Publish Prerelease
42 |
43 | You need a personal access token (see [here](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token)).
44 |
45 | Run
46 |
47 | - `vsce login Ionic` (make sure the I is capitalized)
48 | - `vsce publish --pre-release`
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2022-present Drifty Co.
2 | https://ionic.io
3 |
4 | MIT License
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining
7 | a copy of this software and associated documentation files (the
8 | "Software"), to deal in the Software without restriction, including
9 | without limitation the rights to use, copy, modify, merge, publish,
10 | distribute, sublicense, and/or sell copies of the Software, and to
11 | permit persons to whom the Software is furnished to do so, subject to
12 | the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/certificates/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/certificates/favicon.png
--------------------------------------------------------------------------------
/certificates/index.css:
--------------------------------------------------------------------------------
1 | ion-card {
2 | margin-left: auto;
3 | margin-right: auto;
4 | max-width: 600px;
5 | margin-bottom: 30px;
6 | margin-top: 30px;
7 | }
8 |
9 | i {
10 | font-family: 'Courier New', Courier, monospace;
11 | font-weight: bold;
12 | font-style: normal;
13 | }
14 |
15 | ion-content {
16 | --background: #eee;
17 | }
18 |
--------------------------------------------------------------------------------
/certificates/index.js:
--------------------------------------------------------------------------------
1 | setTimeout(() => {
2 | document.getElementById('url').innerText = document.location.href;
3 | document.getElementById('mac').hidden = !isMac() || isAndroid();
4 | document.getElementById('other').hidden = !(isMac() || isWindows()) || isAndroid();
5 | document.getElementById('ios').hidden = !isIOS();
6 | document.getElementById('android').hidden = !isAndroid();
7 | }, 30);
8 |
9 | function isMac() {
10 | return navigator.platform.toUpperCase().indexOf('MAC') >= 0 && !isTouch();
11 | }
12 |
13 | function isAndroid() {
14 | return navigator.userAgent.toLowerCase().indexOf('android') > -1;
15 | }
16 |
17 | function isWindows() {
18 | return navigator.platform.indexOf('Win') > -1;
19 | }
20 | function isIOS() {
21 | return (
22 | ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) ||
23 | // iPad on iOS 13 detection
24 | isTouch()
25 | );
26 | }
27 |
28 | function isTouch() {
29 | return navigator.userAgent.includes('Mac') && 'ontouchend' in document;
30 | }
31 |
--------------------------------------------------------------------------------
/certs.md:
--------------------------------------------------------------------------------
1 | # Live Reload
2 |
3 | To aid with rapid development the Live Reload feature will allow your browser or mobile device to use your development web server instead of static files on your device. Whenever you change a file in your editor the device will reload your app and display your changes.
4 |
5 | In the VS Code extension you can choose `Settings` > `Live Reload` and then run on Web or mobile device to use the Live Reload feature.
6 |
7 | Live Reload will use http (not https) and this may affect your application particularly if it uses APIs that require a secure context (such as geolocation, crypto).
8 |
9 | ## Live Reload with SSL
10 |
11 | If your app uses APIs that require a secure context (like web crypto) then it must be served using https. The device will also need to trust the connection which means that if you use a self signed certificate it will need to be installed and trusted on the device.
12 |
13 | The VS Code extension can help create a self signed certificate and trust it on devices. Choose `Settings` > `Use HTTPS`. When you check the box `Use HTTPS` it will generate a self signed certificate on your computer and will display a page with instructions on how to download, install and trust the certificate.
14 |
15 | After downloading, installing and trusting the certificate on the device you want to test your application you can then run the app and it will be served by your local development server.
16 |
17 | ## Troubleshooting
18 |
19 | ### http is always used
20 |
21 | Your local development server needs to use https and the created certificate and private key. Angular projects are understand and handled by the VS Code extension. React and Vue projects are not and need manual configuration.
22 |
23 | ### White Page on Startup
24 |
25 | The certificate is not installed and trusted. To do this go to `Settings` > `Use HTTPS` (you may need to uncheck and recheck the option). A web page will display with instructions on installing and trusting the certificate.
26 |
27 | You can visit this page on the mobile device to download the certificate and install it.
28 |
29 | ## Known Issues
30 |
31 | ### Android SSL Support
32 |
33 | > Android devices will not trust a certificate when run in the app (causing a white screen) even when the certificate is installed correctly and displays the web app in Chrome.
34 |
35 | You can get around this issue by installing the SSL skip plugin: `npm install @jcesarmobile/ssl-skip`.
36 |
37 | ### Windows SSL Support
38 |
39 | > Windows is not supported or tested (yet).
40 |
--------------------------------------------------------------------------------
/ionic-start/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /build
6 | /tmp
7 | /out-tsc
8 | /bazel-out
9 |
10 | # Node
11 | /node_modules
12 | npm-debug.log
13 | yarn-error.log
14 |
15 | # IDEs and editors
16 | .idea/
17 | .project
18 | .classpath
19 | .c9/
20 | *.launch
21 | .settings/
22 | .angular/
23 | *.sublime-workspace
24 |
25 | # Visual Studio Code
26 | .vscode/*
27 | !.vscode/settings.json
28 | !.vscode/tasks.json
29 | !.vscode/launch.json
30 | !.vscode/extensions.json
31 | .history/*
32 |
33 | # Miscellaneous
34 | /.angular/cache
35 | .sass-cache/
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | testem.log
40 | /typings
41 |
42 | # System files
43 | .DS_Store
44 | Thumbs.db
45 |
--------------------------------------------------------------------------------
/ionic-start/README.md:
--------------------------------------------------------------------------------
1 | # Ionic Start
2 |
3 | This directory contains an Angular app that lets you create a new project.
4 | It uses the [VSCode toolkit](https://github.com/microsoft/vscode-webview-ui-toolkit). Samples are [here](https://github.com/microsoft/vscode-webview-ui-toolkit-samples)
5 |
--------------------------------------------------------------------------------
/ionic-start/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage'),
13 | require('@angular-devkit/build-angular/plugins/karma'),
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true, // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, './coverage/my-app'),
29 | subdir: '.',
30 | reporters: [{ type: 'html' }, { type: 'text-summary' }],
31 | },
32 | reporters: ['progress', 'kjhtml'],
33 | port: 9876,
34 | colors: true,
35 | logLevel: config.LOG_INFO,
36 | autoWatch: true,
37 | browsers: ['Chrome'],
38 | singleRun: false,
39 | restartOnFileChange: true,
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/ionic-start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-start",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "build": "ng build --output-hashing=none --configuration production",
9 | "watch": "ng build --watch --configuration development",
10 | "test": "ng test"
11 | },
12 | "dependencies": {
13 | "@angular/animations": "^19.0.1",
14 | "@angular/common": "^19.0.1",
15 | "@angular/compiler": "^19.0.1",
16 | "@angular/core": "^19.0.1",
17 | "@angular/forms": "^19.0.1",
18 | "@angular/platform-browser": "^19.0.1",
19 | "@angular/platform-browser-dynamic": "^19.0.1",
20 | "@angular/router": "^19.0.1",
21 | "@vscode/webview-ui-toolkit": "1.4.0",
22 | "rxjs": "~7.5.0",
23 | "tslib": "2.6.0",
24 | "zone.js": "~0.15.0"
25 | },
26 | "devDependencies": {
27 | "@angular-devkit/build-angular": "^19.0.2",
28 | "@angular/cli": "^19.0.2",
29 | "@angular/compiler-cli": "^19.0.1",
30 | "@types/jasmine": "4.3.5",
31 | "@types/node": "18.15.11",
32 | "@types/vscode-webview": "1.57.5",
33 | "jasmine-core": "5.3.0",
34 | "karma": "6.4.4",
35 | "karma-chrome-launcher": "3.2.0",
36 | "karma-coverage": "2.2.1",
37 | "karma-jasmine": "5.1.0",
38 | "karma-jasmine-html-reporter": "2.1.0",
39 | "typescript": "5.5.4"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ionic-start/src/app/utilities/dom.ts:
--------------------------------------------------------------------------------
1 | export function getValue(id: string): string {
2 | return document.getElementById(id)?.getAttribute('current-value') as string;
3 | }
4 |
5 | export function checked(id: string): boolean {
6 | const value = document.getElementById(id)?.getAttribute('current-checked');
7 | return value == 'true';
8 | }
9 |
10 | export function setChecked(id: string, checked: boolean): void {
11 | document.getElementById(id)?.setAttribute('current-checked', checked ? 'true' : 'false');
12 | }
13 |
--------------------------------------------------------------------------------
/ionic-start/src/app/utilities/messages.ts:
--------------------------------------------------------------------------------
1 | import { vscode } from './vscode';
2 |
3 | export enum MessageType {
4 | getTemplates = 'getTemplates',
5 | createProject = 'createProject',
6 | getProjectsFolder = 'getProjectsFolder',
7 | chooseFolder = 'chooseFolder',
8 | creatingProject = 'creatingProject',
9 | }
10 |
11 | export function sendMessage(command: MessageType, value: string) {
12 | vscode.postMessage({ command, text: value });
13 | }
14 |
--------------------------------------------------------------------------------
/ionic-start/src/app/utilities/template.ts:
--------------------------------------------------------------------------------
1 | export interface Template {
2 | type: string;
3 | typeName: string;
4 | title: string;
5 | name: string;
6 | description: string;
7 | appearance?: string;
8 | icon?: string;
9 | }
10 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/ionic-start/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ionic-start/src/assets/android.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/apple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/blank.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/capacitor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/chevron-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/ionic.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/list.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/logo-angular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/logo-capacitor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/logo-vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/my-first-app.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/sidemenu.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/star-outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/tabs.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/ionic-start/src/assets/web.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ionic-start/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/ionic-start/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/ionic-start/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/ionic-start/src/favicon.ico
--------------------------------------------------------------------------------
/ionic-start/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Plugin Explorer
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ionic-start/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { environment } from './environments/environment';
3 | import { bootstrapApplication } from '@angular/platform-browser';
4 | import { AppComponent } from './app/app.component';
5 | import {
6 | provideVSCodeDesignSystem,
7 | vsCodeButton,
8 | vsCodeCheckbox,
9 | vsCodeDivider,
10 | vsCodeLink,
11 | vsCodePanelView,
12 | vsCodeProgressRing,
13 | vsCodeRadio,
14 | vsCodeRadioGroup,
15 | vsCodeTag,
16 | vsCodeTextField,
17 | } from '@vscode/webview-ui-toolkit';
18 |
19 | if (environment.production) {
20 | enableProdMode();
21 | }
22 |
23 | // In order to use the Webview UI Toolkit web components they
24 | // must be registered with the browser (i.e. webview) using the
25 | // syntax below.
26 | provideVSCodeDesignSystem().register(
27 | vsCodeButton(),
28 | vsCodeTextField(),
29 | vsCodePanelView(),
30 | vsCodeLink(),
31 | vsCodeTag(),
32 | vsCodeCheckbox(),
33 | vsCodeDivider(),
34 | vsCodeRadio(),
35 | vsCodeRadioGroup(),
36 | vsCodeProgressRing(),
37 | );
38 |
39 | bootstrapApplication(AppComponent).catch((err) => console.error(err));
40 |
--------------------------------------------------------------------------------
/ionic-start/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including
12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | /***************************************************************************************************
46 | * Zone JS is required by default for Angular itself.
47 | */
48 | import 'zone.js'; // Included with Angular CLI.
49 |
50 | /***************************************************************************************************
51 | * APPLICATION IMPORTS
52 | */
53 |
--------------------------------------------------------------------------------
/ionic-start/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | main {
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: center;
6 | height: 100%;
7 | }
8 |
9 | h2,
10 | h3 {
11 | margin: 0;
12 | }
13 |
14 | main > * {
15 | margin: 0.5rem 0;
16 | }
17 |
18 | .columns {
19 | display: flex;
20 | width: 100%;
21 | }
22 |
23 | vscode-text-field {
24 | width: 100%;
25 | }
26 |
27 | .tooltip {
28 | position: relative;
29 | display: inline-block;
30 | border-bottom: 1px dotted var(--vscode-editor-background);
31 | }
32 |
33 | .tooltip .tooltiptext {
34 | visibility: hidden;
35 | width: 120px;
36 | background-color: var(--vscode-editor-background);
37 | color: var(--vscode-editor-foreground);
38 | text-align: center;
39 | border-radius: 6px;
40 | padding: 5px 0;
41 |
42 | /* Position the tooltip */
43 | position: absolute;
44 | z-index: 1;
45 | }
46 |
47 | .small-tooltip {
48 | font-size: smaller !important;
49 | width: 190px;
50 | }
51 |
52 | .ionicon {
53 | width: 16px;
54 | height: 16px;
55 | }
56 |
57 | .tooltip:hover .tooltiptext {
58 | visibility: visible;
59 | }
60 |
61 | p {
62 | line-height: 1.7;
63 | margin: 0;
64 | }
65 |
66 | /* For live editing */
67 | /* body {
68 | background-color: #2c2c2c;
69 | color: white;
70 | font-family:Arial, Helvetica, sans-serif;
71 | } */
72 |
--------------------------------------------------------------------------------
/ionic-start/src/tests.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
6 |
7 | declare const require: {
8 | context(
9 | path: string,
10 | deep?: boolean,
11 | filter?: RegExp,
12 | ): {
13 | (id: string): T;
14 | keys(): string[];
15 | };
16 | };
17 |
18 | // First, initialize the Angular testing environment.
19 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
20 |
21 | // Then we find all the tests.
22 | const context = require.context('./', true, /\.spec\.ts$/);
23 | // And load the modules.
24 | context.keys().map(context);
25 |
--------------------------------------------------------------------------------
/ionic-start/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": ["src/main.ts", "src/polyfills.ts"],
9 | "include": ["src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/ionic-start/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "declaration": false,
15 | "downlevelIteration": true,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "node",
18 | "importHelpers": true,
19 | "skipLibCheck": true,
20 | "target": "es2015",
21 | "module": "es2020",
22 | "lib": ["es2018", "dom"],
23 | },
24 | "angularCompilerOptions": {
25 | "enableI18nLegacyMessageIdFormat": false,
26 | "strictInjectionParameters": true,
27 | "strictInputAccessModifiers": true,
28 | "strictStandalone": true,
29 | "strictTemplates": true,
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/ionic-start/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": ["jasmine"]
7 | },
8 | "files": ["src/test.ts", "src/polyfills.ts"],
9 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/log-client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/media/ionic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/media/ionic.png
--------------------------------------------------------------------------------
/media/ionic.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/plugin-explorer/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /build
6 | /tmp
7 | /out-tsc
8 | /bazel-out
9 |
10 | # Node
11 | /node_modules
12 | npm-debug.log
13 | yarn-error.log
14 |
15 | # IDEs and editors
16 | .idea/
17 | .project
18 | .classpath
19 | .c9/
20 | *.launch
21 | .settings/
22 | .angular/
23 | *.sublime-workspace
24 |
25 | # Visual Studio Code
26 | .vscode/*
27 | !.vscode/settings.json
28 | !.vscode/tasks.json
29 | !.vscode/launch.json
30 | !.vscode/extensions.json
31 | .history/*
32 |
33 | # Miscellaneous
34 | /.angular/cache
35 | .sass-cache/
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | testem.log
40 | /typings
41 |
42 | # System files
43 | .DS_Store
44 | Thumbs.db
45 |
--------------------------------------------------------------------------------
/plugin-explorer/README.md:
--------------------------------------------------------------------------------
1 | # Plugin Explorer
2 |
3 | This directory contains an Angular app that lets you explore plugins and install them.
4 | It uses the [VSCode toolkit](https://github.com/microsoft/vscode-webview-ui-toolkit). Samples are [here](https://github.com/microsoft/vscode-webview-ui-toolkit-samples)
5 |
--------------------------------------------------------------------------------
/plugin-explorer/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage'),
13 | require('@angular-devkit/build-angular/plugins/karma'),
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true, // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, './coverage/my-app'),
29 | subdir: '.',
30 | reporters: [{ type: 'html' }, { type: 'text-summary' }],
31 | },
32 | reporters: ['progress', 'kjhtml'],
33 | port: 9876,
34 | colors: true,
35 | logLevel: config.LOG_INFO,
36 | autoWatch: true,
37 | browsers: ['Chrome'],
38 | singleRun: false,
39 | restartOnFileChange: true,
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/plugin-explorer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "plugin-explorer",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "build": "ng build --output-hashing=none --configuration production",
9 | "watch": "ng build --watch --configuration development",
10 | "test": "ng test"
11 | },
12 | "dependencies": {
13 | "@angular/animations": "^19.0.1",
14 | "@angular/common": "^19.0.1",
15 | "@angular/compiler": "^19.0.1",
16 | "@angular/core": "^19.0.1",
17 | "@angular/forms": "^19.0.1",
18 | "@angular/platform-browser": "^19.0.1",
19 | "@angular/platform-browser-dynamic": "^19.0.1",
20 | "@angular/router": "^19.0.1",
21 | "@vscode/webview-ui-toolkit": "1.4.0",
22 | "rxjs": "~7.5.0",
23 | "tslib": "2.5.2",
24 | "zone.js": "~0.15.0"
25 | },
26 | "devDependencies": {
27 | "@angular-devkit/build-angular": "^19.0.2",
28 | "@angular/cli": "^19.0.2",
29 | "@angular/compiler-cli": "^19.0.1",
30 | "@types/jasmine": "4.3.1",
31 | "@types/node": "18.15.11",
32 | "@types/vscode-webview": "1.57.5",
33 | "jasmine-core": "5.3.0",
34 | "karma": "6.4.4",
35 | "karma-chrome-launcher": "3.2.0",
36 | "karma-coverage": "2.2.0",
37 | "karma-jasmine": "5.1.0",
38 | "karma-jasmine-html-reporter": "~1.7.0",
39 | "typescript": "5.5.4"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | .panel {
2 | background-color: rgba(255, 255, 255, 0.02);
3 | margin-bottom: 1rem;
4 | margin-left: 0;
5 | margin-right: 0;
6 | padding: 1rem;
7 | }
8 |
9 | .progress {
10 | width: 100%;
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | }
15 |
16 | .two-col {
17 | display: flex;
18 | }
19 |
20 | .side {
21 | padding-left: 20px;
22 | min-width: 180px;
23 | }
24 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 | Search
13 |
14 |
15 | @if (busy) {
16 |
17 |
18 |
19 | }
20 |
21 |
{{ listTitle }}
22 | @for (plugin of plugins; track plugin) {
23 |
26 | }
27 |
28 | The most popular open source plugins are tested and indexed. Got a plugin that isnt here?
29 | Submit a suggestion
30 |
31 |
32 |
33 |
34 |
35 |
36 | iOS
37 | Android
38 | Both
39 | Any
40 |
41 |
42 |
Filters
43 |
Installed
46 |
Official Support
47 |
Capacitor Only
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/plugin-info.ts:
--------------------------------------------------------------------------------
1 | export interface Plugin {
2 | name: string;
3 | version: string;
4 | success: string[];
5 | repo?: string;
6 | keywords?: string[];
7 | fails: string[];
8 | description?: string;
9 | quality?: number;
10 | versions: string[];
11 | platforms: string[];
12 | author: any;
13 | bugs?: string;
14 | published: string;
15 | downloads?: number;
16 | stars?: number;
17 | image?: string;
18 | updated?: string;
19 | license: string;
20 | title: string; // Calculated
21 | rating: number; // Calculated
22 | ratingInfo: string; // Calculated
23 | tagInfo: string; // Calcuilated
24 | dailyDownloads: string; // Calculated
25 | changed: string; // Calculated
26 | installed: string; // Calculated: whether the plugin is installed in the current project
27 | framework: string | undefined; // Calculated: either capacitor or cordova
28 | moreInfoUrl: string; // Calculated
29 | singlePlatform: string | undefined; // Calculated: either android or apple
30 | }
31 |
32 | export interface PluginInfo {
33 | name: string;
34 | version: string;
35 | latest: string;
36 | }
37 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/plugin.component.css:
--------------------------------------------------------------------------------
1 | vscode-badge {
2 | margin: 0.2rem;
3 | padding: 0.2rem;
4 | border-radius: 0.1rem;
5 | opacity: 0.3;
6 | background: rgba(255, 255, 255, 0.1);
7 | line-height: 2;
8 | }
9 |
10 | vscode-button {
11 | margin-right: 0.5rem;
12 | }
13 |
14 | .subtitle {
15 | font-family: monospace, 'Courier New', Courier;
16 | opacity: 0.5;
17 | margin-top: 0.2rem;
18 | margin-bottom: 0;
19 | font-size: smaller;
20 | }
21 |
22 | .px-group {
23 | display: flex;
24 | flex-direction: row;
25 | justify-content: stretch;
26 | width: 100%;
27 | }
28 |
29 | .side {
30 | min-width: 160px;
31 | justify-content: flex-end;
32 | }
33 |
34 | .author {
35 | vertical-align: middle;
36 | width: 50px;
37 | height: 50px;
38 | object-fit: contain;
39 | border-radius: 50%;
40 | }
41 |
42 | .prof {
43 | min-width: 55px;
44 | height: 55px;
45 | margin-right: 1rem;
46 | display: flex;
47 | justify-content: center;
48 | }
49 |
50 | .panel2 {
51 | width: 100%;
52 | padding-right: 1rem;
53 | }
54 |
55 | .center-title {
56 | display: flex;
57 | align-items: center;
58 | gap: 8px;
59 | }
60 |
61 | .center-image {
62 | height: 100%;
63 | display: flex;
64 | align-items: center;
65 | }
66 |
67 | .wide-tip {
68 | width: 300px !important;
69 | top: 25px;
70 | line-height: 2;
71 | padding: 1rem;
72 | }
73 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/star.component.ts:
--------------------------------------------------------------------------------
1 | import { CUSTOM_ELEMENTS_SCHEMA, Component, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'star',
5 | imports: [],
6 | schemas: [CUSTOM_ELEMENTS_SCHEMA],
7 | template: `
8 | @for (x of _stars; track x) {
9 |
14 | }
15 | @for (x of _misses; track x) {
16 |
25 | }
26 |
27 | `,
28 | })
29 | export class StarComponent {
30 | _stars = [0, 1, 2];
31 | _misses = [3, 4, 5];
32 | @Input() set rating(value: number) {
33 | if (!value) {
34 | this._stars = [];
35 | this._misses = [].constructor(5);
36 | } else {
37 | this._stars = [].constructor(value);
38 | this._misses = [].constructor(5 - value);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/utilities/dom.ts:
--------------------------------------------------------------------------------
1 | export function d(id: string): string {
2 | return document.getElementById(id)?.getAttribute('current-value') as string;
3 | }
4 |
5 | export function checked(id: string): boolean {
6 | const value = document.getElementById(id)?.getAttribute('current-checked');
7 | return value == 'true';
8 | }
9 |
10 | export function setChecked(id: string, checked: boolean): void {
11 | document.getElementById(id)?.setAttribute('current-checked', checked ? 'true' : 'false');
12 | }
13 |
--------------------------------------------------------------------------------
/plugin-explorer/src/app/utilities/messages.ts:
--------------------------------------------------------------------------------
1 | import { vscode } from './vscode';
2 |
3 | export enum MessageType {
4 | getPlugins = 'getPlugins',
5 | getPlugin = 'getPlugin',
6 | getInstalledDeps = 'getInstalledDeps',
7 | chooseVersion = 'choose-version',
8 | }
9 |
10 | export function sendMessage(command: MessageType, value: string) {
11 | vscode.postMessage({ command, text: value });
12 | }
13 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/plugin-explorer/src/assets/.gitkeep
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/android.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/apple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/capacitor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/chevron-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/cordova.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/star-outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugin-explorer/src/assets/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugin-explorer/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/plugin-explorer/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/plugin-explorer/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ionic-team/vscode-ionic/058c9a0ab2d9ecaf3be051d1a6a94b7b19b76ae3/plugin-explorer/src/favicon.ico
--------------------------------------------------------------------------------
/plugin-explorer/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Plugin Explorer
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/plugin-explorer/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import {
3 | provideVSCodeDesignSystem,
4 | vsCodeButton,
5 | vsCodeCheckbox,
6 | vsCodeDivider,
7 | vsCodeLink,
8 | vsCodePanelView,
9 | vsCodeProgressRing,
10 | vsCodeRadio,
11 | vsCodeRadioGroup,
12 | vsCodeTag,
13 | vsCodeTextField,
14 | } from '@vscode/webview-ui-toolkit';
15 | import { environment } from './environments/environment';
16 | import { AppComponent } from './app/app.component';
17 | import { bootstrapApplication } from '@angular/platform-browser';
18 |
19 | if (environment.production) {
20 | enableProdMode();
21 | }
22 |
23 | // In order to use the Webview UI Toolkit web components they
24 | // must be registered with the browser (i.e. webview) using the
25 | // syntax below.
26 | provideVSCodeDesignSystem().register(
27 | vsCodeButton(),
28 | vsCodeTextField(),
29 | vsCodePanelView(),
30 | vsCodeLink(),
31 | vsCodeTag(),
32 | vsCodeCheckbox(),
33 | vsCodeDivider(),
34 | vsCodeRadio(),
35 | vsCodeRadioGroup(),
36 | vsCodeProgressRing(),
37 | );
38 |
39 | bootstrapApplication(AppComponent).catch((err) => console.error(err));
40 |
--------------------------------------------------------------------------------
/plugin-explorer/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including
12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | /***************************************************************************************************
46 | * Zone JS is required by default for Angular itself.
47 | */
48 | import 'zone.js'; // Included with Angular CLI.
49 |
50 | /***************************************************************************************************
51 | * APPLICATION IMPORTS
52 | */
53 |
--------------------------------------------------------------------------------
/plugin-explorer/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | main {
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: center;
6 | height: 100%;
7 | }
8 |
9 | h2,
10 | h3 {
11 | margin: 0;
12 | }
13 |
14 | main > * {
15 | margin: 0.5rem 0;
16 | }
17 |
18 | .columns {
19 | display: flex;
20 | width: 100%;
21 | }
22 |
23 | vscode-text-field {
24 | width: 100%;
25 | }
26 |
27 | .tooltip {
28 | position: relative;
29 | display: inline-block;
30 | border-bottom: 1px dotted var(--vscode-editor-background);
31 | }
32 |
33 | .tooltip .tooltiptext {
34 | visibility: hidden;
35 | width: 120px;
36 | background-color: var(--vscode-editor-background);
37 | color: var(--vscode-editor-foreground);
38 | text-align: center;
39 | border-radius: 6px;
40 | padding: 5px 0;
41 |
42 | /* Position the tooltip */
43 | position: absolute;
44 | z-index: 1;
45 | }
46 |
47 | .small-tooltip {
48 | font-size: smaller !important;
49 | width: 190px;
50 | }
51 |
52 | .ionicon {
53 | width: 16px;
54 | height: 16px;
55 | }
56 |
57 | .tooltip:hover .tooltiptext {
58 | visibility: visible;
59 | }
60 |
61 | p {
62 | line-height: 1.7;
63 | margin: 0;
64 | }
65 |
66 | /* For live editing */
67 | /* body {
68 | background-color: #2c2c2c;
69 | color: white;
70 | font-family:Arial, Helvetica, sans-serif;
71 | } */
72 |
--------------------------------------------------------------------------------
/plugin-explorer/src/tests.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
6 |
7 | declare const require: {
8 | context(
9 | path: string,
10 | deep?: boolean,
11 | filter?: RegExp,
12 | ): {
13 | (id: string): T;
14 | keys(): string[];
15 | };
16 | };
17 |
18 | // First, initialize the Angular testing environment.
19 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
20 |
21 | // Then we find all the tests.
22 | const context = require.context('./', true, /\.spec\.ts$/);
23 | // And load the modules.
24 | context.keys().map(context);
25 |
--------------------------------------------------------------------------------
/plugin-explorer/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": ["src/main.ts", "src/polyfills.ts"],
9 | "include": ["src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/plugin-explorer/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "declaration": false,
15 | "downlevelIteration": true,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "node",
18 | "importHelpers": true,
19 | "skipLibCheck": true,
20 | "target": "es2015",
21 | "module": "es2020",
22 | "lib": ["es2018", "dom"],
23 | },
24 | "angularCompilerOptions": {
25 | "enableI18nLegacyMessageIdFormat": false,
26 | "strictInjectionParameters": true,
27 | "strictInputAccessModifiers": true,
28 | "strictStandalone": true,
29 | "strictTemplates": true,
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/plugin-explorer/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": ["jasmine"]
7 | },
8 | "files": ["src/test.ts", "src/polyfills.ts"],
9 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/resources/dark/add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/android.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/angular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/apple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/beaker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/box.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/build-anim.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/resources/dark/build.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/resources/dark/capacitor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/checkbox.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/checkmark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/circle-filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/comment.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/cordova.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/debug-alt-small-anim.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/dark/debug-alt-small.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/resources/dark/debug.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/resources/dark/dependency.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/error.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/file-media.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/files.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/globe-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/globe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/info.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/ionic.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/dark/lightbulb.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/live-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/live.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/more.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/resources/dark/nexus-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/nexus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/run-anim.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/run.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/settings-gear.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/sync-anim.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/resources/dark/sync.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/dark/vscode-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/vscode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/warning.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/android.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/angular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/apple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/beaker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/box.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/build-anim.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/resources/light/build.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/resources/light/capacitor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/checkbox.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/checkmark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/circle-filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/comment.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/cordova.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/debug-alt-small-anim.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/light/debug-alt-small.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/resources/light/debug.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/light/dependency.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/error.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/file-media.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/files.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/globe-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/globe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/info.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/ionic.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/light/lightbulb.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/more.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/resources/light/nexus-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/nexus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/run-anim.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/run.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/resources/light/settings-gear.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/resources/light/sync-anim.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/resources/light/sync.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/resources/light/vscode-select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/vscode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/warning.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/android-debug-list.ts:
--------------------------------------------------------------------------------
1 | import { Command, TreeItemCollapsibleState } from 'vscode';
2 | import { debugAndroid } from './android-debug';
3 | import { findDevices, findWebViews } from './android-debug-bridge';
4 | import { Device, WebView } from './android-debug-models';
5 | import { CommandName } from './command-name';
6 | import { ionicState } from './ionic-tree-provider';
7 | import { Recommendation } from './recommendation';
8 | import { QueueFunction, Tip, TipType } from './tip';
9 |
10 | export async function getAndroidWebViewList(
11 | hasCapacitorAndroid: boolean,
12 | wwwFolder: string,
13 | ): Promise {
14 | if (ionicState.refreshDebugDevices) {
15 | ionicState.refreshDebugDevices = false;
16 | }
17 | if (!hasCapacitorAndroid) {
18 | return [];
19 | }
20 |
21 | const result: Array = [];
22 | const devices = await findDevices();
23 | for (const device of devices) {
24 | const webviews = await findWebViews(device!);
25 | for (const webview of webviews) {
26 | const r = new Recommendation(
27 | `Debug ${webview.packageName} ${webview.versionName} on running Android device ${device.product}`,
28 | `(${device.product})`,
29 | `${webview.packageName}`,
30 | TreeItemCollapsibleState.None,
31 | getCommand(),
32 | undefined,
33 | );
34 | r.setIcon('debug');
35 | r.tip = new Tip(undefined, undefined, TipType.Run).setQueuedAction(debug, device, webview, wwwFolder).doNotWait();
36 | r.command.arguments = [r];
37 | result.push(r);
38 | }
39 | if (webviews.length == 0) {
40 | const r = new Recommendation(
41 | 'test',
42 | 'No Web View',
43 | device.product,
44 | TreeItemCollapsibleState.None,
45 | getCommand(),
46 | undefined,
47 | );
48 | r.setIcon('android');
49 | result.push(r);
50 | }
51 | }
52 | return result;
53 | }
54 |
55 | async function debug(queueFunction: QueueFunction, device: Device, webview: WebView, wwwfolder: string): Promise {
56 | queueFunction();
57 | debugAndroid(webview.packageName, wwwfolder);
58 | return;
59 | }
60 |
61 | function getCommand(): Command {
62 | return {
63 | command: CommandName.Function,
64 | title: 'Open',
65 | };
66 | }
67 |
--------------------------------------------------------------------------------
/src/android-debug-models.ts:
--------------------------------------------------------------------------------
1 | export interface WebView {
2 | device: Device;
3 | socket: string;
4 | type: WebViewType;
5 | packageName?: string;
6 | versionName?: string;
7 | }
8 |
9 | export enum WebViewType {
10 | chrome = 'chrome',
11 | webview = 'webview',
12 | crosswalk = 'crosswalk',
13 | unknown = 'unknown',
14 | }
15 |
16 | export type DeviceState =
17 | | 'device'
18 | | 'connecting'
19 | | 'offline'
20 | | 'unknown'
21 | | 'bootloader'
22 | | 'recovery'
23 | | 'download'
24 | | 'unauthorized'
25 | | 'host'
26 | | 'no permissions';
27 |
28 | export interface Device {
29 | serial: string;
30 | state: DeviceState;
31 | usb?: string;
32 | product?: string;
33 | model?: string;
34 | device?: string;
35 | features?: string;
36 | transportId?: string;
37 | }
38 |
39 | export interface ForwardedSocket {
40 | local: string;
41 | remote: string;
42 | }
43 |
44 | export interface AdbOptions {
45 | executable: string;
46 | arguments: string[];
47 | }
48 |
49 | export interface ShellOptions extends AdbOptions {
50 | serial: string;
51 | command: string;
52 | }
53 |
54 | export interface ForwardOptions extends AdbOptions {
55 | serial: string;
56 | local: string;
57 | remote: string;
58 | }
59 |
60 | export interface UnforwardOptions extends AdbOptions {
61 | local: string;
62 | }
63 |
64 | export interface Process {
65 | pid: number;
66 | name: string;
67 | }
68 |
69 | export interface Package {
70 | packageName: string;
71 | versionName: string;
72 | }
73 |
74 | export interface WebViewPage {
75 | url: string;
76 | title: string;
77 | webSocketDebuggerUrl: string;
78 | }
79 |
--------------------------------------------------------------------------------
/src/android-debug.ts:
--------------------------------------------------------------------------------
1 | import { debug, workspace } from 'vscode';
2 | import { startSourceMapServer } from './source-map-server';
3 | import { debugSkipFiles } from './utilities';
4 | import { ionicState } from './ionic-tree-provider';
5 |
6 | // The debug provider type for VS Code
7 | export const AndroidDebugType = 'android-web';
8 |
9 | export function debugAndroid(packageName: string, wwwFolder: string) {
10 | // Source maps are required for debugging. These are loaded from where the app is
11 | // loaded (eg http://localhost) so we're running a source map server to deliver them
12 | // An alternative includes inlining the source maps.
13 |
14 | // Inlining source maps:
15 | // https://github.com/ionic-team/ionic-framework/issues/16455#issuecomment-505397373
16 |
17 | // Solution: https://ionic.zendesk.com/hc/en-us/articles/5177027959319
18 |
19 | // See this location for options for debugging that are supported
20 | // https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md#pwa-chrome-attach
21 |
22 | // Note: options here include sourceMapPathOverrides and resolveSourceMapLocations both dont fix the
23 | // problem with source maps not being accessible to the debugger
24 | ionicState.debugged = true;
25 | debug.startDebugging(workspace.workspaceFolders[0], {
26 | type: AndroidDebugType,
27 | name: 'Debug Android',
28 | request: 'attach',
29 | packageName: packageName,
30 | webRoot: '${workspaceFolder}',
31 | skipFiles: debugSkipFiles(),
32 | });
33 |
34 | startSourceMapServer(wwwFolder);
35 | }
36 |
--------------------------------------------------------------------------------
/src/angular-generate.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 |
3 | import { getRunOutput, getStringFrom, openUri, replaceAll } from './utilities';
4 | import { write, writeError, writeIonic } from './logging';
5 | import { join } from 'path';
6 | import { existsSync } from 'fs';
7 | import { isGreaterOrEqual } from './analyzer';
8 | import { window } from 'vscode';
9 | import { QueueFunction } from './tip';
10 | import { ionicState } from './ionic-tree-provider';
11 | import { npx } from './node-commands';
12 | import { checkAngularJson } from './rules-angular-json';
13 |
14 | export async function angularGenerate(
15 | queueFunction: QueueFunction,
16 | project: Project,
17 | angularType: string,
18 | ): Promise {
19 | let name = await window.showInputBox({
20 | title: `New Angular ${angularType}`,
21 | placeHolder: `Enter name for new ${angularType}`,
22 | });
23 |
24 | if (!name || name.length < 1) return;
25 | queueFunction();
26 |
27 | // CREATE src/app/test2/test2.component.ts
28 | try {
29 | let args = '';
30 | if (isGreaterOrEqual('@angular/core', '15.0.0')) {
31 | if (isGreaterOrEqual('@ionic/angular-toolkit', '8.1.0')) {
32 | if (angularType == 'page') {
33 | args += ' --standalone';
34 | }
35 | }
36 | if (isGreaterOrEqual('@ionic/angular-toolkit', '11.0.1')) {
37 | if (angularType == 'component') {
38 | args += ' --standalone';
39 | }
40 | }
41 | }
42 | name = replaceAll(name, ' ', '-').trim();
43 | writeIonic(`Creating Angular ${angularType} named ${name}..`);
44 | checkAngularJson(project);
45 | const angularProjectName = ionicState.project ?? 'app';
46 | // eg ng generate page page-a --standalone --project=app
47 | let cmd = `${npx(project)} ng generate ${angularType} ${name}${args} --project=${angularProjectName}`;
48 | if (angularType == 'directive') {
49 | cmd += ` --skip-import`;
50 | }
51 | write(`> ${cmd}`);
52 | const out = await getRunOutput(cmd, project.projectFolder());
53 | write(out);
54 | const src = getStringFrom(out, 'CREATE ', '.ts');
55 | const path = join(project.projectFolder(), src + '.ts');
56 | if (!src || !existsSync(path)) {
57 | writeError(`Failed to create Angular ${angularType} named ${name}`);
58 | } else {
59 | writeIonic(`Created Angular ${angularType} named ${name}`);
60 | await openUri(path);
61 | }
62 | } catch (err) {
63 | writeError(`Unable to generate Angular ${angularType} named ${name}: ${err}`);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/build-configuration.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 | import { ionicState } from './ionic-tree-provider';
3 | import { exists } from './analyzer';
4 | import { ExtensionContext, window } from 'vscode';
5 | import { existsSync, readFileSync } from 'fs';
6 | import { join } from 'path';
7 |
8 | export function getConfigurationName(): string {
9 | if (!ionicState.configuration || ionicState.configuration == 'default') {
10 | return '';
11 | } else {
12 | return `(${ionicState.configuration})`;
13 | }
14 | }
15 |
16 | export function getConfigurationArgs(isDebugging?: boolean): string {
17 | let config = ionicState.configuration;
18 | if (isDebugging) {
19 | // If we are debugging and its an Angular project without a selected build config
20 | // then choose "development" so that source maps work
21 | if (config == 'production') {
22 | config = 'development'; // Assume we have this configuration
23 | }
24 | }
25 | if (!config || config == 'default') {
26 | return '';
27 | } else {
28 | if (exists('vue') || exists('react')) {
29 | return ` --mode=${config}`;
30 | } else {
31 | return ` --configuration=${config}`;
32 | }
33 | }
34 | }
35 |
36 | export async function buildConfiguration(folder: string, context: ExtensionContext, project: Project): Promise {
37 | let configs = [];
38 | const filename = join(project.projectFolder(), 'angular.json');
39 | if (existsSync(filename)) {
40 | configs = getAngularBuildConfigs(filename);
41 | }
42 | if (exists('vue') || exists('react')) {
43 | configs = ['development', 'production'];
44 | }
45 | if (configs.length == 0) {
46 | window.showInformationMessage('No build configurations found in this project');
47 | return;
48 | }
49 | configs.unshift('default');
50 | const selection = window.showQuickPick(configs, { placeHolder: 'Select a build configuration to use' });
51 | return selection;
52 | }
53 |
54 | function getAngularBuildConfigs(filename: string): Array {
55 | try {
56 | const result = [];
57 | const angular = JSON.parse(readFileSync(filename, 'utf8'));
58 | for (const config of Object.keys(angular.projects.app.architect.build.configurations)) {
59 | result.push(config);
60 | }
61 | return result;
62 | } catch {
63 | return [];
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/cap-project.ts:
--------------------------------------------------------------------------------
1 | export interface CapacitorProjectState {
2 | iosBundleId?: string;
3 | androidBundleId?: string;
4 | iosVersion?: string;
5 | androidVersion?: string;
6 | iosBuild?: number;
7 | androidBuild?: number;
8 | iosDisplayName?: string;
9 | androidDisplayName?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/src/capacitor-add.ts:
--------------------------------------------------------------------------------
1 | import { exists } from './analyzer';
2 | import { CapacitorPlatform } from './capacitor-platform';
3 | import { useIonicCLI } from './capacitor-run';
4 | import { InternalCommand } from './command-name';
5 | import { MonoRepoType } from './monorepo';
6 | import { npx } from './node-commands';
7 | import { Project } from './project';
8 |
9 | /**
10 | * Add a Capacitor Platform
11 | * @param {Project} project
12 | * @param {CapacitorPlatform} platform
13 | * @returns string
14 | */
15 | export function capacitorAdd(project: Project, platform: CapacitorPlatform): string {
16 | const ionic = useIonicCLI() ? 'ionic ' : '';
17 | switch (project.repoType) {
18 | case MonoRepoType.none:
19 | return `${npx(project)} ${ionic}cap add ${platform}`;
20 | case MonoRepoType.npm:
21 | case MonoRepoType.yarn:
22 | case MonoRepoType.lerna:
23 | case MonoRepoType.folder:
24 | case MonoRepoType.pnpm:
25 | return `${InternalCommand.cwd}${npx(project)} ${ionic}cap add ${platform}`;
26 | case MonoRepoType.nx:
27 | return nxAdd(project, platform);
28 | default:
29 | throw new Error('Unsupported Monorepo type');
30 | }
31 | }
32 |
33 | function nxAdd(project: Project, platform: CapacitorPlatform): string {
34 | return `${npx(project)} nx run ${project.monoRepo.name}:add:${platform}`;
35 | }
36 |
--------------------------------------------------------------------------------
/src/capacitor-platform.ts:
--------------------------------------------------------------------------------
1 | export enum CapacitorPlatform {
2 | ios = 'ios',
3 | android = 'android',
4 | }
5 |
--------------------------------------------------------------------------------
/src/capacitor-pwa.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { Project } from './project';
3 | import { ActionResult } from './command-name';
4 | import { ignore } from './ignore';
5 | import { ionicState } from './ionic-tree-provider';
6 | import { QueueFunction, Tip } from './tip';
7 | import { runCommands } from './advanced-actions';
8 | import { npx } from './node-commands';
9 |
10 | export async function integratePWA(queueFunction: QueueFunction, project: Project, tip: Tip): Promise {
11 | const result = await window.showInformationMessage(
12 | `Progressive Web Application (PWA) Integration - This will add @angular/pwa to your project and make changes in your project to make it a PWA (manifest file, splash screen and icon resources).`,
13 | 'Apply Changes',
14 | 'Ignore',
15 | );
16 | if (result == 'Ignore') {
17 | ignore(tip, ionicState.context);
18 | return;
19 | }
20 | if (!result) {
21 | return;
22 | }
23 | queueFunction();
24 | await runCommands(
25 | [`${npx(project)} ng add @angular/pwa --defaults --skip-confirmation true`],
26 | 'Adding @angular/pwa',
27 | project,
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/src/capacitor-sync.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 | import { MonoRepoType } from './monorepo';
3 | import { exists, isGreaterOrEqual } from './analyzer';
4 | import { InternalCommand } from './command-name';
5 | import { npx, PackageManager, preflightNPMCheck } from './node-commands';
6 | import { getConfigurationArgs } from './build-configuration';
7 | import { useIonicCLI } from './capacitor-run';
8 |
9 | /**
10 | * Creates the capacitor sync command
11 | * @param {Project} project
12 | * @returns string
13 | */
14 | export async function capacitorSync(project: Project): Promise {
15 | const preop = preflightNPMCheck(project);
16 |
17 | const ionicCLI = useIonicCLI();
18 | switch (project.repoType) {
19 | case MonoRepoType.none:
20 | return preop + (ionicCLI ? ionicCLISync(project) : capCLISync(project));
21 | case MonoRepoType.folder:
22 | case MonoRepoType.pnpm:
23 | case MonoRepoType.lerna:
24 | case MonoRepoType.yarn:
25 | case MonoRepoType.npm:
26 | return InternalCommand.cwd + preop + (ionicCLI ? ionicCLISync(project) : capCLISync(project));
27 | case MonoRepoType.nx:
28 | return preop + nxSync(project);
29 | default:
30 | throw new Error('Unsupported Monorepo type');
31 | }
32 | }
33 |
34 | function capCLISync(project: Project): string {
35 | if (isGreaterOrEqual('@capacitor/cli', '4.1.0')) {
36 | return `${npx(project)} cap sync --inline`;
37 | }
38 | return `${npx(project)} cap sync${getConfigurationArgs()}`;
39 | }
40 |
41 | function ionicCLISync(project: Project): string {
42 | return `${npx(project)} ionic cap sync --inline${getConfigurationArgs()}`;
43 | }
44 |
45 | function nxSync(project: Project): string {
46 | if (project.monoRepo.isNXStandalone) {
47 | return capCLISync(project);
48 | }
49 | return `${npx(project)} nx sync ${project.monoRepo.name}${getConfigurationArgs()}`;
50 | }
51 |
--------------------------------------------------------------------------------
/src/command-title.ts:
--------------------------------------------------------------------------------
1 | export enum CommandTitle {
2 | OpenInXCode = 'Open in Xcode',
3 | OpenInAndroidStudio = 'Open in Android Studio',
4 | RunForIOS = 'iOS',
5 | RunForAndroid = 'Android',
6 | Sync = 'Sync',
7 | RunForWeb = 'Web',
8 | }
9 |
--------------------------------------------------------------------------------
/src/context-variables.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 |
3 | export enum Context {
4 | // Whether the project has been inspected (true) or not (false)
5 | inspectedProject = 'inspectedProject',
6 |
7 | // Whether the user has clicked Login (true)
8 | isLoggingIn = 'isLoggingIn',
9 |
10 | // Whether the current user is not known (true)
11 | isAnonymous = 'isAnonymous',
12 |
13 | // VS Code hasnt opened a folder
14 | noProjectFound = 'noProjectFound',
15 |
16 | // Used for splash screen assets that can be viewed
17 | asset = 'asset',
18 |
19 | // The panel for monorepo projects
20 | isMonoRepo = 'isMonoRepo',
21 |
22 | // The panel for the running dev server
23 | isDevServing = 'isDevServing',
24 |
25 | // A scope that can be upgraded
26 | upgrade = 'upgrade',
27 |
28 | // Upgrade options
29 | lightbulb = 'lightbulb',
30 |
31 | // Live Reload
32 | liveReload = 'liveReload',
33 |
34 | // Stop option
35 | stop = 'stop',
36 |
37 | // Build configuration
38 | buildConfig = 'buildConfig',
39 |
40 | // Web configuration
41 | webConfig = 'webConfig',
42 |
43 | // Web Debug configuration
44 | webDebugConfig = 'webDebugConfig',
45 |
46 | // Select Action
47 | selectAction = 'selectAction',
48 |
49 | // Device selection
50 | selectDevice = 'selectDevice',
51 |
52 | // Shell (eg /bin/zsh)
53 | shell = 'shell',
54 |
55 | // Rebuild used for splash screen
56 | rebuild = 'rebuild',
57 |
58 | // Refresh used for debug instances
59 | refreshDebug = 'refreshDebug',
60 | }
61 |
62 | // Commands from vs code
63 | export enum VSCommand {
64 | setContext = 'setContext',
65 | }
66 |
67 | export function PackageCacheOutdated(project: Project) {
68 | if (project?.monoRepo?.localPackageJson) {
69 | return 'npmOutdatedData_' + project.monoRepo.name;
70 | }
71 | return 'npmOutdatedData';
72 | }
73 |
74 | export function PackageCacheList(project: Project) {
75 | if (project?.monoRepo?.localPackageJson) {
76 | return 'npmListData_' + project.monoRepo.name;
77 | }
78 | return 'npmListData';
79 | }
80 |
81 | export function CapProjectCache(project: Project) {
82 | if (project?.monoRepo?.localPackageJson) {
83 | return 'CapacitorProject_' + project.monoRepo.name;
84 | }
85 | return 'CapacitorProject';
86 | }
87 |
88 | export function PackageCacheModified(project: Project) {
89 | if (project?.monoRepo?.localPackageJson) {
90 | return 'packagesModified_' + project.monoRepo.name;
91 | }
92 | return 'packagesModified';
93 | }
94 |
95 | export const LastManifestCheck = 'LastManifestCheck';
96 |
--------------------------------------------------------------------------------
/src/features.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { GlobalSetting, getGlobalSetting, setGlobalSetting } from './workspace-state';
3 | import { alt } from './utilities';
4 |
5 | // Feature Flags for experimental options
6 | export const Features = {
7 | debugAndroid: true, // Whether debugging for Android is turned on
8 | pluginExplorer: true, // Whether the plugin explorer is shown
9 | requireLogin: false, // Whether we require the user to be logged in via "ionic login"
10 | };
11 |
12 | export function showTips() {
13 | const tips = getGlobalSetting(GlobalSetting.lastTipsShown);
14 | const shownAt = tips ? Date.parse(tips) : 0;
15 | const days = (new Date().getTime() - shownAt) / (1000 * 3600 * 24);
16 | if (days > 30) {
17 | window.showInformationMessage(`Ionic Tip: Press ${alt('D')} to debug your app and ${alt('R')} to run it!`, 'OK');
18 | setGlobalSetting(GlobalSetting.lastTipsShown, new Date().toISOString());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/gradle-to-json.ts:
--------------------------------------------------------------------------------
1 | import { existsSync, readFileSync } from 'fs';
2 | import { replaceAll } from './utilities';
3 |
4 | export function gradleToJson(filename: string): any | undefined {
5 | if (!existsSync(filename)) {
6 | return undefined;
7 | }
8 | try {
9 | const lines = readFileSync(filename, 'utf8').split('\n');
10 | const result = {};
11 | let at = result;
12 | const stack = [at];
13 | for (const line of lines) {
14 | if (line.trim().endsWith('{')) {
15 | const key = replaceAll(line, '{', '').trim();
16 | at[key] = {};
17 | stack.push(at);
18 | at = at[key];
19 | } else if (line.trim().endsWith('}')) {
20 | at = stack.pop();
21 | } else if (line.trim() !== '') {
22 | const kv = line.trim().split(' ');
23 | if (kv.length == 2) {
24 | at[kv[0]] = kv[1];
25 | } else {
26 | at[kv[0]] = [];
27 | for (let i = 1; i < kv.length; i++) {
28 | at[kv[0]].push(kv[i]);
29 | }
30 | }
31 | }
32 | }
33 | return result;
34 | } catch {
35 | return undefined;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/ignore.ts:
--------------------------------------------------------------------------------
1 | import { ExtensionContext } from 'vscode';
2 | import { Tip } from './tip';
3 |
4 | /**
5 | * Allows recommendations to be ignored. We need to store the recommendation text from the tip
6 | * @param {Tip} tip
7 | * @param {vscode.ExtensionContext} context
8 | */
9 | export function ignore(tip: Tip, context: ExtensionContext) {
10 | const key = 'ignoredRecommendations';
11 | const txt = `${tip.message}+${tip.title}`;
12 | const listJSON: string = context.workspaceState.get(key);
13 | let list = [];
14 |
15 | if (listJSON) {
16 | list = JSON.parse(listJSON);
17 | }
18 | if (!list.includes(txt)) {
19 | list.push(txt);
20 | }
21 |
22 | context.workspaceState.update(key, JSON.stringify(list));
23 | }
24 |
25 | export function getIgnored(context: ExtensionContext): Array {
26 | const key = 'ignoredRecommendations';
27 | const listJSON: string = context.workspaceState.get(key);
28 | let list = [];
29 | try {
30 | list = JSON.parse(listJSON);
31 | return list;
32 | } catch {
33 | return [];
34 | }
35 | }
36 |
37 | export function clearIgnored(context: ExtensionContext) {
38 | const key = 'ignoredRecommendations';
39 | context.workspaceState.update(key, undefined);
40 | }
41 |
42 | export function excludeIgnoredTips(tips: Array, context: ExtensionContext): Array {
43 | const key = 'ignoredRecommendations';
44 | const listJSON: string = context.workspaceState.get(key);
45 | let list = [];
46 |
47 | if (listJSON) {
48 | try {
49 | list = JSON.parse(listJSON);
50 | return tips.filter((tip) => {
51 | return tip && !list.includes(`${tip.message}+${tip.title}`);
52 | });
53 | } catch {
54 | context.workspaceState.update(key, '[]');
55 | return tips;
56 | }
57 | } else {
58 | return tips;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/ionic-auth.ts:
--------------------------------------------------------------------------------
1 | import { Context, VSCommand } from './context-variables';
2 | import { ionicState } from './ionic-tree-provider';
3 | import { sendTelemetryEvent, TelemetryEventType } from './telemetry';
4 | import { writeAppend } from './logging';
5 | import { ExtensionContext, ExtensionKind, UIKind, commands, env, window } from 'vscode';
6 | import { join } from 'path';
7 | import { ExecException, exec } from 'child_process';
8 |
9 | /**
10 | * ionic login and signup commands
11 | * @param {string} folder
12 | * @param {vscode.ExtensionContext} context
13 | */
14 | export async function ionicLogin(folder: string, context: ExtensionContext) {
15 | const ifolder = join(folder, 'node_modules', '@ionic', 'cli', 'bin');
16 | try {
17 | if (env.uiKind == UIKind.Web) {
18 | window.showErrorMessage(
19 | 'The Codespaces browser editor has limited functionality. Click "Next" to continue.',
20 | 'Next',
21 | );
22 | ionicState.skipAuth = true;
23 | await commands.executeCommand(VSCommand.setContext, Context.isAnonymous, false);
24 | return;
25 | }
26 | await run(`npx ionic login --confirm`, ifolder);
27 | sendTelemetryEvent(folder, TelemetryEventType.Login, context);
28 | } catch (err) {
29 | window.showErrorMessage(err);
30 | ionicState.skipAuth = true;
31 | await commands.executeCommand(VSCommand.setContext, Context.isAnonymous, false);
32 | }
33 | }
34 |
35 | export async function ionicSignup(folder: string, context: ExtensionContext) {
36 | const ifolder = join(folder, 'node_modules', '@ionic', 'cli', 'bin');
37 | await run('npx ionic signup', ifolder);
38 | sendTelemetryEvent(folder, TelemetryEventType.SignUp, context);
39 | }
40 |
41 | async function run(command: string, folder: string): Promise {
42 | return new Promise((resolve, reject) => {
43 | let out = '';
44 | const cmd = exec(command, { cwd: folder }, (error: ExecException, stdout: string, stderror: string) => {
45 | if (stdout) {
46 | out += stdout;
47 | writeAppend(out);
48 | }
49 | if (!error) {
50 | writeAppend(out);
51 | resolve(out);
52 | } else {
53 | if (stderror) {
54 | reject(stderror);
55 | } else {
56 | resolve(out);
57 | }
58 | }
59 | });
60 | cmd.stdin.pipe(process.stdin);
61 | });
62 | }
63 |
--------------------------------------------------------------------------------
/src/ionic-devserver-provider.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CancellationToken,
3 | ExtensionContext,
4 | WebviewView,
5 | WebviewViewProvider,
6 | WebviewViewResolveContext,
7 | } from 'vscode';
8 |
9 | import { commands } from 'vscode';
10 | import { CommandName } from './command-name';
11 | import { qrWebView } from './nexus-browser';
12 |
13 | export class IonicDevServerProvider implements WebviewViewProvider {
14 | registered = false;
15 | constructor(
16 | private workspaceRoot: string | undefined,
17 | private context: ExtensionContext,
18 | ) {}
19 |
20 | resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken) {
21 | if (this.registered) return;
22 | this.registered = true;
23 | commands.registerCommand(CommandName.ViewDevServer, (url: string) => {
24 | const shortUrl = qrWebView(webviewView.webview, url);
25 | //webviewView.description = shortUrl;
26 | webviewView.show(true);
27 | });
28 |
29 | commands.registerCommand(CommandName.hideDevServer, () => {
30 | // THERE IS NO API TO HIDE/COLLAPSE A VIEW
31 | const shortUrl = qrWebView(webviewView.webview, undefined);
32 | //webviewView.show(true);
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ionic-projects-provider.ts:
--------------------------------------------------------------------------------
1 | import { Event, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, TreeItemCollapsibleState } from 'vscode';
2 | import { CommandName } from './command-name';
3 | import { ionicState } from './ionic-tree-provider';
4 | import { Recommendation } from './recommendation';
5 |
6 | export class IonicProjectsreeProvider implements TreeDataProvider {
7 | private _onDidChangeTreeData: EventEmitter = new EventEmitter<
8 | Recommendation | undefined | void
9 | >();
10 | readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event;
11 | constructor(
12 | private workspaceRoot: string | undefined,
13 | private context: ExtensionContext,
14 | ) {}
15 |
16 | selectedProject: string;
17 |
18 | refresh(project: string): void {
19 | ionicState.workspace = project;
20 | this.selectedProject = project;
21 | this._onDidChangeTreeData.fire();
22 | }
23 |
24 | getTreeItem(element: Recommendation): TreeItem {
25 | return element;
26 | }
27 |
28 | getChildren(element?: Recommendation): Thenable {
29 | return Promise.resolve(this.projectList());
30 | }
31 |
32 | projectList(): Array {
33 | const list = [];
34 | for (const project of ionicState.projects) {
35 | const cmd = {
36 | command: CommandName.ProjectSelect,
37 | title: 'Open',
38 | arguments: [project.name],
39 | };
40 | const r = new Recommendation(project.folder, undefined, project.name, TreeItemCollapsibleState.None, cmd);
41 | const icon = project.name == this.selectedProject ? 'circle-filled' : 'none';
42 | r.setIcon(icon);
43 | list.push(r);
44 | }
45 | return list;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/ionic-start-templates.ts:
--------------------------------------------------------------------------------
1 | // You can paste these by running npx ionic start -l
2 | export const ionicTemplates = `
3 | Starters for @ionic/vue (--type=vue)
4 |
5 | name | description
6 | ----------------------------------------------------------------------------------
7 | tabs | A starting project with a simple tabbed interface
8 | sidemenu | A starting project with a side menu with navigation in the content area
9 | blank | A blank starter project
10 | list | A starting project with a list
11 |
12 |
13 | Starters for @ionic/angular (--type=angular)
14 |
15 | name | description
16 | --------------------------------------------------------------------------------------
17 | tabs | A starting project with a simple tabbed interface
18 | sidemenu | A starting project with a side menu with navigation in the content area
19 | blank | A blank starter project
20 | list | A starting project with a list
21 | my-first-app | A template for the "Build Your First App" tutorial
22 |
23 |
24 | Starters for angular-standalone (--type=angular-standalone)
25 |
26 | name | description
27 | --------------------------------------------------------------------------------------
28 | tabs | A starting project with a simple tabbed interface
29 | sidemenu | A starting project with a side menu with navigation in the content area
30 | blank | A blank starter project
31 | list | A starting project with a list
32 | my-first-app | A template for the "Build Your First App" tutorial
33 |
34 |
35 | Starters for @ionic/react (--type=react)
36 |
37 | name | description
38 | --------------------------------------------------------------------------------------
39 | blank | A blank starter project
40 | list | A starting project with a list
41 | my-first-app | A template for the "Build Your First App" tutorial
42 | sidemenu | A starting project with a side menu with navigation in the content area
43 | tabs | A starting project with a simple tabbed interface
44 | `;
45 |
--------------------------------------------------------------------------------
/src/logging.ts:
--------------------------------------------------------------------------------
1 | import { OutputChannel, window } from 'vscode';
2 |
3 | let channel: OutputChannel = undefined;
4 |
5 | function getOutputChannel(): OutputChannel {
6 | if (!channel) {
7 | channel = window.createOutputChannel('Ionic');
8 | channel.show();
9 | }
10 | return channel;
11 | }
12 |
13 | export function clearOutput(): OutputChannel {
14 | const channel = getOutputChannel();
15 | channel.clear();
16 | channel.show();
17 | return channel;
18 | }
19 |
20 | export function showOutput() {
21 | const channel = getOutputChannel();
22 | channel.show();
23 | }
24 |
25 | export function write(message: string) {
26 | getOutputChannel().appendLine(message);
27 | }
28 |
29 | export function writeAppend(message: string) {
30 | getOutputChannel().append(message);
31 | }
32 |
33 | export function writeIonic(message: string) {
34 | const channel = getOutputChannel();
35 | channel.appendLine(`[Ionic] ${message}`);
36 | }
37 |
38 | export function writeError(message: string) {
39 | const channel = getOutputChannel();
40 | channel.appendLine(`[error] ${message}`);
41 | }
42 |
43 | export function writeWarning(message: string) {
44 | const channel = getOutputChannel();
45 | channel.appendLine(`[warning] ${message}`);
46 | }
47 |
--------------------------------------------------------------------------------
/src/messages.ts:
--------------------------------------------------------------------------------
1 | import { npmInstall } from './node-commands';
2 | import { Command, Tip, TipType } from './tip';
3 |
4 | export const error = (title: string, str: string): Tip => {
5 | return new Tip(title, str, TipType.Error, str, Command.NoOp, 'OK').canIgnore();
6 | };
7 |
8 | export const libString = (lib: string, ver: string) => {
9 | const vstr = ver ? ` (${ver})` : '';
10 | return `${lib}${vstr}`;
11 | };
12 |
13 | export const writeMinVersionError = (library: string, version: string, minVersion: string, reason: string): Tip => {
14 | return new Tip(
15 | library,
16 | `${library} must be upgraded from ${version} to at least version ${minVersion}${reason ? ' ' + reason : ''}`,
17 | TipType.Error,
18 | undefined,
19 | npmInstall(library + '@latest'),
20 | `Upgrade`,
21 | `${library} successfully updated.`,
22 | ).canIgnore();
23 | };
24 | export const writeMinVersionWarning = (
25 | library: string,
26 | version: string,
27 | minVersion: string,
28 | reason: string,
29 | url?: string,
30 | ): Tip => {
31 | let r = reason ? ' ' + reason : '';
32 | if (url) r = `[${reason}](${url})`;
33 | return new Tip(
34 | library,
35 | `Update to at least ${minVersion}${reason ? ' ' + reason : ''}`,
36 | TipType.Idea,
37 | `${library} ${version} should be updated to at least ${minVersion}${reason ? ' ' + reason : ''}`,
38 | npmInstall(`${library}@latest`),
39 | `Upgrade`,
40 | `${library} successfully updated.`,
41 | ).canIgnore();
42 | };
43 |
44 | export const writeConsistentVersionWarning = (lib1: string, ver1: string, lib2: string, ver2: string) => {
45 | return new Tip(
46 | lib2,
47 | `Version of ${libString(lib2, ver2)} should match ${libString(lib1, ver1)}`,
48 | TipType.Error,
49 | undefined,
50 | npmInstall(`${lib2}@${ver1}`),
51 | `Upgrade`,
52 | `${lib2} successfully updated.`,
53 | ).canIgnore();
54 | };
55 |
56 | export const writeConsistentVersionError = (lib1: string, ver1: string, lib2: string, ver2: string): Tip => {
57 | return new Tip(
58 | lib2,
59 | `Version of ${libString(lib2, ver2)} must match ${libString(lib1, ver1)}`,
60 | TipType.Error,
61 | undefined,
62 | npmInstall(`${lib2}@${ver1}`),
63 | `Upgrade`,
64 | `${lib2} successfully updated.`,
65 | ).canIgnore();
66 | };
67 |
--------------------------------------------------------------------------------
/src/monorepos-lerna.ts:
--------------------------------------------------------------------------------
1 | import * as globule from 'globule';
2 |
3 | import { MonoRepoProject } from './monorepo';
4 | import { Project } from './project';
5 | import { existsSync, readFileSync } from 'fs';
6 | import { basename, join } from 'path';
7 |
8 | export function getLernaWorkspaces(project: Project): Array {
9 | const lernaFile = join(project.folder, 'lerna.json');
10 | if (!existsSync(lernaFile)) {
11 | return [];
12 | }
13 |
14 | try {
15 | const json = readFileSync(lernaFile, { encoding: 'utf8' });
16 | const lerna = JSON.parse(json);
17 | const list = [];
18 | for (const folder of lerna.packages) {
19 | list.push(folder);
20 | }
21 | const folders = globule.find({ src: list, srcBase: project.folder });
22 | const repos: Array = [];
23 | for (const folder of folders) {
24 | repos.push({ folder: join(project.folder, folder), name: basename(folder) });
25 | }
26 | return repos;
27 | } catch (err) {
28 | console.error(err);
29 | return [];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/monorepos-npm.ts:
--------------------------------------------------------------------------------
1 | import * as globule from 'globule';
2 |
3 | import { MonoRepoProject } from './monorepo';
4 | import { Project } from './project';
5 | import { basename, join } from 'path';
6 |
7 | /**
8 | * Get mono repo project list when using npm workspaces
9 | * @param {Project} project
10 | * @returns Array of Mono Repo Projects
11 | */
12 | export function getNpmWorkspaceProjects(project: Project): Array {
13 | const result: Array = [];
14 | const folders = globule.find({ src: project.workspaces, srcBase: project.folder });
15 | for (const folder of folders) {
16 | result.push({ name: basename(folder), folder: join(project.folder, folder) });
17 | }
18 | return result;
19 | }
20 |
--------------------------------------------------------------------------------
/src/monorepos-pnpm.ts:
--------------------------------------------------------------------------------
1 | import * as globule from 'globule';
2 |
3 | import { MonoRepoProject } from './monorepo';
4 | import { replaceAll } from './utilities';
5 | import { Project } from './project';
6 | import { existsSync, readFileSync } from 'fs';
7 | import { basename, join } from 'path';
8 |
9 | export function getPnpmWorkspaces(project: Project): Array {
10 | const pw = join(project.folder, 'pnpm-workspace.yaml');
11 | if (!existsSync(pw)) {
12 | return [];
13 | }
14 | const yaml = readFileSync(pw, { encoding: 'utf8' });
15 | try {
16 | const list = [];
17 | for (const line of yaml.split('\n')) {
18 | if (line.trim().startsWith('-')) {
19 | let folder = line.replace('-', '').trim();
20 | folder = replaceAll(folder, '"', '');
21 | folder = replaceAll(folder, `'`, '');
22 | list.push(folder);
23 | // packages/*
24 | // '.'
25 | // */**
26 | // '!devtool/**'
27 | // '!docs/**'
28 | // '!examples/**'
29 | }
30 | }
31 | const folders = globule.find({ src: list, srcBase: project.folder });
32 | const repos: Array = [];
33 | for (const folder of folders) {
34 | repos.push({ folder: join(project.folder, folder), name: basename(folder) });
35 | }
36 | return repos;
37 | } catch (err) {
38 | console.error(err);
39 | return [];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/npm-info-data.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is the API response from https://registry.npmjs.org/${name}/latest or https://registry.npmjs.org/${name}
3 | */
4 | export interface NpmInfo {
5 | _id: string;
6 | _rev: string;
7 | name: string;
8 | 'dist-tags': DistTags;
9 | versions: string[] | undefined;
10 | time: any;
11 | created: string;
12 | maintainers: string[];
13 | description: string;
14 | homepage: string;
15 | keywords: string[];
16 | repository: Repository;
17 | author: { name: string; email?: string; url?: string } | string;
18 | bugs: Bugs;
19 | license: { type: string; url?: string } | string;
20 | readmeFilename: string;
21 | _cached: boolean;
22 | _contentLength: number;
23 | version: string;
24 | main: string;
25 | module: string;
26 | types: string;
27 | unpkg: string;
28 | scripts: any;
29 | devDependencies: any;
30 | peerDependencies: any;
31 | dependencies: any;
32 | prettier: string;
33 | swiftlint: string;
34 | gitHead: string;
35 | engines: any;
36 | _nodeVersion: string;
37 | _npmVersion: string;
38 | dist: Dist;
39 | cordova: CordovaInfo;
40 | capacitor: CapacitorInfo;
41 | _npmUser: string;
42 | directories: Directories;
43 | _npmOperationalInternal: NpmOperationalInternal;
44 | _hasShrinkwrap: boolean;
45 | }
46 |
47 | interface CordovaInfo {
48 | platforms: string[] | string;
49 | }
50 |
51 | interface Directories {
52 | unknown: any;
53 | }
54 |
55 | interface CapacitorInfo {
56 | ios: any;
57 | android: any;
58 | }
59 |
60 | interface DistTags {
61 | latest: string;
62 | next: string;
63 | }
64 |
65 | interface Repository {
66 | type: string;
67 | url: string;
68 | }
69 |
70 | interface Bugs {
71 | url: string;
72 | }
73 |
74 | interface Dist {
75 | integrity: string;
76 | shasum: string;
77 | tarball: string;
78 | fileCount: number;
79 | unpackedSize: number;
80 | signatures: Signature[];
81 | 'npm-signature': string;
82 | }
83 |
84 | interface Signature {
85 | keyid: string;
86 | sig: string;
87 | }
88 |
89 | interface NpmOperationalInternal {
90 | host: string;
91 | tmp: string;
92 | }
93 |
94 | /**
95 | * This is the response from the npm api https://api.npmjs.org/downloads/[period]/[package]
96 | */
97 | export interface NpmDownloads {
98 | downloads: number;
99 | start: string;
100 | end: string;
101 | package: string;
102 | }
103 |
--------------------------------------------------------------------------------
/src/npm-info.ts:
--------------------------------------------------------------------------------
1 | import { NpmInfo } from './npm-info-data';
2 |
3 | export async function getNpmInfo(name: string, latest: boolean): Promise {
4 | let url = '';
5 | try {
6 | url = latest ? `https://registry.npmjs.org/${name}/latest` : `https://registry.npmjs.org/${name}`;
7 | const np: NpmInfo = await httpGet(url, npmHeaders());
8 | if (!np.name) throw new Error(`No name found in ${url}`); // This error is happening for some reason
9 | //np.versions = undefined;
10 | np.version = np['dist-tags'] ? np['dist-tags'].latest : np.version;
11 | return np;
12 | } catch (error) {
13 | const msg = `${error}`;
14 | if (msg.includes(`'Not found'`)) {
15 | console.error(`[error] ${name} was not found on npm.`);
16 | } else {
17 | console.error(`getNpmInfo Failed ${url}`, error);
18 | }
19 | return {} as NpmInfo;
20 | }
21 | }
22 |
23 | function npmHeaders(): any {
24 | return {
25 | headers: {
26 | Authorization: `bearer ${getNpmToken()}`,
27 | 'User-Agent': 'Ionic VSCode Extension',
28 | Accept: '*/*',
29 | },
30 | };
31 | }
32 |
33 | export async function httpGet(url: string, opts: any): Promise {
34 | const response = await fetch(url, opts);
35 | try {
36 | const data = await response.json();
37 | if (rateLimited(data)) {
38 | console.log(`The api call ${url} was rate limited.`);
39 | }
40 | return data;
41 | } catch (error) {
42 | throw new Error(`Error: get ${url}: ${response.status} ${response.statusText}`);
43 | }
44 | }
45 |
46 | function rateLimited(a: any): boolean {
47 | return (
48 | (a as any).message?.startsWith('API rate limit exceeded') ||
49 | (a as any).message?.startsWith('You have exceeded a secondary rate limit')
50 | );
51 | }
52 |
53 | export function getNpmToken() {
54 | return process.env.DATA_SCRIPTS_NPM_TOKEN;
55 | }
56 |
--------------------------------------------------------------------------------
/src/npm-model.ts:
--------------------------------------------------------------------------------
1 | // Used for the data than comes from npm list --json
2 | export interface NpmPackage {
3 | // Version number in the package.json
4 | version: string;
5 |
6 | // Name in package.json
7 | name: string;
8 |
9 | // This is an object with properties for each package.
10 | // eg { "@capacitor/project": {"version": "1.0.31", "resolved": "https://registry.npmjs.org/@capacitor/project/-/project-1.0.31.tgz"}}
11 | dependencies: object;
12 | }
13 |
14 | export interface NpmDependency {
15 | version: string; // Version number
16 | resolved: string; // URL to the package
17 | }
18 |
19 | // Used from npm outdated --json
20 | export interface NpmOutdatedDependency {
21 | current: string; // Current version
22 | wanted: string;
23 | latest: string;
24 | dependent: string; // Package that depends on this
25 | location: string; // path to the node modules folder
26 | }
27 |
28 | export enum PackageType {
29 | Dependency = 'Dependency',
30 | CapacitorPlugin = 'Capacitor Plugin',
31 | CordovaPlugin = 'Plugin',
32 | }
33 |
34 | export enum PackageVersion {
35 | Unknown = 'Unknown',
36 |
37 | // Like a version that is pulled from git or local folder
38 | Custom = '[custom]',
39 | }
40 |
--------------------------------------------------------------------------------
/src/package-info.ts:
--------------------------------------------------------------------------------
1 | export interface PackageInfo {
2 | version: string;
3 | current: string;
4 | wanted: string;
5 | latest: string;
6 | change: string;
7 | depType: string;
8 | }
9 |
--------------------------------------------------------------------------------
/src/package-lock.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path';
2 | import { Project } from './project';
3 | import { PackageManager } from './node-commands';
4 | import { existsSync, readFileSync } from 'fs';
5 | import { tEnd, tStart } from './utilities';
6 | import { NpmPackage } from './npm-model';
7 |
8 | export function getVersionsFromPackageLock(project: Project): NpmPackage {
9 | if (project.packageManager != PackageManager.npm) return undefined;
10 | const lockFile = join(project.projectFolder(), 'package-lock.json');
11 | if (!existsSync(lockFile)) return undefined;
12 | const command = `getVersionsFromPackageLock`;
13 | tStart(command);
14 | const txt = readFileSync(lockFile, { encoding: 'utf8' });
15 | const data = JSON.parse(txt);
16 | const result = {};
17 | try {
18 | const packages = data.packages[''];
19 | for (const dep of [...Object.keys(packages.dependencies), ...Object.keys(packages.devDependencies)]) {
20 | const name = `node_modules/${dep}`;
21 | result[dep] = { version: data.packages[name].version };
22 | }
23 | tEnd(command);
24 | return { name: project.name, version: '0.0.0', dependencies: result };
25 | } catch {
26 | return undefined;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/peer-dependency-cleanup.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { getAllPackageNames, getPackageVersion, load } from './analyzer';
3 | import { ionicState } from './ionic-tree-provider';
4 | import { write } from './logging';
5 | import { DependencyVersion, PeerReport, checkPeerDependencies } from './peer-dependencies';
6 | import { Project, inspectProject } from './project';
7 | import { showProgress } from './utilities';
8 |
9 | export async function peerDependencyCleanup(project: Project): Promise {
10 | let report: PeerReport;
11 | await showProgress(`Checking dependencies in your project...`, async () => {
12 | // Need to reload dependency list
13 | await inspectProject(ionicState.rootFolder, ionicState.context, undefined);
14 |
15 | const dependencies = getAllPackageNames();
16 | const list: DependencyVersion[] = [];
17 | for (const dependency of dependencies) {
18 | const versionInfo = getPackageVersion(dependency);
19 | list.push({ name: dependency, version: versionInfo.version });
20 | }
21 |
22 | report = await checkPeerDependencies(project.projectFolder(), list, []);
23 | });
24 | //write(JSON.stringify(report, undefined, 2));
25 | if (report.commands.length == 0) {
26 | write(`There are no dependency conflicts.`);
27 | return;
28 | }
29 | write('');
30 | let question = 'Would you like to fix these?';
31 | if (report.commands.length == 1) {
32 | question = `Would you like to update ${report.dependencies[0].name}?`;
33 | }
34 | if (
35 | (await window.showWarningMessage(
36 | `There ${isAre(report.commands.length)} ${report.commands.length} dependency conflict${plural(
37 | report.commands.length,
38 | )} that can be resolved. ${question}`,
39 | 'Yes',
40 | 'No',
41 | )) != 'Yes'
42 | ) {
43 | return;
44 | }
45 | for (const cmd of report.commands) {
46 | write(`> ${cmd}`);
47 | await project.run2(cmd, true);
48 | }
49 | write(`${report.commands.length} dependency conflict${plural(report.commands.length)} resolved.`);
50 | }
51 |
52 | function isAre(count: number): string {
53 | return count == 1 ? 'is' : 'are';
54 | }
55 |
56 | function plural(count: number): string {
57 | return count > 1 ? 's' : '';
58 | }
59 |
--------------------------------------------------------------------------------
/src/plugin-summary.ts:
--------------------------------------------------------------------------------
1 | export interface PluginSummary {
2 | plugins: Plugin[];
3 | }
4 |
5 | export interface Plugin {
6 | name: string;
7 | version: string;
8 | success: string[];
9 | repo?: string;
10 | keywords?: string[];
11 | fails: string[];
12 | description?: string;
13 | quality?: number;
14 | versions: string[];
15 | author: any;
16 | bugs?: string;
17 | published: string;
18 | downloads?: number;
19 | stars?: number;
20 | image?: string;
21 | updated?: string;
22 | fork?: boolean;
23 | license?: string;
24 | }
25 |
--------------------------------------------------------------------------------
/src/quick-fix.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CancellationToken,
3 | CodeAction,
4 | CodeActionContext,
5 | CodeActionKind,
6 | CodeActionProvider,
7 | Command,
8 | Diagnostic,
9 | ProviderResult,
10 | Range,
11 | TextDocument,
12 | } from 'vscode';
13 | import { autoFixImports } from './imports-auto-fix';
14 |
15 | export class ImportQuickFixProvider implements CodeActionProvider {
16 | public static readonly providedCodeActionKinds = [CodeActionKind.QuickFix];
17 |
18 | public provideCodeActions(
19 | document: TextDocument,
20 | range: Range | Selection,
21 | context: CodeActionContext,
22 | token: CancellationToken,
23 | ): ProviderResult<(CodeAction | Command)[]> {
24 | // Filter out diagnostics that are not related to missing imports
25 | const missingImportDiagnostics = context.diagnostics.filter((diagnostic) =>
26 | diagnostic.message.includes('is not a known element'),
27 | );
28 |
29 | // Return an array of code actions for each diagnostic
30 | return missingImportDiagnostics.map((diagnostic) => this.createImportQuickFix(document, diagnostic));
31 | }
32 |
33 | private createImportQuickFix(document: TextDocument, diagnostic: Diagnostic): CodeAction {
34 | // Get the name of the missing identifier from the diagnostic message
35 | const missingComponent = diagnostic.message.split(' ')[0].replace(/["']/g, '');
36 | console.log(diagnostic.message);
37 | autoFixImports(document, missingComponent);
38 | return;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/recommendation.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path';
2 | import { Tip } from './tip';
3 | import { Command, TreeItem, TreeItemCollapsibleState } from 'vscode';
4 |
5 | export class Recommendation extends TreeItem {
6 | public children: Recommendation[];
7 | private iconName: string;
8 | private data: any;
9 | public whenExpanded: () => Promise>;
10 |
11 | constructor(
12 | public readonly tooltip: string,
13 | public readonly title: string,
14 | public readonly label: string,
15 | public readonly collapsibleState: TreeItemCollapsibleState,
16 | public readonly command?: Command,
17 | public tip?: Tip,
18 | public readonly url?: string,
19 | ) {
20 | super(label, collapsibleState);
21 |
22 | this.tooltip = `${this.tooltip}`;
23 | this.description = this.title;
24 | }
25 |
26 | public setIcon(name: string) {
27 | this.iconName = name;
28 | this.iconPath = {
29 | light: join(__filename, '..', '..', 'resources', 'light', name + '.svg'),
30 | dark: join(__filename, '..', '..', 'resources', 'dark', name + '.svg'),
31 | };
32 | }
33 |
34 | public setData(data: any): Recommendation {
35 | this.data = data;
36 | return this;
37 | }
38 |
39 | public getData(): any {
40 | return this.data;
41 | }
42 |
43 | // Animated icons need to have an equivalent filename with -anim that contains animated svg
44 | public animate() {
45 | this.setIcon(this.iconName + '-anim');
46 | }
47 |
48 | public setContext(value: string) {
49 | this.contextValue = value;
50 | }
51 |
52 | iconPath = undefined;
53 | contextValue = 'recommendation';
54 | }
55 |
--------------------------------------------------------------------------------
/src/rules-angular-toolkit.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 | import { QueueFunction, Tip, TipType } from './tip';
3 | import { window } from 'vscode';
4 | import { existsSync, readFileSync, writeFileSync } from 'fs';
5 | import { join } from 'path';
6 |
7 | /**
8 | * For Capacitor project if @ionic/angular-toolkit >= v6 then
9 | * "ionic-cordova-build" / "ionic-cordova-serve" sections in angular.json are not needed
10 | * Note: In Cordova projects require @ionic/cordova-builders
11 | * @param {Project} project
12 | */
13 | export function checkMigrationAngularToolkit(project: Project) {
14 | // v6 removed the "ionic-cordova-build" / "ionic-cordova-serve" sections in Angular.json
15 | const filename = join(project.folder, 'angular.json');
16 | if (existsSync(filename)) {
17 | const txt = readFileSync(filename, 'utf8');
18 | if (txt && txt.includes('ionic-cordova-build')) {
19 | project.add(
20 | new Tip('Migrate angular.json', 'Remove Cordova configurations', TipType.Error).setQueuedAction(
21 | fixAngularJson,
22 | filename,
23 | ),
24 | );
25 | }
26 | }
27 | }
28 |
29 | async function fixAngularJson(queueFunction: QueueFunction, filename: string) {
30 | if (
31 | !(await window.showErrorMessage(
32 | 'When using @ionic/angular-toolkit v6+ the ionic-cordova-build and ionic-cordova-serve sections in angular.json can be removed.',
33 | 'Fix angular.json',
34 | ))
35 | )
36 | return;
37 | queueFunction();
38 | const txt = readFileSync(filename, 'utf8');
39 | const angular = JSON.parse(txt);
40 | try {
41 | for (const project of Object.keys(angular.projects)) {
42 | delete angular.projects[project].architect['ionic-cordova-build'];
43 | delete angular.projects[project].architect['ionic-cordova-serve'];
44 | }
45 | writeFileSync(filename, JSON.stringify(angular, undefined, 2));
46 | window.showInformationMessage('angular.json has been migrated');
47 | } catch (err) {
48 | window.showErrorMessage('Failed to fix angular.json: ' + err);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/rules-capacitor-migration.ts:
--------------------------------------------------------------------------------
1 | import { exists, reviewPlugin } from './analyzer';
2 | import { InternalCommand } from './command-name';
3 | import { reviewPluginsWithHooks } from './process-packages';
4 | import { Project } from './project';
5 | import { capacitorRecommendations } from './rules-capacitor';
6 | import { Tip, TipType } from './tip';
7 | import { isWindows } from './utilities';
8 |
9 | export async function capacitorMigrationChecks(packages, project: Project): Promise {
10 | const tips: Tip[] = [];
11 | project.setGroup(
12 | 'Capacitor Migration',
13 | 'Your Cordova application ' +
14 | project.name +
15 | ' can be migrated to Capacitor (see [guide](https://capacitorjs.com/docs/cordova/migrating-from-cordova-to-capacitor)). The following recommendations will help with the migration:',
16 | TipType.Capacitor,
17 | true,
18 | );
19 |
20 | const list = await capacitorRecommendations(project, true);
21 | tips.push(...list);
22 |
23 | // Plugins with Hooks
24 | tips.push(...reviewPluginsWithHooks(packages));
25 |
26 | // Requires evaluation to determine compatibility
27 | tips.push(reviewPlugin('cordova-wheel-selector-plugin'));
28 | tips.push(reviewPlugin('cordova-plugin-secure-storage'));
29 | tips.push(reviewPlugin('newrelic-cordova-plugin'));
30 |
31 | if (exists('cordova-ios') || exists('cordova-android') || project.fileExists('config.xml')) {
32 | const movecmd = isWindows() ? 'rename config.xml config.xml.bak' : 'mv config.xml config.xml.bak';
33 | tips.push(
34 | new Tip(
35 | 'Remove Cordova Project',
36 | '',
37 | TipType.Capacitor,
38 | 'Remove the Cordova integration',
39 | ['npm uninstall cordova-ios', 'npm uninstall cordova-android', movecmd, InternalCommand.removeCordova],
40 | 'Remove Cordova',
41 | 'Removing Cordova',
42 | 'Successfully removed Cordova',
43 | ),
44 | );
45 | }
46 | project.tips(tips);
47 | }
48 |
--------------------------------------------------------------------------------
/src/rules-deprecated-plugins.ts:
--------------------------------------------------------------------------------
1 | import { Project } from './project';
2 |
3 | /**
4 | * Rules around deprecated plugins
5 | * @param {Project} project
6 | */
7 | export function checkDeprecatedPlugins(project: Project) {
8 | // Adobe Mobiles services deprecation
9 | project.deprecatedPlugin(
10 | 'adobe-mobile-services',
11 | 'Mobile Services reaches end-of-life on December 31, 2022',
12 | 'https://experienceleague.adobe.com/docs/mobile-services/using/eol.html?lang=en',
13 | );
14 |
15 | // Cordova Plugin Crop deprecation
16 | project.deprecatedPlugin(
17 | 'cordova-plugin-crop',
18 | 'cordova-plugin-crop is deprecated and does not support Android 11+',
19 | 'https://github.com/jeduan/cordova-plugin-crop#readme',
20 | );
21 |
22 | // App Center deprecated Cordova SDK
23 | project.deprecatedPlugin(
24 | 'cordova-plugin-appcenter-analytics',
25 | 'App Center is deprecating support for Cordova SDK in April 2022',
26 | 'https://devblogs.microsoft.com/appcenter/announcing-apache-cordova-retirement',
27 | );
28 | project.deprecatedPlugin(
29 | 'cordova-plugin-appcenter-crashes',
30 | 'App Center is deprecating support for Cordova SDK in April 2022',
31 | 'https://devblogs.microsoft.com/appcenter/announcing-apache-cordova-retirement',
32 | );
33 | project.deprecatedPlugin(
34 | 'cordova-plugin-appcenter-shared',
35 | 'App Center is deprecating support for Cordova SDK in April 2022',
36 | 'https://devblogs.microsoft.com/appcenter/announcing-apache-cordova-retirement',
37 | );
38 |
39 | project.deprecatedPlugin('cordova-plugin-contacts', 'Consider migration to @capacitor-community/contacts');
40 |
41 | project.deprecatedPlugin(
42 | '@ionic-enterprise/offline-storage',
43 | 'Replace this plugin with @ionic-enterprise/secure-storage',
44 | );
45 |
46 | project.recommendRemove(
47 | 'jetifier',
48 | 'jetifier',
49 | 'This tool was used to transition non-AndroidX libraries. By now though all plugins support Android 10 and this tool should be removed.',
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/src/rules-package-upgrade.ts:
--------------------------------------------------------------------------------
1 | import { fixIssue } from './extension';
2 | import { npmInstall } from './node-commands';
3 | import { Tip } from './tip';
4 | import { getRunOutput, showProgress } from './utilities';
5 | import { QuickPickItem, window } from 'vscode';
6 | import { QuickPickItemKind } from 'vscode';
7 |
8 | interface PackageInfo {
9 | name: string;
10 | version: string;
11 | }
12 | /**
13 | * Upgrade a package by allowing a user to select from the available versions
14 | * @param {PackageInfo} info
15 | * @param {string} folder
16 | */
17 | export async function packageUpgrade(info: PackageInfo, folder: string): Promise {
18 | let txt = '';
19 | await showProgress(`Finding versions of ${info.name}`, async () => {
20 | txt = await getRunOutput(`npm view ${info.name} versions --json`, folder);
21 | });
22 | const versions: Array = JSON.parse(txt).reverse();
23 | const idx = versions.findIndex((version) => info.version == version);
24 | versions.splice(idx, 1);
25 | const picks: QuickPickItem[] = [];
26 | const betas: string[] = [];
27 | picks.push({ label: 'Releases', kind: QuickPickItemKind.Separator });
28 | for (const version of versions) {
29 | if (version.includes('-')) {
30 | betas.push(version);
31 | } else {
32 | picks.push({ label: version });
33 | }
34 | }
35 | if (betas.length > 0) {
36 | picks.push({ label: 'Betas', kind: QuickPickItemKind.Separator });
37 | for (const version of betas) {
38 | picks.push({ label: version });
39 | }
40 | }
41 | const selection: QuickPickItem = await window.showQuickPick(picks, {
42 | placeHolder: `Update to version of ${info.name}`,
43 | });
44 | if (!selection) return;
45 |
46 | const message = `Update ${info.name} to ${selection.label}`;
47 | await fixIssue(
48 | npmInstall(`${info.name}@${selection.label}`),
49 | folder,
50 | undefined,
51 | new Tip(message, undefined).showProgressDialog(),
52 | undefined,
53 | message,
54 | );
55 | return true;
56 | }
57 |
--------------------------------------------------------------------------------
/src/rules-web-project.ts:
--------------------------------------------------------------------------------
1 | import { exists } from './analyzer';
2 | import { InternalCommand } from './command-name';
3 | import { MonoRepoType } from './monorepo';
4 |
5 | import { npmInstall, npx } from './node-commands';
6 | import { Project } from './project';
7 | import { Tip, TipType } from './tip';
8 | import { asAppId } from './utilities';
9 | import { checkCapacitorPluginMigration } from './rules-capacitor-plugins';
10 | import { existsSync } from 'fs';
11 | import { join } from 'path';
12 |
13 | /**
14 | * Web projects are not using Capacitor or Cordova
15 | * @param {Project} project
16 | */
17 | export function webProject(project: Project) {
18 | let outFolder = 'www';
19 |
20 | // If there is a build folder and not a www folder then...
21 | if (!existsSync(join(project.projectFolder(), 'www'))) {
22 | if (existsSync(join(project.projectFolder(), 'build')) || exists('react')) {
23 | outFolder = 'build'; // use build folder (usually react)
24 | } else if (existsSync(join(project.projectFolder(), 'dist')) || exists('vue')) {
25 | outFolder = 'dist'; /// use dist folder (usually vue)
26 | }
27 | }
28 |
29 | const pre = project.repoType != MonoRepoType.none ? InternalCommand.cwd : '';
30 |
31 | if (project.isCapacitorPlugin) {
32 | checkCapacitorPluginMigration(project);
33 | }
34 |
35 | if (!project.isCapacitorPlugin) {
36 | project.tip(
37 | new Tip(
38 | 'Add Capacitor Integration',
39 | '',
40 | TipType.Capacitor,
41 | 'Integrate Capacitor with this project to make it native mobile?',
42 | [
43 | npmInstall(`@capacitor/core`),
44 | npmInstall(`@capacitor/cli`),
45 | npmInstall(`@capacitor/app @capacitor/haptics @capacitor/keyboard @capacitor/status-bar`),
46 | `${pre}${npx(project)} capacitor init "${project.name}" "${asAppId(project.name)}" --web-dir ${outFolder}`,
47 | InternalCommand.ionicInit,
48 | ],
49 | 'Add Capacitor',
50 | 'Capacitor added to this project',
51 | 'https://capacitorjs.com',
52 | ),
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/scripts.ts:
--------------------------------------------------------------------------------
1 | import { exists } from './analyzer';
2 | import { MonoRepoType } from './monorepo';
3 | import { npmRun } from './node-commands';
4 | import { Project } from './project';
5 | import { Tip, TipType } from './tip';
6 | import { getPackageJSON, PackageFile } from './utilities';
7 |
8 | // Look in package.json for scripts and add options to execute
9 | export function addScripts(project: Project) {
10 | const expand = !(exists('@capacitor/core') || exists('cordova-ios') || exists('cordova-android'));
11 | project.setGroup(`Scripts`, `The scripts from package.json`, TipType.Files, expand);
12 |
13 | addScriptsFrom(getPackageJSON(project.projectFolder()), project);
14 |
15 | if (project.repoType == MonoRepoType.nx) {
16 | addScriptsFrom(getPackageJSON(project.folder), project);
17 | addNXScripts(['build', 'test', 'lint', 'e2e'], project);
18 | }
19 | }
20 |
21 | function addScriptsFrom(packages: PackageFile, project: Project) {
22 | if (packages.scripts) {
23 | for (const script of Object.keys(packages.scripts)) {
24 | project.add(
25 | new Tip(script, '', TipType.Run, '', npmRun(script), `Running ${script}`, `Ran ${script}`)
26 | .canStop()
27 | .canAnimate()
28 | .setTooltip(`Runs 'npm run ${script}' found in package.json`),
29 | );
30 | }
31 | }
32 |
33 | // We may be able to migrate a Capacitor Plugin
34 | project.isCapacitorPlugin = !!(packages.capacitor?.ios || packages.capacitor?.android);
35 | }
36 |
37 | function addNXScripts(names: Array, project: Project) {
38 | for (const name of names) {
39 | project.add(
40 | new Tip(
41 | `${project.monoRepo.name} ${name}`,
42 | '',
43 | TipType.Run,
44 | '',
45 | `npx nx run ${project.monoRepo.name}:${name}`,
46 | `Running ${name}`,
47 | `Ran ${name}`,
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/source-map-server.ts:
--------------------------------------------------------------------------------
1 | import { writeIonic } from './logging';
2 | import { readFile } from 'fs';
3 | import { createServer } from 'http';
4 | import { extname, join } from 'path';
5 |
6 | export function startSourceMapServer(folder: string) {
7 | writeIonic('Starting source map server on port 80....');
8 | createServer((request, response) => {
9 | const filePath = join(folder, request.url);
10 | writeIonic(`Serving ${filePath}`);
11 |
12 | const ex = extname(filePath);
13 | const contentType = getMimeType(ex);
14 |
15 | readFile(filePath, (error, content) => {
16 | if (error) {
17 | if (error.code == 'ENOENT') {
18 | readFile('./404.html', function (error, content) {
19 | response.writeHead(200, { 'Content-Type': contentType });
20 | response.end(content, 'utf-8');
21 | });
22 | } else {
23 | response.writeHead(500);
24 | response.end('Oh bummer error: ' + error.code + ' ..\n');
25 | response.end();
26 | }
27 | } else {
28 | response.writeHead(200, { 'Content-Type': contentType });
29 | response.end(content, 'utf-8');
30 | }
31 | });
32 | }).listen(80);
33 | }
34 |
35 | function getMimeType(extname: string): string {
36 | switch (extname) {
37 | case '.js':
38 | return 'text/javascript';
39 | case '.css':
40 | return 'text/css';
41 | case '.json':
42 | return 'application/json';
43 | case '.png':
44 | return 'image/png';
45 | case '.jpg':
46 | return 'image/jpg';
47 | case '.wav':
48 | return 'audio/wav';
49 | }
50 | return 'text/html';
51 | }
52 |
--------------------------------------------------------------------------------
/src/web-configuration.ts:
--------------------------------------------------------------------------------
1 | import { commands, window } from 'vscode';
2 | import { getSetting, setSetting, WorkspaceSetting } from './workspace-state';
3 | import { Context, VSCommand } from './context-variables';
4 |
5 | export enum WebConfigSetting {
6 | nexus = 'WebConfigNexusBrowser',
7 | browser = 'WebConfigWebBrowser',
8 | editor = 'WebConfigEditor',
9 | none = 'WebConfigNone',
10 | }
11 |
12 | export function getWebConfiguration(): WebConfigSetting {
13 | const setting = getSetting(WorkspaceSetting.webAction);
14 | if (setting) {
15 | return setting;
16 | } else {
17 | return WebConfigSetting.browser;
18 | }
19 | }
20 |
21 | export async function setWebConfig(setting: WebConfigSetting) {
22 | setSetting(WorkspaceSetting.webAction, setting);
23 | commands.executeCommand(VSCommand.setContext, Context.webConfig, setting);
24 | }
25 |
--------------------------------------------------------------------------------
/src/web-debug.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { getSetting, setSetting, WorkspaceSetting } from './workspace-state';
3 |
4 | export enum WebDebugSetting {
5 | edge = 'pwa-msedge',
6 | chrome = 'chrome',
7 | }
8 |
9 | export function getWebDebugSetting(): WebDebugSetting {
10 | const setting = getSetting(WorkspaceSetting.debugBrowser);
11 | if (setting) {
12 | return setting;
13 | } else {
14 | return WebDebugSetting.edge;
15 | }
16 | }
17 |
18 | export async function webDebugSetting(): Promise {
19 | const setting = getSetting(WorkspaceSetting.debugBrowser);
20 | const configs = [
21 | check(WebDebugSetting.edge, setting, 'Microsoft Edge'),
22 | check(WebDebugSetting.chrome, setting, 'Google Chrome'),
23 | ];
24 |
25 | const selection = await window.showQuickPick(configs, {
26 | placeHolder: 'Select the debuggable Browser',
27 | });
28 | if (selection) {
29 | const value = selection.includes('Edge') ? WebDebugSetting.edge : WebDebugSetting.chrome;
30 | setSetting(WorkspaceSetting.debugBrowser, value);
31 | }
32 | }
33 |
34 | function check(msg: string, setting: string, title: string): string {
35 | if (msg === setting) {
36 | return title + ` $(check)`;
37 | }
38 | return title;
39 | }
40 |
--------------------------------------------------------------------------------
/src/workspace-state.ts:
--------------------------------------------------------------------------------
1 | import { workspace } from 'vscode';
2 | import { ionicState } from './ionic-tree-provider';
3 |
4 | export enum WorkspaceSetting {
5 | liveReload = 'liveReload',
6 | httpsForWeb = 'httpsForWeb',
7 | pluginDrift = 'pluginDrift', // Whether the user has been shown the plugin drift compared to NexusBrowser app
8 | webAction = 'webAction',
9 | logFilter = 'logFilter',
10 | tips = 'tipsShown',
11 | lastIPAddress = 'lastIPAddress',
12 | debugBrowser = 'debugBrowser',
13 | cocoaPods = 'cocoaPods2',
14 | }
15 |
16 | export enum ExtensionSetting {
17 | internalAddress = 'internalAddress',
18 | javaHome = 'javaHome',
19 | manualNewProjects = 'manualNewProjects',
20 | }
21 |
22 | export enum GlobalSetting {
23 | lastTipsShown = 'lastTipsShown',
24 | projectsFolder = 'projectsFolder',
25 | suggestNPMInstall = 'suggestNPMInstall',
26 | }
27 |
28 | export function getSetting(key: WorkspaceSetting): any {
29 | return ionicState.context.workspaceState.get(key);
30 | }
31 |
32 | export async function setSetting(key: WorkspaceSetting, value: any): Promise {
33 | await ionicState.context.workspaceState.update(key, value);
34 | }
35 |
36 | export function getExtSetting(key: ExtensionSetting): any {
37 | return workspace.getConfiguration('ionic').get(key);
38 | }
39 |
40 | export function getGlobalSetting(key: GlobalSetting): any {
41 | return ionicState.context.globalState.get(key);
42 | }
43 |
44 | export async function setGlobalSetting(key: GlobalSetting, value: any): Promise {
45 | return await ionicState.context.globalState.update(key, value);
46 | }
47 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es2019",
5 | "lib": ["ES2019", "DOM"],
6 | "outDir": "out",
7 | "allowSyntheticDefaultImports": true,
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "rootDir": "src"
11 | },
12 | "exclude": ["node_modules", "log-client", ".vscode-test", "plugin-explorer", "ionic-start"]
13 | }
14 |
--------------------------------------------------------------------------------