diff --git a/.vscode/launch.json b/.vscode/launch.json index 95b600ad..bb76b436 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -83,6 +83,27 @@ "smartStep": true, "internalConsoleOptions": "openOnSessionStart", "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "protocol": "inspector", + "name": "Run Test [current]", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "args": [ + "--require", + "reflect-metadata/Reflect", + "--no-timeouts", + "--colors", + "**/${fileBasenameNoExtension}.js" + ], + "env": { + "TS_NODE_PROJECT": "${workspaceRoot}/tsconfig.json" + }, + "sourceMaps": true, + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" } ] } diff --git a/arduino-debugger-extension/package.json b/arduino-debugger-extension/package.json index 6da8edb8..bdbf7499 100644 --- a/arduino-debugger-extension/package.json +++ b/arduino-debugger-extension/package.json @@ -26,8 +26,8 @@ ], "theiaExtensions": [ { - "backend": "lib/node/backend-module", - "frontend": "lib/browser/frontend-module" + "backend": "lib/node/arduino-debug-backend-module", + "frontend": "lib/browser/arduino-debug-frontend-module" } ] } diff --git a/arduino-debugger-extension/src/browser/frontend-module.ts b/arduino-debugger-extension/src/browser/arduino-debug-frontend-module.ts similarity index 99% rename from arduino-debugger-extension/src/browser/frontend-module.ts rename to arduino-debugger-extension/src/browser/arduino-debug-frontend-module.ts index 1270812a..792b2a12 100644 --- a/arduino-debugger-extension/src/browser/frontend-module.ts +++ b/arduino-debugger-extension/src/browser/arduino-debug-frontend-module.ts @@ -10,7 +10,6 @@ import { ArduinoDebugSessionManager } from './arduino-debug-session-manager'; import '../../src/browser/style/index.css'; - export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ArduinoVariableResolver).toSelf().inSingletonScope(); bind(VariableContribution).toService(ArduinoVariableResolver); diff --git a/arduino-debugger-extension/src/node/backend-module.ts b/arduino-debugger-extension/src/node/arduino-debug-backend-module.ts similarity index 100% rename from arduino-debugger-extension/src/node/backend-module.ts rename to arduino-debugger-extension/src/node/arduino-debug-backend-module.ts diff --git a/arduino-ide-extension/data/cli/schema/arduino-cli.schema.json b/arduino-ide-extension/data/cli/schema/arduino-cli.schema.json index d391fc8d..08a9490b 100644 --- a/arduino-ide-extension/data/cli/schema/arduino-cli.schema.json +++ b/arduino-ide-extension/data/cli/schema/arduino-cli.schema.json @@ -110,5 +110,8 @@ "additionalProperties": false } }, + "// TODOs": [ + "additionalProperties should be true. See the new telemetry entry" + ], "additionalProperties": false } diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 309ae64e..c73d4223 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -15,8 +15,8 @@ "lint": "tslint -c ./tslint.json --project ./tsconfig.json", "build": "tsc && ncp ./src/node/cli-protocol/ ./lib/node/cli-protocol/ && yarn lint", "watch": "tsc -w", - "test": "mocha \"./src/test/**/*.test.ts\"", - "test:watch": "mocha --watch --watch-files src \"./src/test/**/*.test.ts\"" + "test": "mocha \"./lib/test/**/*.test.js\"", + "test:watch": "mocha --watch --watch-files lib \"./lib/test/**/*.test.js\"" }, "dependencies": { "@grpc/grpc-js": "^0.6.18", @@ -79,18 +79,16 @@ "protoc": "1.0.4", "shelljs": "^0.8.3", "temp": "^0.9.1", - "ts-node": "^8.6.2", "uuid": "^3.2.1", "yargs": "^11.1.0" }, "mocha": { "require": [ - "ts-node/register", "reflect-metadata/Reflect" ], "reporter": "spec", "colors": true, - "watch-extensions": "ts,tsx", + "watch-extensions": "js", "timeout": 10000 }, "files": [ @@ -101,12 +99,12 @@ ], "theiaExtensions": [ { - "backend": "lib/node/arduino-backend-module", - "frontend": "lib/browser/arduino-frontend-module" + "backend": "lib/node/arduino-ide-backend-module", + "frontend": "lib/browser/arduino-ide-frontend-module" }, { "frontend": "lib/browser/menu/browser-arduino-menu-module", - "frontendElectron": "lib/electron-browser/electron-arduino-menu-module" + "frontendElectron": "lib/electron-browser/menu/electron-arduino-menu-module" } ] } diff --git a/arduino-ide-extension/src/browser/arduino-daemon-client-impl.ts b/arduino-ide-extension/src/browser/arduino-daemon-client-impl.ts index 697b1238..f638bee9 100644 --- a/arduino-ide-extension/src/browser/arduino-daemon-client-impl.ts +++ b/arduino-ide-extension/src/browser/arduino-daemon-client-impl.ts @@ -2,7 +2,7 @@ import { injectable, inject } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; import { Event, Emitter } from '@theia/core/lib/common/event'; import { MessageService } from '@theia/core/lib/common/message-service'; -import { ArduinoDaemonClient } from '../common/protocol/arduino-daemon'; +import { ArduinoDaemonClient } from '../common/protocol'; @injectable() export class ArduinoDaemonClientImpl implements ArduinoDaemonClient { diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index 26bf0fe6..1da26c29 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -5,9 +5,8 @@ import { EditorWidget } from '@theia/editor/lib/browser/editor-widget'; import { MessageService } from '@theia/core/lib/common/message-service'; import { CommandContribution, CommandRegistry, Command, CommandHandler } from '@theia/core/lib/common/command'; import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; -import { BoardsService } from '../common/protocol/boards-service'; +import { BoardsService, BoardsServiceClient, CoreService, Sketch, SketchesService, ToolOutputServiceClient } from '../common/protocol'; import { ArduinoCommands } from './arduino-commands'; -import { CoreService } from '../common/protocol/core-service'; import { BoardsServiceClientImpl } from './boards/boards-service-client-impl'; import { WorkspaceRootUriAwareCommandHandler, WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands'; import { SelectionService, MenuContribution, MenuModelRegistry, MAIN_MENU_BAR, MenuPath } from '@theia/core'; @@ -19,8 +18,6 @@ import { } from '@theia/core/lib/browser'; import { OpenFileDialogProps, FileDialogService } from '@theia/filesystem/lib/browser/file-dialog'; import { FileSystem, FileStat } from '@theia/filesystem/lib/common'; -import { Sketch, SketchesService } from '../common/protocol/sketches-service'; -import { ToolOutputServiceClient } from '../common/protocol/tool-output-service'; import { CommonCommands, CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution'; import { FileSystemCommands } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution'; import { FileDownloadCommands } from '@theia/filesystem/lib/browser/download/file-download-command-contribution'; @@ -45,6 +42,8 @@ import { ColorContribution } from '@theia/core/lib/browser/color-application-con import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; import { ArduinoDaemon } from '../common/protocol/arduino-daemon'; import { ConfigService } from '../common/protocol/config-service'; +import { BoardsConfigStore } from './boards/boards-config-store'; +import { MainMenuManager } from './menu/main-menu-manager'; export namespace ArduinoMenus { export const SKETCH = [...MAIN_MENU_BAR, '3_sketch']; @@ -75,7 +74,11 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut protected readonly toolOutputServiceClient: ToolOutputServiceClient; @inject(BoardsServiceClientImpl) - protected readonly boardsServiceClient: BoardsServiceClientImpl; + protected readonly boardsServiceClientImpl: BoardsServiceClientImpl; + + // Unused but do not remove it. It's required by DI, otherwise `init` method is not called. + @inject(BoardsServiceClient) + protected readonly boardsServiceClient: BoardsServiceClient; @inject(SelectionService) protected readonly selectionService: SelectionService; @@ -143,6 +146,12 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut @inject(ConfigService) protected readonly configService: ConfigService; + @inject(BoardsConfigStore) + protected readonly boardsConfigStore: BoardsConfigStore; + + @inject(MainMenuManager) + protected readonly mainMenuManager: MainMenuManager; + protected application: FrontendApplication; protected wsSketchCount: number = 0; // TODO: this does not belong here, does it? @@ -154,15 +163,10 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut text: BoardsConfig.Config.toString(config) }); } - this.boardsServiceClient.onBoardsConfigChanged(updateStatusBar); - updateStatusBar(this.boardsServiceClient.boardsConfig); + this.boardsServiceClientImpl.onBoardsConfigChanged(updateStatusBar); + updateStatusBar(this.boardsServiceClientImpl.boardsConfig); this.registerSketchesInMenu(this.menuRegistry); - - Promise.all([ - this.boardsService.getAttachedBoards(), - this.boardsService.getAvailablePorts() - ]).then(([{ boards }, { ports }]) => this.boardsServiceClient.tryReconnect(boards, ports)); } onStart(app: FrontendApplication): void { @@ -210,8 +214,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut render: () => , + boardsServiceClient={this.boardsServiceClientImpl} />, isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left', priority: 2 }); @@ -276,10 +279,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut }); registry.registerCommand(ArduinoCommands.TOGGLE_COMPILE_FOR_DEBUG, { - execute: () => { - this.editorMode.toggleCompileForDebug(); - this.editorMode.menuContentChanged.fire(); - }, + execute: () => this.editorMode.toggleCompileForDebug(), isToggled: () => this.editorMode.compileForDebug }); @@ -345,7 +345,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut execute: async () => { const boardsConfig = await this.boardsConfigDialog.open(); if (boardsConfig) { - this.boardsServiceClient.boardsConfig = boardsConfig; + this.boardsServiceClientImpl.boardsConfig = boardsConfig; } } }); @@ -377,18 +377,18 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut } try { - const { boardsConfig } = this.boardsServiceClient; + const { boardsConfig } = this.boardsServiceClientImpl; if (!boardsConfig || !boardsConfig.selectedBoard) { throw new Error('No boards selected. Please select a board.'); } if (!boardsConfig.selectedBoard.fqbn) { - throw new Error(`No core is installed for ${boardsConfig.selectedBoard.name}. Please install the board.`); + throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); } - // Reveal the Output view asynchronously (don't await it) + const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); this.outputContribution.openView({ reveal: true }); await this.coreService.compile({ - uri: uri.toString(), - board: boardsConfig.selectedBoard, + sketchUri: uri.toString(), + fqbn, optimizeForDebug: this.editorMode.compileForDebug }); } catch (e) { @@ -413,7 +413,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut } try { - const { boardsConfig } = this.boardsServiceClient; + const { boardsConfig } = this.boardsServiceClientImpl; if (!boardsConfig || !boardsConfig.selectedBoard) { throw new Error('No boards selected. Please select a board.'); } @@ -421,11 +421,14 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut if (!selectedPort) { throw new Error('No ports selected. Please select a port.'); } - // Reveal the Output view asynchronously (don't await it) + if (!boardsConfig.selectedBoard.fqbn) { + throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); + } this.outputContribution.openView({ reveal: true }); + const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); await this.coreService.upload({ - uri: uri.toString(), - board: boardsConfig.selectedBoard, + sketchUri: uri.toString(), + fqbn, port: selectedPort.address, optimizeForDebug: this.editorMode.compileForDebug }); diff --git a/arduino-ide-extension/src/browser/arduino-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts similarity index 93% rename from arduino-ide-extension/src/browser/arduino-frontend-module.ts rename to arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 98ce3f19..d444d55d 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -75,6 +75,9 @@ import { ArduinoFrontendConnectionStatusService, ArduinoApplicationConnectionSta import { FrontendConnectionStatusService, ApplicationConnectionStatusContribution } from '@theia/core/lib/browser/connection-status-service'; import { ConfigServiceClientImpl } from './config-service-client-impl'; import { CoreServiceClientImpl } from './core-service-client-impl'; +import { BoardsDetailsMenuUpdater } from './boards/boards-details-menu-updater'; +import { BoardsConfigStore } from './boards/boards-config-store'; +import { ILogger } from '@theia/core'; const ElementQueries = require('css-element-queries/src/ElementQueries'); @@ -144,12 +147,28 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un // Boards service client to receive and delegate notifications from the backend. bind(BoardsServiceClientImpl).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(BoardsServiceClientImpl); - bind(BoardsServiceClient).toDynamicValue(context => { + bind(BoardsServiceClient).toDynamicValue(async context => { const client = context.container.get(BoardsServiceClientImpl); + const service = context.container.get(BoardsService); + const [attachedBoards, availablePorts] = await Promise.all([ + service.getAttachedBoards(), + service.getAvailablePorts() + ]); + client.init({ attachedBoards, availablePorts }); WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath, client); return client; }).inSingletonScope(); + // To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board. + bind(FrontendApplicationContribution).to(BoardsDetailsMenuUpdater).inSingletonScope(); + bind(BoardsConfigStore).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(BoardsConfigStore); + // Logger for the Arduino daemon + bind(ILogger).toDynamicValue(ctx => { + const parentLogger = ctx.container.get(ILogger); + return parentLogger.child('store'); + }).inSingletonScope().whenTargetNamed('store'); + // Boards auto-installer bind(BoardsAutoInstaller).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(BoardsAutoInstaller); diff --git a/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts index 8581b6f3..cb0c340d 100644 --- a/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts +++ b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts @@ -35,9 +35,9 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution { protected ensureCoreExists(config: BoardsConfig.Config): void { const { selectedBoard } = config; if (selectedBoard) { - this.boardsService.search({}).then(({ items }) => { - const candidates = items - .filter(item => item.boards.some(board => Board.sameAs(board, selectedBoard))) + this.boardsService.search({}).then(packages => { + const candidates = packages + .filter(pkg => pkg.boards.some(board => Board.sameAs(board, selectedBoard))) .filter(({ installable, installedVersion }) => installable && !installedVersion); for (const candidate of candidates) { // tslint:disable-next-line:max-line-length diff --git a/arduino-ide-extension/src/browser/boards/boards-config-quick-open-service.ts b/arduino-ide-extension/src/browser/boards/boards-config-quick-open-service.ts new file mode 100644 index 00000000..3220174b --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-config-quick-open-service.ts @@ -0,0 +1,43 @@ +import { inject, injectable } from 'inversify'; +import { QuickOpenItem, QuickOpenModel } from '@theia/core/lib/common/quick-open-model'; +import { QuickOpenService, QuickOpenOptions } from '@theia/core/lib/browser/quick-open/quick-open-service'; +import { BoardsService, BoardsServiceClient } from '../../common/protocol'; + +@injectable() +export class BoardsConfigQuickOpenService { + + @inject(QuickOpenService) + protected readonly quickOpenService: QuickOpenService; + + @inject(BoardsService) + protected readonly boardsService: BoardsService; + + @inject(BoardsServiceClient) + protected readonly boardsServiceClient: BoardsServiceClient; + + async selectBoard(): Promise { + + } + + protected open(items: QuickOpenItem | QuickOpenItem[], placeholder: string): void { + this.quickOpenService.open(this.getModel(Array.isArray(items) ? items : [items]), this.getOptions(placeholder)); + } + + protected getOptions(placeholder: string, fuzzyMatchLabel: boolean = true, onClose: (canceled: boolean) => void = () => { }): QuickOpenOptions { + return QuickOpenOptions.resolve({ + placeholder, + fuzzyMatchLabel, + fuzzySort: false, + onClose + }); + } + + protected getModel(items: QuickOpenItem | QuickOpenItem[]): QuickOpenModel { + return { + onType(_: string, acceptor: (items: QuickOpenItem[]) => void): void { + acceptor(Array.isArray(items) ? items : [items]); + } + }; + } + +} diff --git a/arduino-ide-extension/src/browser/boards/boards-config-store.ts b/arduino-ide-extension/src/browser/boards/boards-config-store.ts new file mode 100644 index 00000000..8967174c --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-config-store.ts @@ -0,0 +1,161 @@ +import { injectable, inject, named } from 'inversify'; +import { ILogger } from '@theia/core/lib/common/logger'; +import { MaybePromise } from '@theia/core/lib/common/types'; +import { Event, Emitter } from '@theia/core/lib/common/event'; +import { deepClone, notEmpty } from '@theia/core/lib/common/objects'; +import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser'; +import { BoardsService, ConfigOption, Installable, BoardDetails } from '../../common/protocol'; +import { BoardsServiceClientImpl } from './boards-service-client-impl'; + +@injectable() +export class BoardsConfigStore implements FrontendApplicationContribution { + + @inject(ILogger) + @named('store') + protected readonly logger: ILogger; + + @inject(BoardsService) + protected readonly boardsService: BoardsService; + + @inject(BoardsServiceClientImpl) + protected readonly boardsServiceClient: BoardsServiceClientImpl; + + @inject(LocalStorageService) + protected readonly storageService: LocalStorageService; + + protected readonly onChangedEmitter = new Emitter(); + + onStart(): void { + this.boardsServiceClient.onBoardsPackageInstalled(async ({ pkg }) => { + const { installedVersion: version } = pkg; + if (!version) { + return; + } + let shouldFireChanged = false; + for (const fqbn of pkg.boards.map(({ fqbn }) => fqbn).filter(notEmpty).filter(fqbn => !!fqbn)) { + const key = this.getStorageKey(fqbn, version); + let data = await this.storageService.getData(key); + if (!data || !data.length) { + const details = await this.getBoardDetailsSafe(fqbn); + if (details) { + data = details.configOptions; + if (data.length) { + await this.storageService.setData(key, data); + shouldFireChanged = true; + } + } + } + } + if (shouldFireChanged) { + this.fireChanged(); + } + }); + } + + get onChanged(): Event { + return this.onChangedEmitter.event; + } + + async appendConfigToFqbn( + fqbn: string, + boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { + + const configOptions = await this.getConfig(fqbn, boardsPackageVersion); + return ConfigOption.decorate(fqbn, configOptions); + } + + async getConfig( + fqbn: string, + boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { + + const version = await boardsPackageVersion; + if (!version) { + return []; + } + const key = this.getStorageKey(fqbn, version); + let configOptions = await this.storageService.getData(key, undefined); + if (configOptions) { + return configOptions; + } + + const details = await this.getBoardDetailsSafe(fqbn); + if (!details) { + return []; + } + + configOptions = details.configOptions; + await this.storageService.setData(key, configOptions); + return configOptions; + } + + async setSelected( + { fqbn, option, selectedValue }: { fqbn: string, option: string, selectedValue: string }, + boardsPackageVersion: MaybePromise = this.getBoardsPackageVersion(fqbn)): Promise { + + const configOptions = deepClone(await this.getConfig(fqbn, boardsPackageVersion)); + const configOption = configOptions.find(c => c.option === option); + if (!configOption) { + return false; + } + let updated = false; + for (const value of configOption.values) { + if (value.value === selectedValue) { + (value as any).selected = true; + updated = true; + } else { + (value as any).selected = false; + } + } + if (!updated) { + return false; + } + const version = await boardsPackageVersion; + if (!version) { + return false; + } + await this.setConfig({ fqbn, configOptions, version }); + this.fireChanged(); + return true; + } + + protected async setConfig( + { fqbn, configOptions, version }: { fqbn: string, configOptions: ConfigOption[], version: Installable.Version }): Promise { + + const key = this.getStorageKey(fqbn, version); + return this.storageService.setData(key, configOptions); + } + + protected getStorageKey(fqbn: string, version: Installable.Version): string { + return `.arduinoProIDE-configOptions-${version}-${fqbn}`; + } + + protected async getBoardDetailsSafe(fqbn: string): Promise { + try { + const details = this.boardsService.getBoardDetails({ fqbn }); + return details; + } catch (err) { + if (err instanceof Error && err.message.includes('loading board data') && err.message.includes('is not installed')) { + this.logger.warn(`The boards package is not installed for board with FQBN: ${fqbn}`); + } else { + this.logger.error(`An unexpected error occurred while retrieving the board details for ${fqbn}.`, err); + } + return undefined; + } + } + + protected fireChanged(): void { + this.onChangedEmitter.fire(); + } + + protected async getBoardsPackageVersion(fqbn: string): Promise { + if (!fqbn) { + return undefined; + } + const boardsPackage = await this.boardsService.getContainerBoardPackage({ fqbn }); + if (!boardsPackage) { + return undefined; + } + return boardsPackage.installedVersion; + } + +} diff --git a/arduino-ide-extension/src/browser/boards/boards-config.tsx b/arduino-ide-extension/src/browser/boards/boards-config.tsx index 04adbe98..59a380a9 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-config.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { DisposableCollection } from '@theia/core'; -import { BoardsService, Board, Port, AttachedSerialBoard, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service'; +import { BoardsService, Board, Port, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service'; import { BoardsServiceClientImpl } from './boards-service-client-impl'; import { CoreServiceClientImpl } from '../core-service-client-impl'; import { ArduinoDaemonClientImpl } from '../arduino-daemon-client-impl'; @@ -36,11 +36,11 @@ export abstract class Item extends React.Component<{ selected: boolean, onClick: (item: T) => void, missing?: boolean, - detail?: string + details?: string }> { render(): React.ReactNode { - const { selected, label, missing, detail } = this.props; + const { selected, label, missing, details } = this.props; const classNames = ['item']; if (selected) { classNames.push('selected'); @@ -48,11 +48,11 @@ export abstract class Item extends React.Component<{ if (missing === true) { classNames.push('missing') } - return
+ return
{label}
- {!detail ? '' :
{detail}
} + {!details ? '' :
{details}
} {!selected ? '' :
}
; } @@ -82,13 +82,15 @@ export class BoardsConfig extends React.Component this.updatePorts(ports)); + this.props.boardsService.getAvailablePorts().then(ports => this.updatePorts(ports)); const { boardsServiceClient, coreServiceClient, daemonClient } = this.props; this.toDispose.pushAll([ - boardsServiceClient.onBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)), + boardsServiceClient.onAttachedBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)), boardsServiceClient.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => { this.setState({ selectedBoard, selectedPort }, () => this.fireConfigChanged()); }), + boardsServiceClient.onBoardsPackageInstalled(() => this.updateBoards(this.state.query)), + boardsServiceClient.onBoardsPackageUninstalled(() => this.updateBoards(this.state.query)), coreServiceClient.onIndexUpdated(() => this.updateBoards(this.state.query)), daemonClient.onDaemonStarted(() => this.updateBoards(this.state.query)), daemonClient.onDaemonStopped(() => this.setState({ searchResults: [] })) @@ -110,11 +112,11 @@ export class BoardsConfig extends React.Component this.setState({ searchResults })); + this.queryBoards({ query }).then(searchResults => this.setState({ searchResults })); } protected updatePorts = (ports: Port[] = [], removedPorts: Port[] = []) => { - this.queryPorts(Promise.resolve({ ports })).then(({ knownPorts }) => { + this.queryPorts(Promise.resolve(ports)).then(({ knownPorts }) => { let { selectedPort } = this.state; // If the currently selected port is not available anymore, unset the selected port. if (removedPorts.some(port => Port.equals(port, selectedPort))) { @@ -124,35 +126,17 @@ export class BoardsConfig extends React.Component }> => { - const { boardsService } = this.props; - const query = (options.query || '').toLocaleLowerCase(); - return new Promise<{ searchResults: Array }>(resolve => { - boardsService.search(options) - .then(({ items }) => items - .map(item => item.boards.map(board => ({ ...board, packageName: item.name }))) - .reduce((acc, curr) => acc.concat(curr), []) - .filter(board => board.name.toLocaleLowerCase().indexOf(query) !== -1) - .sort(Board.compare)) - .then(searchResults => resolve({ searchResults })); - }); + protected queryBoards = (options: { query?: string } = {}): Promise> => { + return this.props.boardsService.searchBoards(options); } - protected get attachedBoards(): Promise<{ boards: Board[] }> { - return this.props.boardsService.getAttachedBoards(); - } - - protected get availablePorts(): Promise<{ ports: Port[] }> { + protected get availablePorts(): Promise { return this.props.boardsService.getAvailablePorts(); } - protected queryPorts = (availablePorts: Promise<{ ports: Port[] }> = this.availablePorts) => { - return new Promise<{ knownPorts: Port[] }>(resolve => { - availablePorts - .then(({ ports }) => ports - .sort(Port.compare)) - .then(knownPorts => resolve({ knownPorts })); - }); + protected queryPorts = async (availablePorts: Promise = this.availablePorts) => { + const ports = await availablePorts; + return { knownPorts: ports.sort(Port.compare) }; } protected toggleFilterPorts = () => { @@ -194,41 +178,20 @@ export class BoardsConfig extends React.Component(); - for (const { name } of searchResults) { - const counter = distinctBoardNames.get(name) || 0; - distinctBoardNames.set(name, counter + 1); - } - - // Due to the non-unique board names, we have to check the package name as well. - const selected = (board: Board & { packageName: string }) => { - if (!!selectedBoard) { - if (Board.equals(board, selectedBoard)) { - if ('packageName' in selectedBoard) { - return board.packageName === (selectedBoard as any).packageName; - } - return true; - } - } - return false; - } - return
- {this.state.searchResults.map(board => + {Board.decorateBoards(selectedBoard, searchResults).map(board => key={`${board.name}-${board.packageName}`} item={board} label={board.name} - detail={(distinctBoardNames.get(board.name) || 0) > 1 ? ` - ${board.packageName}` : undefined} - selected={selected(board)} + details={board.details} + selected={board.selected} onClick={this.selectBoard} - missing={!Board.installed(board)} + missing={board.missing} />)}
; @@ -276,9 +239,9 @@ export namespace BoardsConfig { export namespace Config { - export function sameAs(config: Config, other: Config | AttachedSerialBoard): boolean { + export function sameAs(config: Config, other: Config | Board): boolean { const { selectedBoard, selectedPort } = config; - if (AttachedSerialBoard.is(other)) { + if (Board.is(other)) { return !!selectedBoard && Board.equals(other, selectedBoard) && Port.sameAs(selectedPort, other.port); diff --git a/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts b/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts new file mode 100644 index 00000000..8fcaa66b --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-details-menu-updater.ts @@ -0,0 +1,90 @@ +import { inject, injectable } from 'inversify'; +import { CommandRegistry } from '@theia/core/lib/common/command'; +import { MenuModelRegistry, MenuNode } from '@theia/core/lib/common/menu'; +import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable'; +import { BoardsServiceClientImpl } from './boards-service-client-impl'; +import { Board, ConfigOption } from '../../common/protocol'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { ArduinoMenus } from '../arduino-frontend-contribution'; +import { BoardsConfigStore } from './boards-config-store'; +import { MainMenuManager } from '../menu/main-menu-manager'; + +@injectable() +export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution { + + @inject(CommandRegistry) + protected readonly commandRegistry: CommandRegistry; + + @inject(MenuModelRegistry) + protected readonly menuRegistry: MenuModelRegistry; + + @inject(MainMenuManager) + protected readonly mainMenuManager: MainMenuManager; + + @inject(BoardsConfigStore) + protected readonly boardsConfigStore: BoardsConfigStore; + + @inject(BoardsServiceClientImpl) + protected readonly boardsServiceClient: BoardsServiceClientImpl; + + protected readonly toDisposeOnBoardChange = new DisposableCollection(); + + onStart(): void { + this.boardsConfigStore.onChanged(() => this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard)); + this.boardsServiceClient.onBoardsConfigChanged(({ selectedBoard }) => this.updateMenuActions(selectedBoard)); + this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard); + } + + protected async updateMenuActions(selectedBoard: Board | undefined): Promise { + if (selectedBoard) { + this.toDisposeOnBoardChange.dispose(); + this.mainMenuManager.update(); + const { fqbn } = selectedBoard; + if (fqbn) { + const configOptions = await this.boardsConfigStore.getConfig(fqbn); + const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z_boardsConfig']; // `z_` is for ordering. + for (const { label, option, values } of configOptions.sort(ConfigOption.LABEL_COMPARATOR)) { + const menuPath = [...boardsConfigMenuPath, `${option}`]; + const commands = new Map() + for (const value of values) { + const id = `${fqbn}-${option}--${value.value}`; + const command = { id, label: value.label }; + const selectedValue = value.value; + const handler = { + execute: () => this.boardsConfigStore.setSelected({ fqbn, option, selectedValue }), + isToggled: () => value.selected + }; + commands.set(id, this.commandRegistry.registerCommand(command, handler)); + } + this.menuRegistry.registerSubmenu(menuPath, label); + this.toDisposeOnBoardChange.pushAll([ + ...commands.values(), + Disposable.create(() => this.unregisterSubmenu(menuPath)), // We cannot dispose submenu entries: https://github.com/eclipse-theia/theia/issues/7299 + ...Array.from(commands.keys()).map((commandId, index) => { + this.menuRegistry.registerMenuAction(menuPath, { commandId, order: String(index) }) + return Disposable.create(() => this.menuRegistry.unregisterMenuAction(commandId)) + }) + ]); + } + this.mainMenuManager.update(); + } + } + } + + protected unregisterSubmenu(menuPath: string[]): void { + if (menuPath.length < 2) { + throw new Error(`Expected at least two item as a menu-path. Got ${JSON.stringify(menuPath)} instead.`); + } + const toRemove = menuPath[menuPath.length - 1]; + const parentMenuPath = menuPath.slice(0, menuPath.length - 1); + // This is unsafe. Calling `getMenu` with a non-existing menu-path will result in a new menu creation. + // https://github.com/eclipse-theia/theia/issues/7300 + const parent = this.menuRegistry.getMenu(parentMenuPath); + const index = parent.children.findIndex(({ id }) => id === toRemove); + if (index === -1) { + throw new Error(`Could not find menu with menu-path: ${JSON.stringify(menuPath)}.`); + } + (parent.children as Array).splice(index, 1); + } + +} diff --git a/arduino-ide-extension/src/browser/boards/boards-list-widget.ts b/arduino-ide-extension/src/browser/boards/boards-list-widget.ts index 0caf24b0..54947d62 100644 --- a/arduino-ide-extension/src/browser/boards/boards-list-widget.ts +++ b/arduino-ide-extension/src/browser/boards/boards-list-widget.ts @@ -1,17 +1,17 @@ import { inject, injectable } from 'inversify'; -import { BoardPackage, BoardsService } from '../../common/protocol/boards-service'; +import { BoardsPackage, BoardsService } from '../../common/protocol/boards-service'; import { ListWidget } from '../components/component-list/list-widget'; import { ListItemRenderer } from '../components/component-list/list-item-renderer'; @injectable() -export class BoardsListWidget extends ListWidget { +export class BoardsListWidget extends ListWidget { static WIDGET_ID = 'boards-list-widget'; static WIDGET_LABEL = 'Boards Manager'; constructor( @inject(BoardsService) protected service: BoardsService, - @inject(ListItemRenderer) protected itemRenderer: ListItemRenderer) { + @inject(ListItemRenderer) protected itemRenderer: ListItemRenderer) { super({ id: BoardsListWidget.WIDGET_ID, @@ -19,7 +19,7 @@ export class BoardsListWidget extends ListWidget { iconClass: 'fa fa-microchip', searchable: service, installable: service, - itemLabel: (item: BoardPackage) => item.name, + itemLabel: (item: BoardsPackage) => item.name, itemRenderer }); } diff --git a/arduino-ide-extension/src/browser/boards/boards-service-client-impl.ts b/arduino-ide-extension/src/browser/boards/boards-service-client-impl.ts index 60309f9c..b9970c06 100644 --- a/arduino-ide-extension/src/browser/boards/boards-service-client-impl.ts +++ b/arduino-ide-extension/src/browser/boards/boards-service-client-impl.ts @@ -1,11 +1,11 @@ -import { injectable, inject } from 'inversify'; +import { injectable, inject, optional } from 'inversify'; import { Emitter } from '@theia/core/lib/common/event'; import { ILogger } from '@theia/core/lib/common/logger'; import { MessageService } from '@theia/core/lib/common/message-service'; -import { LocalStorageService } from '@theia/core/lib/browser/storage-service'; +import { StorageService } from '@theia/core/lib/browser/storage-service'; import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; import { RecursiveRequired } from '../../common/types'; -import { BoardsServiceClient, AttachedBoardsChangeEvent, BoardInstalledEvent, AttachedSerialBoard, Board, Port, BoardUninstalledEvent } from '../../common/protocol/boards-service'; +import { BoardsServiceClient, AttachedBoardsChangeEvent, BoardInstalledEvent, Board, Port, BoardUninstalledEvent } from '../../common/protocol'; import { BoardsConfig } from './boards-config'; @injectable() @@ -14,16 +14,18 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp @inject(ILogger) protected logger: ILogger; + @optional() @inject(MessageService) protected messageService: MessageService; - @inject(LocalStorageService) - protected storageService: LocalStorageService; + @inject(StorageService) + protected storageService: StorageService; - protected readonly onBoardInstalledEmitter = new Emitter(); - protected readonly onBoardUninstalledEmitter = new Emitter(); + protected readonly onBoardsPackageInstalledEmitter = new Emitter(); + protected readonly onBoardsPackageUninstalledEmitter = new Emitter(); protected readonly onAttachedBoardsChangedEmitter = new Emitter(); - protected readonly onSelectedBoardsConfigChangedEmitter = new Emitter(); + protected readonly onBoardsConfigChangedEmitter = new Emitter(); + protected readonly onAvailableBoardsChangedEmitter = new Emitter(); /** * Used for the auto-reconnecting. Sometimes, the attached board gets disconnected after uploading something to it. @@ -34,35 +36,51 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp */ protected latestValidBoardsConfig: RecursiveRequired | undefined = undefined; protected _boardsConfig: BoardsConfig.Config = {}; + protected _attachedBoards: Board[] = []; // This does not contain the `Unknown` boards. They're visible from the available ports only. + protected _availablePorts: Port[] = []; + protected _availableBoards: AvailableBoard[] = []; - readonly onBoardsChanged = this.onAttachedBoardsChangedEmitter.event; - readonly onBoardInstalled = this.onBoardInstalledEmitter.event; - readonly onBoardUninstalled = this.onBoardUninstalledEmitter.event; - readonly onBoardsConfigChanged = this.onSelectedBoardsConfigChangedEmitter.event; + /** + * Event when the state of the attached/detached boards has changed. For instance, the user have detached a physical board. + */ + readonly onAttachedBoardsChanged = this.onAttachedBoardsChangedEmitter.event; + readonly onBoardsPackageInstalled = this.onBoardsPackageInstalledEmitter.event; + readonly onBoardsPackageUninstalled = this.onBoardsPackageUninstalledEmitter.event; + /** + * Unlike `onAttachedBoardsChanged` this even fires when the user modifies the selected board in the IDE.\ + * This even also fires, when the boards package was not available for the currently selected board, + * and the user installs the board package. Note: installing a board package will set the `fqbn` of the + * currently selected board.\ + * This even also emitted when the board package for the currently selected board was uninstalled. + */ + readonly onBoardsConfigChanged = this.onBoardsConfigChangedEmitter.event; + readonly onAvailableBoardsChanged = this.onAvailableBoardsChangedEmitter.event; async onStart(): Promise { return this.loadState(); } - notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void { - this.logger.info('Attached boards and available ports changed: ', JSON.stringify(event)); - const { detached, attached } = AttachedBoardsChangeEvent.diff(event); - const { selectedPort, selectedBoard } = this.boardsConfig; - this.onAttachedBoardsChangedEmitter.fire(event); - // Dynamically unset the port if is not available anymore. A port can be "detached" when removing a board. - if (detached.ports.some(port => Port.equals(selectedPort, port))) { - this.boardsConfig = { - selectedBoard, - selectedPort: undefined - }; - } - // Try to reconnect. - this.tryReconnect(attached.boards, attached.ports); + /** + * When the FE connects to the BE, the BE stets the known boards and ports.\ + * This is a DI workaround for not being able to inject the service into the client. + */ + init({ attachedBoards, availablePorts }: { attachedBoards: Board[], availablePorts: Port[] }): void { + this._attachedBoards = attachedBoards; + this._availablePorts = availablePorts; + this.reconcileAvailableBoards().then(() => this.tryReconnect()); } - async tryReconnect(attachedBoards: Board[], availablePorts: Port[]): Promise { + notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void { + this.logger.info('Attached boards and available ports changed: ', JSON.stringify(event)); + this._attachedBoards = event.newState.boards; + this.onAttachedBoardsChangedEmitter.fire(event); + this._availablePorts = event.newState.ports; + this.reconcileAvailableBoards().then(() => this.tryReconnect()); + } + + protected async tryReconnect(): Promise { if (this.latestValidBoardsConfig && !this.canUploadTo(this.boardsConfig)) { - for (const board of attachedBoards.filter(AttachedSerialBoard.is)) { + for (const board of this.availableBoards.filter(({ state }) => state !== AvailableBoard.State.incomplete)) { if (this.latestValidBoardsConfig.selectedBoard.fqbn === board.fqbn && this.latestValidBoardsConfig.selectedBoard.name === board.name && Port.sameAs(this.latestValidBoardsConfig.selectedPort, board.port)) { @@ -73,13 +91,13 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp } // If we could not find an exact match, we compare the board FQBN-name pairs and ignore the port, as it might have changed. // See documentation on `latestValidBoardsConfig`. - for (const board of attachedBoards.filter(AttachedSerialBoard.is)) { + for (const board of this.availableBoards.filter(({ state }) => state !== AvailableBoard.State.incomplete)) { if (this.latestValidBoardsConfig.selectedBoard.fqbn === board.fqbn && this.latestValidBoardsConfig.selectedBoard.name === board.name) { this.boardsConfig = { ...this.latestValidBoardsConfig, - selectedPort: availablePorts.find(port => Port.sameAs(port, board.port)) + selectedPort: board.port }; return true; } @@ -90,21 +108,52 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp notifyBoardInstalled(event: BoardInstalledEvent): void { this.logger.info('Board installed: ', JSON.stringify(event)); - this.onBoardInstalledEmitter.fire(event); + this.onBoardsPackageInstalledEmitter.fire(event); + const { selectedBoard } = this.boardsConfig; + const { installedVersion, id } = event.pkg; + if (selectedBoard) { + const installedBoard = event.pkg.boards.find(({ name }) => name === selectedBoard.name); + if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) { + this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`); + this.boardsConfig = { + ...this.boardsConfig, + selectedBoard: installedBoard + }; + } + } } notifyBoardUninstalled(event: BoardUninstalledEvent): void { this.logger.info('Board uninstalled: ', JSON.stringify(event)); - this.onBoardUninstalledEmitter.fire(event); + this.onBoardsPackageUninstalledEmitter.fire(event); + const { selectedBoard } = this.boardsConfig; + if (selectedBoard && selectedBoard.fqbn) { + const uninstalledBoard = event.pkg.boards.find(({ name }) => name === selectedBoard.name); + if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) { + this.logger.info(`Board package ${event.pkg.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`); + const selectedBoardWithoutFqbn = { + name: selectedBoard.name + // No FQBN + }; + this.boardsConfig = { + ...this.boardsConfig, + selectedBoard: selectedBoardWithoutFqbn + }; + } + } } set boardsConfig(config: BoardsConfig.Config) { + this.doSetBoardsConfig(config); + this.saveState().finally(() => this.reconcileAvailableBoards().finally(() => this.onBoardsConfigChangedEmitter.fire(this._boardsConfig))); + } + + protected doSetBoardsConfig(config: BoardsConfig.Config): void { this.logger.info('Board config changed: ', JSON.stringify(config)); this._boardsConfig = config; if (this.canUploadTo(this._boardsConfig)) { this.latestValidBoardsConfig = this._boardsConfig; } - this.saveState().then(() => this.onSelectedBoardsConfigChangedEmitter.fire(this._boardsConfig)); } get boardsConfig(): BoardsConfig.Config { @@ -123,7 +172,7 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp } if (!config.selectedBoard) { - if (!options.silent) { + if (!options.silent && this.messageService) { this.messageService.warn('No boards selected.', { timeout: 3000 }); } return false; @@ -133,7 +182,7 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp } /** - * `true` if the `canVerify` and the `config.selectedPort` is also set with FQBN, hence can upload to board. Otherwise, `false`. + * `true` if `canVerify`, the board has an FQBN and the `config.selectedPort` is also set, hence can upload to board. Otherwise, `false`. */ canUploadTo( config: BoardsConfig.Config | undefined = this.boardsConfig, @@ -145,14 +194,14 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp const { name } = config.selectedBoard; if (!config.selectedPort) { - if (!options.silent) { + if (!options.silent && this.messageService) { this.messageService.warn(`No ports selected for board: '${name}'.`, { timeout: 3000 }); } return false; } if (!config.selectedBoard.fqbn) { - if (!options.silent) { + if (!options.silent && this.messageService) { this.messageService.warn(`The FQBN is not available for the selected board ${name}. Do you have the corresponding core installed?`, { timeout: 3000 }); } return false; @@ -161,8 +210,93 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp return true; } - protected saveState(): Promise { - return this.storageService.setData('latest-valid-boards-config', this.latestValidBoardsConfig); + get availableBoards(): AvailableBoard[] { + return this._availableBoards; + } + + protected async reconcileAvailableBoards(): Promise { + const attachedBoards = this._attachedBoards; + const availablePorts = this._availablePorts; + // Unset the port on the user's config, if it is not available anymore. + if (this.boardsConfig.selectedPort && !availablePorts.some(port => Port.sameAs(port, this.boardsConfig.selectedPort))) { + this.doSetBoardsConfig({ selectedBoard: this.boardsConfig.selectedBoard, selectedPort: undefined }); + this.onBoardsConfigChangedEmitter.fire(this._boardsConfig); + } + const boardsConfig = this.boardsConfig; + const currentAvailableBoards = this._availableBoards; + const availableBoards: AvailableBoard[] = []; + const availableBoardPorts = availablePorts.filter(Port.isBoardPort); + const attachedSerialBoards = attachedBoards.filter(({ port }) => !!port); + + for (const boardPort of availableBoardPorts) { + let state = AvailableBoard.State.incomplete; // Initial pessimism. + let board = attachedSerialBoards.find(({ port }) => Port.sameAs(boardPort, port)); + if (board) { + state = AvailableBoard.State.recognized; + } else { + // If the selected board is not recognized because it is a 3rd party board: https://github.com/arduino/arduino-cli/issues/623 + // We still want to show it without the red X in the boards toolbar: https://github.com/arduino/arduino-pro-ide/issues/198#issuecomment-599355836 + const lastSelectedBoard = await this.getLastSelectedBoardOnPort(boardPort); + if (lastSelectedBoard) { + board = { + ...lastSelectedBoard, + port: boardPort + }; + state = AvailableBoard.State.guessed; + } + } + if (!board) { + availableBoards.push({ name: 'Unknown', port: boardPort, state }); + } else { + const selected = BoardsConfig.Config.sameAs(boardsConfig, board); + availableBoards.push({ ...board, state, selected, port: boardPort }); + } + } + + if (boardsConfig.selectedBoard && !availableBoards.some(({ selected }) => selected)) { + availableBoards.push({ + ...boardsConfig.selectedBoard, + port: boardsConfig.selectedPort, + selected: true, + state: AvailableBoard.State.incomplete + }); + } + + const sortedAvailableBoards = availableBoards.sort(AvailableBoard.COMPARATOR); + let hasChanged = sortedAvailableBoards.length !== currentAvailableBoards.length; + for (let i = 0; !hasChanged && i < sortedAvailableBoards.length; i++) { + hasChanged = AvailableBoard.COMPARATOR(sortedAvailableBoards[i], currentAvailableBoards[i]) !== 0; + } + if (hasChanged) { + this._availableBoards = sortedAvailableBoards; + this.onAvailableBoardsChangedEmitter.fire(this._availableBoards); + } + } + + protected async getLastSelectedBoardOnPort(port: Port | string | undefined): Promise { + if (!port) { + return undefined; + } + const key = this.getLastSelectedBoardOnPortKey(port); + return this.storageService.getData(key); + } + + protected async saveState(): Promise { + // We save the port with the selected board name/FQBN, to be able to guess a better board name. + // Required when the attached board belongs to a 3rd party boards package, and neither the name, nor + // the FQBN can be retrieved with a `board list` command. + // https://github.com/arduino/arduino-cli/issues/623 + const { selectedBoard, selectedPort } = this.boardsConfig; + if (selectedBoard && selectedPort) { + const key = this.getLastSelectedBoardOnPortKey(selectedPort); + await this.storageService.setData(key, selectedBoard); + } + await this.storageService.setData('latest-valid-boards-config', this.latestValidBoardsConfig); + } + + protected getLastSelectedBoardOnPortKey(port: Port | string): string { + // TODO: we lose the port's `protocol` info (`serial`, `network`, etc.) here if the `port` is a `string`. + return `last-selected-board-on-port:${typeof port === 'string' ? port : Port.toString(port)}`; } protected async loadState(): Promise { @@ -176,3 +310,63 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp } } + +/** + * Representation of a ready-to-use board, configured by the user. Not all of the available boards are + * necessarily recognized by the CLI (e.g.: it is a 3rd party board) or correctly configured but ready for `verify`. + * If it has the selected board and a associated port, it can be used for `upload`. + */ +export interface AvailableBoard extends Board { + readonly state: AvailableBoard.State; + readonly selected?: boolean; + readonly port?: Port; +} + +export namespace AvailableBoard { + + export enum State { + /** + * Retrieved from the CLI via the `board list` command. + */ + 'recognized', + /** + * Guessed the name/FQBN of the board from the available board ports (3rd party). + */ + 'guessed', + /** + * We do not know anything about this board, probably a 3rd party. The user has not selected a board for this port yet. + */ + 'incomplete' + } + + export function isWithPort(board: AvailableBoard): board is AvailableBoard & { port: Port } { + return !!board.port; + } + + export const COMPARATOR = (left: AvailableBoard, right: AvailableBoard) => { + let result = left.name.localeCompare(right.name); + if (result !== 0) { + return result; + } + if (left.fqbn && right.fqbn) { + result = left.name.localeCompare(right.name); + if (result !== 0) { + return result; + } + } + if (left.port && right.port) { + result = Port.compare(left.port, right.port); + if (result !== 0) { + return result; + } + } + if (!!left.selected && !right.selected) { + return -1; + } + if (!!right.selected && !left.selected) { + return 1; + } + return left.state - right.state; + } + +} diff --git a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx index 7afea70e..a24c7882 100644 --- a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { CommandRegistry, DisposableCollection } from '@theia/core'; -import { BoardsService, Board, AttachedSerialBoard, Port } from '../../common/protocol/boards-service'; -import { ArduinoCommands } from '../arduino-commands'; -import { BoardsServiceClientImpl } from './boards-service-client-impl'; +import { CommandRegistry } from '@theia/core/lib/common/command'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Port } from '../../common/protocol'; import { BoardsConfig } from './boards-config'; +import { ArduinoCommands } from '../arduino-commands'; +import { BoardsServiceClientImpl, AvailableBoard } from './boards-service-client-impl'; export interface BoardsDropDownListCoords { readonly top: number; @@ -16,14 +17,9 @@ export interface BoardsDropDownListCoords { export namespace BoardsDropDown { export interface Props { readonly coords: BoardsDropDownListCoords | 'hidden'; - readonly items: Item[]; + readonly items: Array void, port: Port }>; readonly openBoardsConfig: () => void; } - export interface Item { - readonly label: string; - readonly selected: boolean; - readonly onClick: () => void; - } } export class BoardsDropDown extends React.Component { @@ -51,48 +47,30 @@ export class BoardsDropDown extends React.Component { if (coords === 'hidden') { return ''; } - items.push({ - label: 'Select Other Board & Port', - selected: false, - onClick: () => this.props.openBoardsConfig() - }) return
- {items.map(this.renderItem)} + {this.renderItem({ + label: 'Select Other Board & Port', + onClick: () => this.props.openBoardsConfig() + })} + {items.map(({ name, port, selected, onClick }) => ({ label: `${name} at ${Port.toString(port)}`, selected, onClick })).map(this.renderItem)}
} - protected renderItem(item: BoardsDropDown.Item): React.ReactNode { - const { label, selected, onClick } = item; + protected renderItem({ label, selected, onClick }: { label: string, selected?: boolean, onClick: () => void }): React.ReactNode { return
{label}
- {selected ? : ''} + {selected ? : ''}
} } -export namespace BoardsToolBarItem { - - export interface Props { - readonly boardService: BoardsService; - readonly boardsServiceClient: BoardsServiceClientImpl; - readonly commands: CommandRegistry; - } - - export interface State { - boardsConfig: BoardsConfig.Config; - attachedBoards: Board[]; - availablePorts: Port[]; - coords: BoardsDropDownListCoords | 'hidden'; - } -} - export class BoardsToolBarItem extends React.Component { static TOOLBAR_ID: 'boards-toolbar'; @@ -102,10 +80,9 @@ export class BoardsToolBarItem extends React.Component this.setState({ boardsConfig })), - client.onBoardsChanged(({ newState }) => this.setState({ attachedBoards: newState.boards, availablePorts: newState.ports })) - ]); - Promise.all([ - boardService.getAttachedBoards(), - boardService.getAvailablePorts() - ]).then(([{boards: attachedBoards}, { ports: availablePorts }]) => { - this.setState({ attachedBoards, availablePorts }) - }); + this.props.boardsServiceClient.onAvailableBoardsChanged(availableBoards => this.setState({ availableBoards })); } componentWillUnmount(): void { @@ -146,7 +113,7 @@ export class BoardsToolBarItem extends React.Component availablePorts.some(port => Port.sameAs(port, board.port))) - .filter(board => BoardsConfig.Config.sameAs(boardsConfig, board)).shift(); - - const items = attachedBoards.filter(AttachedSerialBoard.is).map(board => ({ - label: `${board.name} at ${board.port}`, - selected: configuredBoard === board, - onClick: () => { - this.props.boardsServiceClient.boardsConfig = { - selectedBoard: board, - selectedPort: availablePorts.find(port => Port.sameAs(port, board.port)) - } + const decorator = (() => { + const selectedBoard = availableBoards.find(({ selected }) => selected); + if (!selectedBoard || !selectedBoard.port) { + return 'fa fa-times notAttached' } - })); + if (selectedBoard.state === AvailableBoard.State.guessed) { + return 'fa fa-exclamation-triangle guessed' + } + return '' + })(); return
- +
{title}
- +
({ + ...board, + onClick: () => { + if (board.state === AvailableBoard.State.incomplete) { + this.props.boardsServiceClient.boardsConfig = { + selectedPort: board.port + }; + this.openDialog(); + } else { + this.props.boardsServiceClient.boardsConfig = { + selectedBoard: board, + selectedPort: board.port + } + } + } + }))} openBoardsConfig={this.openDialog}>
; @@ -200,3 +178,16 @@ export class BoardsToolBarItem extends React.Component { +export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendContribution { static readonly OPEN_MANAGER = `${BoardsListWidget.WIDGET_ID}:toggle`; diff --git a/arduino-ide-extension/src/browser/components/component-list/filterable-list-container.tsx b/arduino-ide-extension/src/browser/components/component-list/filterable-list-container.tsx index c3de4ad8..5b52720d 100644 --- a/arduino-ide-extension/src/browser/components/component-list/filterable-list-container.tsx +++ b/arduino-ide-extension/src/browser/components/component-list/filterable-list-container.tsx @@ -72,12 +72,7 @@ export class FilterableListContainer extends React.C protected search(query: string): void { const { searchable } = this.props; - searchable.search({ query: query.trim() }).then(result => { - const { items } = result; - this.setState({ - items: this.sort(items) - }); - }); + searchable.search({ query: query.trim() }).then(items => this.setState({ items: this.sort(items) })); } protected sort(items: T[]): T[] { @@ -91,7 +86,7 @@ export class FilterableListContainer extends React.C dialog.open(); try { await installable.install({ item, version }); - const { items } = await searchable.search({ query: this.state.filterText }); + const items = await searchable.search({ query: this.state.filterText }); this.setState({ items: this.sort(items) }); } finally { dialog.close(); @@ -113,7 +108,7 @@ export class FilterableListContainer extends React.C dialog.open(); try { await installable.uninstall({ item }); - const { items } = await searchable.search({ query: this.state.filterText }); + const items = await searchable.search({ query: this.state.filterText }); this.setState({ items: this.sort(items) }); } finally { dialog.close(); diff --git a/arduino-ide-extension/src/browser/editor-mode.ts b/arduino-ide-extension/src/browser/editor-mode.ts index c697edd4..2b9afb7e 100644 --- a/arduino-ide-extension/src/browser/editor-mode.ts +++ b/arduino-ide-extension/src/browser/editor-mode.ts @@ -1,16 +1,17 @@ -import { injectable } from 'inversify'; -import { Emitter } from '@theia/core/lib/common/event'; +import { injectable, inject } from 'inversify'; import { ApplicationShell, FrontendApplicationContribution, FrontendApplication, Widget } from '@theia/core/lib/browser'; -import { OutputWidget } from '@theia/output/lib/browser/output-widget'; import { EditorWidget } from '@theia/editor/lib/browser'; -import { ArduinoShellLayoutRestorer } from './shell/arduino-shell-layout-restorer'; +import { OutputWidget } from '@theia/output/lib/browser/output-widget'; +import { MainMenuManager } from './menu/main-menu-manager'; import { BoardsListWidget } from './boards/boards-list-widget'; import { LibraryListWidget } from './library/library-list-widget'; +import { ArduinoShellLayoutRestorer } from './shell/arduino-shell-layout-restorer'; @injectable() export class EditorMode implements FrontendApplicationContribution { - readonly menuContentChanged = new Emitter(); + @inject(MainMenuManager) + protected readonly mainMenuManager: MainMenuManager; protected app: FrontendApplication; @@ -62,6 +63,7 @@ export class EditorMode implements FrontendApplicationContribution { const oldState = this.compileForDebug; const newState = !oldState; window.localStorage.setItem(EditorMode.COMPILE_FOR_DEBUG_KEY, String(newState)); + this.mainMenuManager.update(); } } diff --git a/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts b/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts index b22fdf00..dd2176c6 100644 --- a/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts +++ b/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts @@ -2,7 +2,6 @@ import { injectable, inject, postConstruct } from 'inversify'; import { BaseLanguageClientContribution } from '@theia/languages/lib/browser'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; import { BoardsConfig } from '../boards/boards-config'; -import { Board, BoardPackage } from '../../common/protocol/boards-service'; @injectable() export class ArduinoLanguageClientContribution extends BaseLanguageClientContribution { @@ -26,18 +25,6 @@ export class ArduinoLanguageClientContribution extends BaseLanguageClientContrib @postConstruct() protected init() { this.boardsServiceClient.onBoardsConfigChanged(this.selectBoard.bind(this)); - const restartIfAffected = (pkg: BoardPackage) => { - if (!this.boardConfig) { - this.restart(); - return; - } - const { selectedBoard } = this.boardConfig; - if (selectedBoard && pkg.boards.some(board => Board.sameAs(board, selectedBoard))) { - this.restart(); - } - } - this.boardsServiceClient.onBoardInstalled(({ pkg }) => restartIfAffected(pkg)); - this.boardsServiceClient.onBoardUninstalled(({ pkg }) => restartIfAffected(pkg)); } selectBoard(config: BoardsConfig.Config): void { diff --git a/arduino-ide-extension/src/browser/menu/arduino-browser-main-menu-factory.ts b/arduino-ide-extension/src/browser/menu/arduino-browser-main-menu-factory.ts new file mode 100644 index 00000000..e7970c79 --- /dev/null +++ b/arduino-ide-extension/src/browser/menu/arduino-browser-main-menu-factory.ts @@ -0,0 +1,22 @@ +import { injectable } from 'inversify'; +import { BrowserMainMenuFactory, MenuBarWidget } from '@theia/core/lib/browser/menu/browser-menu-plugin'; +import { MainMenuManager } from './main-menu-manager'; + +@injectable() +export class ArduinoBrowserMainMenuFactory extends BrowserMainMenuFactory implements MainMenuManager { + + protected menuBar: MenuBarWidget | undefined; + + createMenuBar(): MenuBarWidget { + this.menuBar = super.createMenuBar(); + return this.menuBar; + } + + update() { + if (this.menuBar) { + this.menuBar.clearMenus(); + this.fillMenuBar(this.menuBar); + } + } + +} diff --git a/arduino-ide-extension/src/browser/menu/browser-arduino-menu-module.ts b/arduino-ide-extension/src/browser/menu/browser-arduino-menu-module.ts index 61c8d073..11fe0589 100644 --- a/arduino-ide-extension/src/browser/menu/browser-arduino-menu-module.ts +++ b/arduino-ide-extension/src/browser/menu/browser-arduino-menu-module.ts @@ -1,10 +1,14 @@ -import { BrowserMenuBarContribution } from '@theia/core/lib/browser/menu/browser-menu-plugin'; -import { ArduinoMenuContribution } from './arduino-menu-contribution'; -import { ContainerModule, interfaces } from 'inversify'; - import '../../../src/browser/style/browser-menu.css' +import { ContainerModule } from 'inversify'; +import { BrowserMenuBarContribution, BrowserMainMenuFactory } from '@theia/core/lib/browser/menu/browser-menu-plugin'; +import { MainMenuManager } from './main-menu-manager'; +import { ArduinoMenuContribution } from './arduino-menu-contribution'; +import { ArduinoBrowserMainMenuFactory } from './arduino-browser-main-menu-factory'; -export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind) => { - unbind(BrowserMenuBarContribution); - bind(BrowserMenuBarContribution).to(ArduinoMenuContribution).inSingletonScope(); + +export default new ContainerModule((bind, unbind, isBound, rebind) => { + bind(ArduinoBrowserMainMenuFactory).toSelf().inSingletonScope(); + bind(MainMenuManager).toService(ArduinoBrowserMainMenuFactory); + rebind(BrowserMainMenuFactory).toService(ArduinoBrowserMainMenuFactory); + rebind(BrowserMenuBarContribution).to(ArduinoMenuContribution).inSingletonScope(); }); diff --git a/arduino-ide-extension/src/browser/menu/main-menu-manager.ts b/arduino-ide-extension/src/browser/menu/main-menu-manager.ts new file mode 100644 index 00000000..868b88d7 --- /dev/null +++ b/arduino-ide-extension/src/browser/menu/main-menu-manager.ts @@ -0,0 +1,8 @@ +export const MainMenuManager = Symbol('MainMenuManager'); +export interface MainMenuManager { + /** + * Call this method if you have changed the content of the main menu (updated a toggle flag, removed/added new groups or menu items) + * and you want to re-render it from scratch. Works for electron too. + */ + update(): void; +} diff --git a/arduino-ide-extension/src/browser/monitor/monitor-connection.ts b/arduino-ide-extension/src/browser/monitor/monitor-connection.ts index 1f588f2f..e8986b4b 100644 --- a/arduino-ide-extension/src/browser/monitor/monitor-connection.ts +++ b/arduino-ide-extension/src/browser/monitor/monitor-connection.ts @@ -4,7 +4,7 @@ import { MessageService } from '@theia/core/lib/common/message-service'; import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; import { MonitorService, MonitorConfig, MonitorError, Status, MonitorReadEvent } from '../../common/protocol/monitor-service'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; -import { Port, Board, BoardsService, AttachedSerialBoard, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service'; +import { Port, Board, BoardsService, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service'; import { MonitorServiceClientImpl } from './monitor-service-client-impl'; import { BoardsConfig } from '../boards/boards-config'; import { MonitorModel } from './monitor-model'; @@ -110,12 +110,12 @@ export class MonitorConnection { } }); this.boardsServiceClient.onBoardsConfigChanged(this.handleBoardConfigChange.bind(this)); - this.boardsServiceClient.onBoardsChanged(event => { + this.boardsServiceClient.onAttachedBoardsChanged(event => { if (this.autoConnect && this.connected) { const { boardsConfig } = this.boardsServiceClient; if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) { const { attached } = AttachedBoardsChangeEvent.diff(event); - if (attached.boards.some(board => AttachedSerialBoard.is(board) && BoardsConfig.Config.sameAs(boardsConfig, board))) { + if (attached.boards.some(board => !!board.port && BoardsConfig.Config.sameAs(boardsConfig, board))) { const { selectedBoard: board, selectedPort: port } = boardsConfig; const { baudRate } = this.monitorModel; this.disconnect() @@ -225,7 +225,7 @@ export class MonitorConnection { if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) { // Instead of calling `getAttachedBoards` and filtering for `AttachedSerialBoard` we have to check the available ports. // The connected board might be unknown. See: https://github.com/arduino/arduino-pro-ide/issues/127#issuecomment-563251881 - this.boardsService.getAvailablePorts().then(({ ports }) => { + this.boardsService.getAvailablePorts().then(ports => { if (ports.some(port => Port.equals(port, boardsConfig.selectedPort))) { new Promise(resolve => { // First, disconnect if connected. diff --git a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx index c5b81873..2fb0916f 100644 --- a/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/monitor/monitor-widget.tsx @@ -178,7 +178,7 @@ export class MonitorWidget extends ReactWidget { this.monitorModel.lineEnding = option.value; } - protected readonly onChangeBaudRate = async (option: SelectOption) => { + protected readonly onChangeBaudRate = (option: SelectOption) => { this.monitorModel.baudRate = option.value; } diff --git a/arduino-ide-extension/src/browser/style/board-select-dialog.css b/arduino-ide-extension/src/browser/style/board-select-dialog.css index 9833fb62..72c251da 100644 --- a/arduino-ide-extension/src/browser/style/board-select-dialog.css +++ b/arduino-ide-extension/src/browser/style/board-select-dialog.css @@ -97,7 +97,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i { margin-left: auto; } -#select-board-dialog .selectBoardContainer .body .list .item .detail { +#select-board-dialog .selectBoardContainer .body .list .item .details { font-size: var(--theia-ui-font-size1); opacity: var(--theia-mod-disabled-opacity); width: 155px; /* used heuristics for the calculation */ @@ -169,6 +169,13 @@ button.theia-button.main { margin: 0 5px; } +.arduino-boards-toolbar-item-container .arduino-boards-toolbar-item .inner-container .guessed { + width: 10px; + height: 10px; + color: var(--theia-warningBackground); + margin: 0 5px; +} + .arduino-boards-toolbar-item-container { display: flex; align-items: center; diff --git a/arduino-ide-extension/src/browser/style/list-widget.css b/arduino-ide-extension/src/browser/style/list-widget.css index 3bc39438..ab65b4f0 100644 --- a/arduino-ide-extension/src/browser/style/list-widget.css +++ b/arduino-ide-extension/src/browser/style/list-widget.css @@ -46,7 +46,7 @@ See above: `.filterable-list-container .items-container > div:nth-child(odd|event)`. We have to increase `z-index` of the scroll-bar thumb. Otherwise, the thumb is not visible. https://github.com/arduino/arduino-pro-ide/issues/82 */ -.arduino-list-widget .ps__rail-y > .ps__thumb-y { +.arduino-list-widget .filterable-list-container .items-container .ps__rail-y { z-index: 1; } diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index d7f0b631..03638b05 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -2,7 +2,6 @@ import { isWindows, isOSX } from '@theia/core/lib/common/os'; import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory'; import { Searchable } from './searchable'; import { Installable } from './installable'; -import { Detailable } from './detailable'; import { ArduinoComponent } from './arduino-component'; const naturalCompare: (left: string, right: string) => number = require('string-natural-compare').caseInsensitive; @@ -22,21 +21,24 @@ export namespace AttachedBoardsChangeEvent { ports: Port[] } }> { - const diff = (left: T[], right: T[]) => { - return left.filter(item => right.indexOf(item) === -1); + // In `lefts` AND not in `rights`. + const diff = (lefts: T[], rights: T[], sameAs: (left: T, right: T) => boolean) => { + return lefts.filter(left => rights.findIndex(right => sameAs(left, right)) === -1); } const { boards: newBoards } = event.newState; const { boards: oldBoards } = event.oldState; const { ports: newPorts } = event.newState; const { ports: oldPorts } = event.oldState; + const boardSameAs = (left: Board, right: Board) => Board.sameAs(left, right); + const portSameAs = (left: Port, right: Port) => Port.sameAs(left, right); return { detached: { - boards: diff(oldBoards, newBoards), - ports: diff(oldPorts, newPorts) + boards: diff(oldBoards, newBoards, boardSameAs), + ports: diff(oldPorts, newPorts, portSameAs) }, attached: { - boards: diff(newBoards, oldBoards), - ports: diff(newPorts, oldPorts) + boards: diff(newBoards, oldBoards, boardSameAs), + ports: diff(newPorts, oldPorts, portSameAs) } }; } @@ -44,11 +46,11 @@ export namespace AttachedBoardsChangeEvent { } export interface BoardInstalledEvent { - readonly pkg: Readonly; + readonly pkg: Readonly; } export interface BoardUninstalledEvent { - readonly pkg: Readonly; + readonly pkg: Readonly; } export const BoardsServiceClient = Symbol('BoardsServiceClient'); @@ -60,9 +62,13 @@ export interface BoardsServiceClient { export const BoardsServicePath = '/services/boards-service'; export const BoardsService = Symbol('BoardsService'); -export interface BoardsService extends Installable, Searchable, Detailable, JsonRpcServer { - getAttachedBoards(): Promise<{ boards: Board[] }>; - getAvailablePorts(): Promise<{ ports: Port[] }>; +export interface BoardsService extends Installable, Searchable, JsonRpcServer { + getAttachedBoards(): Promise; + getAvailablePorts(): Promise; + getBoardDetails(options: { fqbn: string }): Promise; + getBoardPackage(options: { id: string }): Promise; + getContainerBoardPackage(options: { fqbn: string }): Promise; + searchBoards(options: { query?: string }): Promise>; } export interface Port { @@ -160,38 +166,114 @@ export namespace Port { return false; } - export function sameAs(left: Port | undefined, right: string | undefined) { + export function sameAs(left: Port | undefined, right: Port | string | undefined) { if (left && right) { if (left.protocol !== 'serial') { - console.log(`Unexpected protocol for port: ${JSON.stringify(left)}. Ignoring protocol, comparing addresses with ${right}.`); + console.log(`Unexpected protocol for 'left' port: ${JSON.stringify(left)}. Ignoring 'protocol', comparing 'addresses' with ${JSON.stringify(right)}.`); } - return left.address === right; + if (typeof right === 'string') { + return left.address === right; + } + if (right.protocol !== 'serial') { + console.log(`Unexpected protocol for 'right' port: ${JSON.stringify(right)}. Ignoring 'protocol', comparing 'addresses' with ${JSON.stringify(left)}.`); + } + return left.address === right.address; } return false; } } -export interface BoardPackage extends ArduinoComponent { - id: string; - boards: Board[]; +export interface BoardsPackage extends ArduinoComponent { + readonly id: string; + readonly boards: Board[]; } export interface Board { - name: string - fqbn?: string + readonly name: string; + readonly fqbn?: string; + readonly port?: Port; } -export interface BoardDetails extends Board { - fqbn: string; - - requiredTools: Tool[]; +export interface BoardDetails { + readonly fqbn: string; + readonly requiredTools: Tool[]; + readonly configOptions: ConfigOption[]; } export interface Tool { readonly packager: string; readonly name: string; - readonly version: string; + readonly version: Installable.Version; +} + +export interface ConfigOption { + readonly option: string; + readonly label: string; + readonly values: ConfigValue[]; +} +export namespace ConfigOption { + + /** + * Appends the configuration options to the `fqbn` argument. + * Throws an error if the `fqbn` does not have the `segment(':'segment)*` format. + * The provided output format is always segment(':'segment)*(':'option'='value(','option'='value)*)? + * Validation can be disabled with the `{ validation: false }` option. + */ + export function decorate(fqbn: string, configOptions: ConfigOption[], { validate } = { validate: true }): string { + if (validate) { + if (!isValidFqbn(fqbn)) { + throw new ConfigOptionError(`${fqbn} is not a valid FQBN.`); + } + if (isValidFqbnWithOptions(fqbn)) { + throw new ConfigOptionError(`${fqbn} is already decorated with the configuration options.`); + } + } + + if (!configOptions.length) { + return fqbn; + } + + const toValue = (values: ConfigValue[]) => { + const selectedValue = values.find(({ selected }) => selected); + if (!selectedValue) { + console.warn(`None of the config values was selected. Values were: ${JSON.stringify(values)}`); + return undefined; + } + return selectedValue.value; + }; + const options = configOptions + .map(({ option, values }) => [option, toValue(values)]) + .filter(([, value]) => !!value) + .map(([option, value]) => `${option}=${value}`) + .join(','); + + return `${fqbn}:${options}`; + } + + export function isValidFqbn(fqbn: string): boolean { + return /^\w+(:\w+)*$/.test(fqbn); + } + + export function isValidFqbnWithOptions(fqbn: string): boolean { + return /^\w+(:\w+)*(:\w+=\w+(,\w+=\w+)*)$/.test(fqbn); + } + + export class ConfigOptionError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, ConfigOptionError.prototype); + } + } + + export const LABEL_COMPARATOR = (left: ConfigOption, right: ConfigOption) => left.label.toLocaleLowerCase().localeCompare(right.label.toLocaleLowerCase()); + +} + +export interface ConfigValue { + readonly label: string; + readonly value: string; + readonly selected: boolean; } export namespace Board { @@ -232,25 +314,36 @@ export namespace Board { return `${board.name}${fqbn}`; } -} + export function decorateBoards( + selectedBoard: Board | undefined, + searchResults: Array): Array { + // Board names are not unique. We show the corresponding core name as a detail. + // https://github.com/arduino/arduino-cli/pull/294#issuecomment-513764948 + const distinctBoardNames = new Map(); + for (const { name } of searchResults) { + const counter = distinctBoardNames.get(name) || 0; + distinctBoardNames.set(name, counter + 1); + } -export interface AttachedSerialBoard extends Board { - port: string; -} - -export namespace AttachedSerialBoard { - export function is(b: Board | any): b is AttachedSerialBoard { - return !!b && 'port' in b; + // Due to the non-unique board names, we have to check the package name as well. + const selected = (board: Board & { packageName: string }) => { + if (!!selectedBoard) { + if (Board.equals(board, selectedBoard)) { + if ('packageName' in selectedBoard) { + return board.packageName === (selectedBoard as any).packageName; + } + return true; + } + } + return false; + } + return searchResults.map(board => ({ + ...board, + details: (distinctBoardNames.get(board.name) || 0) > 1 ? ` - ${board.packageName}` : undefined, + selected: selected(board), + missing: !installed(board) + })); } -} -export interface AttachedNetworkBoard extends Board { - address: string; - port: string; -} -export namespace AttachedNetworkBoard { - export function is(b: Board): b is AttachedNetworkBoard { - return 'address' in b && 'port' in b; - } } diff --git a/arduino-ide-extension/src/common/protocol/core-service.ts b/arduino-ide-extension/src/common/protocol/core-service.ts index 5b7fa496..97662cb9 100644 --- a/arduino-ide-extension/src/common/protocol/core-service.ts +++ b/arduino-ide-extension/src/common/protocol/core-service.ts @@ -1,5 +1,4 @@ import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory'; -import { Board } from './boards-service'; export const CoreServiceClient = Symbol('CoreServiceClient'); export interface CoreServiceClient { @@ -15,20 +14,18 @@ export interface CoreService extends JsonRpcServer { export namespace CoreService { - export namespace Upload { + export namespace Compile { export interface Options { - readonly uri: string; - readonly board: Board; - readonly port: string; + readonly sketchUri: string; + readonly fqbn: string; readonly optimizeForDebug: boolean; } } - export namespace Compile { - export interface Options { - readonly uri: string; - readonly board: Board; - readonly optimizeForDebug: boolean; + export namespace Upload { + export interface Options extends Compile.Options { + readonly port: string; } } + } diff --git a/arduino-ide-extension/src/common/protocol/detailable.ts b/arduino-ide-extension/src/common/protocol/detailable.ts deleted file mode 100644 index 456dd626..00000000 --- a/arduino-ide-extension/src/common/protocol/detailable.ts +++ /dev/null @@ -1,10 +0,0 @@ - -export interface Detailable { - detail(options: Detailable.Options): Promise<{ item?: T }>; -} - -export namespace Detailable { - export interface Options { - readonly id: string; - } -} \ No newline at end of file diff --git a/arduino-ide-extension/src/common/protocol/searchable.ts b/arduino-ide-extension/src/common/protocol/searchable.ts index f4e996b9..483e12dd 100644 --- a/arduino-ide-extension/src/common/protocol/searchable.ts +++ b/arduino-ide-extension/src/common/protocol/searchable.ts @@ -1,5 +1,5 @@ export interface Searchable { - search(options: Searchable.Options): Promise<{ items: T[] }>; + search(options: Searchable.Options): Promise; } export namespace Searchable { export interface Options { @@ -8,4 +8,4 @@ export namespace Searchable { */ readonly query?: string; } -} \ No newline at end of file +} diff --git a/arduino-ide-extension/src/electron-browser/electron-arduino-menu-contribution.ts b/arduino-ide-extension/src/electron-browser/electron-arduino-menu-contribution.ts deleted file mode 100644 index 4559c6d7..00000000 --- a/arduino-ide-extension/src/electron-browser/electron-arduino-menu-contribution.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as electron from 'electron'; -import { injectable, inject, postConstruct } from 'inversify'; -import { isOSX } from '@theia/core/lib/common/os'; -import { ElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution'; -import { EditorMode } from '../browser/editor-mode'; - -@injectable() -export class ElectronArduinoMenuContribution extends ElectronMenuContribution { - - @inject(EditorMode) - protected readonly editorMode: EditorMode; - - @postConstruct() - protected init(): void { - this.editorMode.menuContentChanged.event(() => { - const createdMenuBar = this.factory.createMenuBar(); - if (isOSX) { - electron.remote.Menu.setApplicationMenu(createdMenuBar); - } else { - electron.remote.getCurrentWindow().setMenu(createdMenuBar); - } - }); - } - - protected hideTopPanel(): void { - // NOOP - // We reuse the `div` for the Arduino toolbar. - } - -} diff --git a/arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-contribution.ts b/arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-contribution.ts new file mode 100644 index 00000000..251e89ec --- /dev/null +++ b/arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-contribution.ts @@ -0,0 +1,17 @@ +import { injectable } from 'inversify'; +import { ElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution'; +import { MainMenuManager } from '../../browser/menu/main-menu-manager'; + +@injectable() +export class ElectronArduinoMenuContribution extends ElectronMenuContribution implements MainMenuManager { + + protected hideTopPanel(): void { + // NOOP + // We reuse the `div` for the Arduino toolbar. + } + + update(): void { + (this as any).setMenu(); + } + +} diff --git a/arduino-ide-extension/src/electron-browser/electron-arduino-menu-module.ts b/arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-module.ts similarity index 76% rename from arduino-ide-extension/src/electron-browser/electron-arduino-menu-module.ts rename to arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-module.ts index b53fc8c4..2849d103 100644 --- a/arduino-ide-extension/src/electron-browser/electron-arduino-menu-module.ts +++ b/arduino-ide-extension/src/electron-browser/menu/electron-arduino-menu-module.ts @@ -1,8 +1,10 @@ import { ContainerModule } from 'inversify'; import { ElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution' import { ElectronArduinoMenuContribution } from './electron-arduino-menu-contribution'; +import { MainMenuManager } from '../../browser/menu/main-menu-manager'; export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ElectronArduinoMenuContribution).toSelf().inSingletonScope(); + bind(MainMenuManager).toService(ElectronArduinoMenuContribution); rebind(ElectronMenuContribution).to(ElectronArduinoMenuContribution); }); diff --git a/arduino-ide-extension/src/node/arduino-backend-module.ts b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts similarity index 99% rename from arduino-ide-extension/src/node/arduino-backend-module.ts rename to arduino-ide-extension/src/node/arduino-ide-backend-module.ts index c5f8b651..a62daa12 100644 --- a/arduino-ide-extension/src/node/arduino-backend-module.ts +++ b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts @@ -85,7 +85,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule); // Boards service - const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => { + const boardsServiceConnectionModule = ConnectionContainerModule.create(async ({ bind, bindBackendService }) => { bind(BoardsServiceImpl).toSelf().inSingletonScope(); bind(BoardsService).toService(BoardsServiceImpl); bindBackendService(BoardsServicePath, BoardsService, (service, client) => { diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index 925ff293..a5074d23 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -1,10 +1,7 @@ import { injectable, inject, postConstruct, named } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; import { Deferred } from '@theia/core/lib/common/promise-util'; -import { - BoardsService, AttachedSerialBoard, BoardPackage, Board, AttachedNetworkBoard, BoardsServiceClient, - Port, BoardDetails, Tool -} from '../common/protocol/boards-service'; +import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue } from '../common/protocol'; import { PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq, PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq @@ -37,8 +34,8 @@ export class BoardsServiceImpl implements BoardsService { * Stores the state of the currently discovered and attached boards. * This state is updated via periodical polls. If there diff, a change event will be sent out to the frontend. */ - protected attachedBoards: { boards: Board[] } = { boards: [] }; - protected availablePorts: { ports: Port[] } = { ports: [] }; + protected attachedBoards: Board[] = []; + protected availablePorts: Port[] = []; protected started = new Deferred(); protected client: BoardsServiceClient | undefined; @@ -49,8 +46,8 @@ export class BoardsServiceImpl implements BoardsService { this.doGetAttachedBoardsAndAvailablePorts() .then(({ boards, ports }) => { const update = (oldBoards: Board[], newBoards: Board[], oldPorts: Port[], newPorts: Port[], message: string) => { - this.attachedBoards = { boards: newBoards }; - this.availablePorts = { ports: newPorts }; + this.attachedBoards = newBoards; + this.availablePorts = newPorts; this.discoveryLogger.info(`${message} - Discovered boards: ${JSON.stringify(newBoards)} and available ports: ${JSON.stringify(newPorts)}`); if (this.client) { this.client.notifyAttachedBoardsChanged({ @@ -76,7 +73,7 @@ export class BoardsServiceImpl implements BoardsService { Promise.all([ this.getAttachedBoards(), this.getAvailablePorts() - ]).then(([{ boards: currentBoards }, { ports: currentPorts }]) => { + ]).then(([currentBoards, currentPorts]) => { this.discoveryLogger.trace(`Updating discovered boards... ${JSON.stringify(currentBoards)}`); if (currentBoards.length !== sortedBoards.length || currentPorts.length !== sortedPorts.length) { update(currentBoards, sortedBoards, currentPorts, sortedPorts, 'Updated discovered boards and available ports.'); @@ -118,12 +115,12 @@ export class BoardsServiceImpl implements BoardsService { this.client = undefined; } - async getAttachedBoards(): Promise<{ boards: Board[] }> { + async getAttachedBoards(): Promise { await this.started.promise; return this.attachedBoards; } - async getAvailablePorts(): Promise<{ ports: Port[] }> { + async getAvailablePorts(): Promise { await this.started.promise; return this.availablePorts; } @@ -192,23 +189,8 @@ export class BoardsServiceImpl implements BoardsService { for (const board of portList.getBoardsList()) { const name = board.getName() || 'unknown'; const fqbn = board.getFqbn(); - const port = address; - if (protocol === 'serial') { - boards.push({ - name, - fqbn, - port - }); - } else if (protocol === 'network') { // We assume, it is a `network` board. - boards.push({ - name, - fqbn, - address, - port - }); - } else { - console.warn(`Unknown protocol for port: ${address}.`); - } + const port = { address, protocol }; + boards.push({ name, fqbn, port }); } } // TODO: remove mock board! @@ -219,37 +201,79 @@ export class BoardsServiceImpl implements BoardsService { return { boards, ports }; } - async detail(options: { id: string }): Promise<{ item?: BoardDetails }> { + async getBoardDetails(options: { fqbn: string }): Promise { const coreClient = await this.coreClientProvider.client(); if (!coreClient) { - return {}; + throw new Error(`Cannot acquire core client provider.`); } const { client, instance } = coreClient; + const { fqbn } = options; const req = new BoardDetailsReq(); req.setInstance(instance); - req.setFqbn(options.id); - const resp = await new Promise((resolve, reject) => client.boardDetails(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp))); + req.setFqbn(fqbn); + const resp = await new Promise((resolve, reject) => client.boardDetails(req, (err, resp) => { + if (err) { + reject(err); + return; + } + resolve(resp); + })); - const tools = await Promise.all(resp.getRequiredToolsList().map(async t => { + const requiredTools = resp.getRequiredToolsList().map(t => { name: t.getName(), packager: t.getPackager(), version: t.getVersion() - })); + }); + + const configOptions = resp.getConfigOptionsList().map(c => { + label: c.getOptionLabel(), + option: c.getOption(), + values: c.getValuesList().map(v => { + value: v.getValue(), + label: v.getValueLabel(), + selected: v.getSelected() + }) + }); return { - item: { - name: resp.getName(), - fqbn: options.id, - requiredTools: tools - } + fqbn, + requiredTools, + configOptions }; } - async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> { + async getBoardPackage(options: { id: string }): Promise { + const { id: expectedId } = options; + if (!expectedId) { + return undefined; + } + const packages = await this.search({ query: expectedId }); + return packages.find(({ id }) => id === expectedId); + } + + async getContainerBoardPackage(options: { fqbn: string }): Promise { + const { fqbn: expectedFqbn } = options; + if (!expectedFqbn) { + return undefined; + } + const packages = await this.search({}); + return packages.find(({ boards }) => boards.some(({ fqbn }) => fqbn === expectedFqbn)); + } + + async searchBoards(options: { query?: string }): Promise> { + const query = (options.query || '').toLocaleLowerCase(); + const results = await this.search(options); + return results.map(item => item.boards.map(board => ({ ...board, packageName: item.name }))) + .reduce((acc, curr) => acc.concat(curr), []) + .filter(board => board.name.toLocaleLowerCase().indexOf(query) !== -1) + .sort(Board.compare); + } + + async search(options: { query?: string }): Promise { const coreClient = await this.coreClientProvider.client(); if (!coreClient) { - return { items: [] }; + return []; } const { client, instance } = coreClient; @@ -265,7 +289,7 @@ export class BoardsServiceImpl implements BoardsService { req.setAllVersions(true); req.setInstance(instance); const resp = await new Promise((resolve, reject) => client.platformSearch(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp))); - const packages = new Map(); + const packages = new Map(); const toPackage = (platform: Platform) => { let installedVersion: string | undefined; const matchingPlatform = installedPlatforms.find(ip => ip.getId() === platform.getId()); @@ -307,7 +331,7 @@ export class BoardsServiceImpl implements BoardsService { if (!leftInstalled && rightInstalled) { return 1; } - return Installable.Version.COMPARATOR(right.getLatest(), left.getLatest()); // Higher version comes first. + return Installable.Version.COMPARATOR(left.getLatest(), right.getLatest()); // Higher version comes first. } for (const id of groupedById.keys()) { groupedById.get(id)!.sort(installedAwareVersionComparator); @@ -326,10 +350,10 @@ export class BoardsServiceImpl implements BoardsService { } } - return { items: [...packages.values()] }; + return [...packages.values()]; } - async install(options: { item: BoardPackage, version?: Installable.Version }): Promise { + async install(options: { item: BoardsPackage, version?: Installable.Version }): Promise { const pkg = options.item; const version = !!options.version ? options.version : pkg.availableVersions[0]; const coreClient = await this.coreClientProvider.client(); @@ -338,11 +362,11 @@ export class BoardsServiceImpl implements BoardsService { } const { client, instance } = coreClient; - const [platform, boardName] = pkg.id.split(":"); + const [platform, architecture] = pkg.id.split(":"); const req = new PlatformInstallReq(); req.setInstance(instance); - req.setArchitecture(boardName); + req.setArchitecture(architecture); req.setPlatformPackage(platform); req.setVersion(version); @@ -359,12 +383,14 @@ export class BoardsServiceImpl implements BoardsService { resp.on('error', reject); }); if (this.client) { - this.client.notifyBoardInstalled({ pkg }); + const packages = await this.search({}); + const updatedPackage = packages.find(({ id }) => id === pkg.id) || pkg; + this.client.notifyBoardInstalled({ pkg: updatedPackage }); } console.info("Board installation done", pkg); } - async uninstall(options: { item: BoardPackage }): Promise { + async uninstall(options: { item: BoardsPackage }): Promise { const pkg = options.item; const coreClient = await this.coreClientProvider.client(); if (!coreClient) { @@ -372,11 +398,11 @@ export class BoardsServiceImpl implements BoardsService { } const { client, instance } = coreClient; - const [platform, boardName] = pkg.id.split(":"); + const [platform, architecture] = pkg.id.split(":"); const req = new PlatformUninstallReq(); req.setInstance(instance); - req.setArchitecture(boardName); + req.setArchitecture(architecture); req.setPlatformPackage(platform); console.info("Starting board uninstallation", pkg); @@ -393,6 +419,7 @@ export class BoardsServiceImpl implements BoardsService { resp.on('error', reject); }); if (this.client) { + // Here, unlike at `install` we send out the argument `pkg`. Otherwise, we would not know about the board FQBN. this.client.notifyBoardUninstalled({ pkg }); } console.info("Board uninstallation done", pkg); diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index 3ae9eca5..e777d7f9 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -36,10 +36,10 @@ export class CoreServiceImpl implements CoreService { async compile(options: CoreService.Compile.Options): Promise { console.log('compile', options); - const { uri } = options; - const sketchFilePath = await this.fileSystem.getFsPath(options.uri); + const { sketchUri, fqbn } = options; + const sketchFilePath = await this.fileSystem.getFsPath(sketchUri); if (!sketchFilePath) { - throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`); + throw new Error(`Cannot resolve filesystem path for URI: ${sketchUri}.`); } const sketchpath = path.dirname(sketchFilePath); @@ -49,18 +49,14 @@ export class CoreServiceImpl implements CoreService { } const { client, instance } = coreClient; - const currentBoard = options.board; - if (!currentBoard) { - throw new Error("no board selected"); - } - if (!currentBoard.fqbn) { - throw new Error(`selected board (${currentBoard.name}) has no FQBN`); + if (!fqbn) { + throw new Error('The selected board has no FQBN.'); } const compilerReq = new CompileReq(); compilerReq.setInstance(instance); compilerReq.setSketchpath(sketchpath); - compilerReq.setFqbn(currentBoard.fqbn!); + compilerReq.setFqbn(fqbn); compilerReq.setOptimizefordebug(options.optimizeForDebug); compilerReq.setPreprocess(false); compilerReq.setVerbose(true); @@ -84,23 +80,15 @@ export class CoreServiceImpl implements CoreService { } async upload(options: CoreService.Upload.Options): Promise { - await this.compile({ uri: options.uri, board: options.board, optimizeForDebug: options.optimizeForDebug }); - + await this.compile(options); console.log('upload', options); - const { uri } = options; - const sketchFilePath = await this.fileSystem.getFsPath(options.uri); + const { sketchUri, fqbn } = options; + const sketchFilePath = await this.fileSystem.getFsPath(sketchUri); if (!sketchFilePath) { - throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`); + throw new Error(`Cannot resolve filesystem path for URI: ${sketchUri}.`); } const sketchpath = path.dirname(sketchFilePath); - const currentBoard = options.board; - if (!currentBoard) { - throw new Error("no board selected"); - } - if (!currentBoard.fqbn) { - throw new Error(`selected board (${currentBoard.name}) has no FQBN`); - } const coreClient = await this.coreClientProvider.client(); if (!coreClient) { @@ -108,10 +96,14 @@ export class CoreServiceImpl implements CoreService { } const { client, instance } = coreClient; + if (!fqbn) { + throw new Error('The selected board has no FQBN.'); + } + const req = new UploadReq(); req.setInstance(instance); req.setSketchPath(sketchpath); - req.setFqbn(currentBoard.fqbn); + req.setFqbn(fqbn); req.setPort(options.port); const result = client.upload(req); diff --git a/arduino-ide-extension/src/node/library-service-impl.ts b/arduino-ide-extension/src/node/library-service-impl.ts index 24afa302..3e97bdb9 100644 --- a/arduino-ide-extension/src/node/library-service-impl.ts +++ b/arduino-ide-extension/src/node/library-service-impl.ts @@ -25,10 +25,10 @@ export class LibraryServiceImpl implements LibraryService { @inject(ToolOutputServiceServer) protected readonly toolOutputService: ToolOutputServiceServer; - async search(options: { query?: string }): Promise<{ items: Library[] }> { + async search(options: { query?: string }): Promise { const coreClient = await this.coreClientProvider.client(); if (!coreClient) { - return { items: [] }; + return []; } const { client, instance } = coreClient; @@ -68,7 +68,7 @@ export class LibraryServiceImpl implements LibraryService { }, item.getLatest()!, availableVersions) }) - return { items }; + return items; } async install(options: { item: Library, version?: Installable.Version }): Promise { diff --git a/arduino-ide-extension/src/test/browser/boards-service-client-impl.test.ts b/arduino-ide-extension/src/test/browser/boards-service-client-impl.test.ts new file mode 100644 index 00000000..82246a9d --- /dev/null +++ b/arduino-ide-extension/src/test/browser/boards-service-client-impl.test.ts @@ -0,0 +1,310 @@ +import { expect } from 'chai'; +import { Container, injectable } from 'inversify'; +import { Event } from '@theia/core/lib/common/event'; +import { ILogger } from '@theia/core/lib/common/logger'; +import { Deferred } from '@theia/core/lib/common/promise-util'; +import { MockLogger } from '@theia/core/lib/common/test/mock-logger'; +import { MaybePromise } from '@theia/core/lib/common/types'; +import { StorageService } from '@theia/core/lib/browser/storage-service'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { BoardsService, Board, Port, BoardsPackage, BoardDetails, BoardsServiceClient } from '../../common/protocol'; +import { BoardsServiceClientImpl, AvailableBoard } from '../../browser/boards/boards-service-client-impl'; +import { BoardsConfig } from '../../browser/boards/boards-config'; + +// tslint:disable: no-unused-expression + +describe('boards-service-client-impl', () => { + + describe('onAvailableBoardsChanged', () => { + + const ESP8266: Port = { protocol: 'serial', address: '/dev/cu.SLAB_USBtoUART' }; + const UNO: Board = { name: 'Arduino Uno', fqbn: 'arduino:avr:uno', port: { protocol: 'serial', address: '/dev/cu.usbmodem14501' } }; + const MKR1000: Board = { name: 'Arduino MKR1000', fqbn: 'arduino:samd:mkr1000', port: { protocol: 'serial', address: '/dev/cu.usbmodem14601' } }; + const NANO: Board = { name: 'Arduino Nano', fqbn: 'arduino:avr:nano' }; + + const recognized = AvailableBoard.State.recognized; + const guessed = AvailableBoard.State.guessed; + const incomplete = AvailableBoard.State.incomplete; + + let server: MockBoardsService; + let client: BoardsServiceClientImpl; + // let storage: MockStorageService; + + beforeEach(() => { + const container = init(); + server = container.get(MockBoardsService); + client = container.get(BoardsServiceClientImpl); + // storage = container.get(MockStorageService); + server.setClient(client); + }); + + it('should have no available boards by default', () => { + expect(client.availableBoards).to.have.length(0); + }); + + it('should be notified when a board is attached', async () => { + await attach(MKR1000); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(recognized); + expect(!!availableBoards()[0].selected).to.be.false; + }); + + it('should be notified when a unknown board is attached', async () => { + await attach(ESP8266); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(incomplete); + }); + + it('should be notified when a board is detached', async () => { + await attach(MKR1000, UNO, ESP8266); + expect(availableBoards()).to.have.length(3); + await detach(MKR1000); + expect(availableBoards()).to.have.length(2); + }); + + it('should be notified when an unknown board is detached', async () => { + await attach(MKR1000, UNO, ESP8266); + expect(availableBoards()).to.have.length(3); + await detach(ESP8266); + expect(availableBoards()).to.have.length(2); + }); + + it('should recognize boards config as an available board', async () => { + await configureBoards({ selectedBoard: NANO }); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(incomplete); + expect(availableBoards()[0].selected).to.be.true; + }); + + it('should discard the boards config port when corresponding board is detached', async () => { + await attach(MKR1000); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(recognized); + expect(availableBoards()[0].selected).to.be.false; + + await configureBoards({ selectedBoard: MKR1000, selectedPort: server.portFor(MKR1000) }); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(recognized); + expect(availableBoards()[0].selected).to.be.true; + + await detach(MKR1000); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(incomplete); + expect(availableBoards()[0].selected).to.be.true; + }); + + it("should consider selected unknown boards as 'guessed'", async () => { + await attach(ESP8266); + await configureBoards({ selectedBoard: { name: 'guessed' }, selectedPort: ESP8266 }); + expect(availableBoards()).to.have.length(1); + expect(availableBoards()[0].state).to.be.equal(guessed); + expect(availableBoards()[0].name).to.be.equal('guessed'); + expect(availableBoards()[0].fqbn).to.be.undefined; + expect(client.canVerify(client.boardsConfig)).to.be.true; + }); + + it('should not reconnect last valid selected if port is gone', async () => { + await attach(ESP8266, UNO); + await configureBoards({ selectedBoard: { name: 'NodeMCU 0.9 (ESP-12 Module)', fqbn: 'esp8266:esp8266:nodemcu' }, selectedPort: ESP8266 }); + await detach(ESP8266); + expect(availableBoards()).to.have.length(2); + const selected = availableBoards().find(({ selected }) => selected); + expect(selected).to.be.not.undefined; + expect(selected!.port).to.be.undefined; + expect(selected!.name).to.be.equal('NodeMCU 0.9 (ESP-12 Module)'); + }); + + function availableBoards(): AvailableBoard[] { + return client.availableBoards.slice(); + } + + async function configureBoards(config: BoardsConfig.Config): Promise { + return awaitAll(() => { client.boardsConfig = config; }, client.onAvailableBoardsChanged); + } + + async function detach(...toDetach: Array): Promise { + return awaitAll(() => server.detach(...toDetach), client.onAttachedBoardsChanged, client.onAvailableBoardsChanged); + } + + async function attach(...toAttach: Array): Promise { + return awaitAll(() => server.attach(...toAttach), client.onAttachedBoardsChanged, client.onAvailableBoardsChanged); + } + + async function awaitAll(exec: () => MaybePromise, ...waitFor: Event[]): Promise { + return new Promise(async resolve => { + const toDispose = new DisposableCollection(); + const promises = waitFor.map(event => { + const deferred = new Deferred(); + toDispose.push(event(() => deferred.resolve())); + return deferred.promise; + }); + await exec(); + await Promise.all(promises); + toDispose.dispose(); + resolve(); + }); + } + + }); + +}); + +function init(): Container { + const container = new Container({ defaultScope: 'Singleton' }); + container.bind(MockBoardsService).toSelf(); + container.bind(MockLogger).toSelf(); + container.bind(ILogger).toService(MockLogger); + container.bind(MockStorageService).toSelf(); + container.bind(StorageService).toService(MockStorageService); + container.bind(BoardsServiceClientImpl).toSelf(); + return container; +} + +@injectable() +export class MockBoardsService implements BoardsService { + + private client: BoardsServiceClient | undefined; + + boards: Board[] = []; + ports: Port[] = []; + + attach(...toAttach: Array): void { + const oldState = { boards: this.boards.slice(), ports: this.ports.slice() }; + for (const what of toAttach) { + if (Board.is(what)) { + if (what.port) { + this.ports.push(what.port); + } + this.boards.push(what); + } else { + this.ports.push(what); + } + } + const newState = { boards: this.boards, ports: this.ports }; + if (this.client) { + this.client.notifyAttachedBoardsChanged({ oldState, newState }); + } + } + + detach(...toRemove: Array): void { + const oldState = { boards: this.boards.slice(), ports: this.ports.slice() }; + for (const what of toRemove) { + if (Board.is(what)) { + const index = this.boards.indexOf(what); + if (index === -1) { + throw new Error(`${what} board is not attached. Boards were: ${JSON.stringify(oldState.boards)}`); + } + this.boards.splice(index, 1); + if (what.port) { + const portIndex = this.ports.findIndex(port => Port.sameAs(what.port, port)); + if (portIndex === -1) { + throw new Error(`${what} port is not available. Ports were: ${JSON.stringify(oldState.ports)}`); + } + this.ports.splice(portIndex, 1); + } + } else { + const index = this.ports.indexOf(what); + if (index === -1) { + throw new Error(`${what} port is not available. Ports were: ${JSON.stringify(oldState.ports)}`); + } + this.ports.splice(index, 1); + } + } + const newState = { boards: this.boards, ports: this.ports }; + if (this.client) { + this.client.notifyAttachedBoardsChanged({ oldState, newState }); + } + } + + reset(): void { + this.setState({ boards: [], ports: [], silent: true }); + } + + setState({ boards, ports, silent }: { boards: Board[], ports: Port[], silent?: boolean }): void { + const oldState = { boards: this.boards, ports: this.ports }; + const newState = { boards, ports }; + if (this.client && !silent) { + this.client.notifyAttachedBoardsChanged({ oldState, newState }); + } + } + + portFor(board: Board): Port { + if (!board.port) { + throw new Error(`${JSON.stringify(board)} does not have a port.`); + } + const port = this.ports.find(port => Port.sameAs(port, board.port)); + if (!port) { + throw new Error(`Could not find port for board: ${JSON.stringify(board)}. Ports were: ${JSON.stringify(this.ports)}.`); + } + return port; + } + + // BoardsService API + + async getAttachedBoards(): Promise { + return this.boards; + } + + async getAvailablePorts(): Promise { + throw this.ports; + } + + async getBoardDetails(): Promise { + throw new Error('Method not implemented.'); + } + + getBoardPackage(): Promise { + throw new Error('Method not implemented.'); + } + + getContainerBoardPackage(): Promise { + throw new Error('Method not implemented.'); + } + + searchBoards(): Promise> { + throw new Error('Method not implemented.'); + } + + install(): Promise { + throw new Error('Method not implemented.'); + } + + uninstall(): Promise { + throw new Error('Method not implemented.'); + } + + search(): Promise { + throw new Error('Method not implemented.'); + } + + dispose(): void { + this.reset(); + this.client = undefined; + } + + setClient(client: BoardsServiceClient | undefined): void { + this.client = client; + } + +} + +@injectable() +class MockStorageService implements StorageService { + + private store: Map = new Map(); + + reset(): void { + this.store.clear(); + } + + async setData(key: string, data: T): Promise { + this.store.set(key, data); + } + + async getData(key: string): Promise; + async getData(key: string, defaultValue?: T): Promise { + const data = this.store.get(key); + return data ? data : defaultValue; + } + +} diff --git a/arduino-ide-extension/src/test/common/boards-service.test.ts b/arduino-ide-extension/src/test/common/boards-service.test.ts new file mode 100644 index 00000000..62dc0781 --- /dev/null +++ b/arduino-ide-extension/src/test/common/boards-service.test.ts @@ -0,0 +1,116 @@ +import { expect } from 'chai'; +import { ConfigOption, AttachedBoardsChangeEvent } from '../../common/protocol'; +import { fail } from 'assert'; + +describe('boards-service', () => { + + describe('AttachedBoardsChangeEvent', () => { + + it('should detect one attached port', () => { + const event = { + oldState: { + boards: [ + { name: 'Arduino MKR1000', fqbn: 'arduino:samd:mkr1000', port: '/dev/cu.usbmodem14601' }, + { name: 'Arduino Uno', fqbn: 'arduino:avr:uno', port: '/dev/cu.usbmodem14501' } + ], + ports: [ + { protocol: 'serial', address: '/dev/cu.usbmodem14501' }, + { protocol: 'serial', address: '/dev/cu.usbmodem14601' }, + { protocol: 'serial', address: '/dev/cu.Bluetooth-Incoming-Port' }, + { protocol: 'serial', address: '/dev/cu.MALS' }, + { protocol: 'serial', address: '/dev/cu.SOC' } + ] + }, + newState: { + boards: [ + { name: 'Arduino MKR1000', fqbn: 'arduino:samd:mkr1000', 'port': '/dev/cu.usbmodem1460' }, + { name: 'Arduino Uno', fqbn: 'arduino:avr:uno', 'port': '/dev/cu.usbmodem14501' } + ], + ports: [ + { protocol: 'serial', address: '/dev/cu.SLAB_USBtoUART' }, + { protocol: 'serial', address: '/dev/cu.usbmodem14501' }, + { protocol: 'serial', address: '/dev/cu.usbmodem14601' }, + { protocol: 'serial', address: '/dev/cu.Bluetooth-Incoming-Port' }, + { protocol: 'serial', address: '/dev/cu.MALS' }, + { protocol: 'serial', address: '/dev/cu.SOC' } + ] + } + }; + const diff = AttachedBoardsChangeEvent.diff(event); + expect(diff.attached.boards).to.be.empty; // tslint:disable-line:no-unused-expression + expect(diff.detached.boards).to.be.empty; // tslint:disable-line:no-unused-expression + expect(diff.detached.ports).to.be.empty; // tslint:disable-line:no-unused-expression + expect(diff.attached.ports.length).to.be.equal(1); + expect(diff.attached.ports[0].address).to.be.equal('/dev/cu.SLAB_USBtoUART'); + }); + + }); + + + describe('ConfigOption', () => { + + ([ + ['', false], + ['foo', true], + ['foo:bar', true], + ['foo:bar:baz', true], + ['foo:', false], + [':foo', false], + [':foo:', false], + ['foo:bar:', false] + ] as Array<[string, boolean]>).forEach(([fqbn, expectation]) => { + it(`"${fqbn}" should ${expectation ? '' : 'not '}be a valid FQBN`, () => { + expect(ConfigOption.isValidFqbn(fqbn)).to.be.equal(expectation); + }); + }); + + ([ + ['', false], + ['foo:bar:option1', false], + ['foo:bar:option1=', false], + ['foo:bar:baz:option1=value1', true], + ['foo:bar:baz:option1=value1,option2=value2', true], + ['foo:bar:baz:option1=value1,option2=value2,', false], + ['foo:bar:baz,option1=value1,option2=value2', false], + ['foo:bar:baz:option1=value1,option2=value2,options3', false], + ['foo:bar:baz:option1=value1,option2=value2, options3=value3', false], + ] as Array<[string, boolean]>).forEach(([fqbn, expectation]) => { + it(`"${fqbn}" should ${expectation ? '' : 'not '}be a valid FQBN with options`, () => { + expect(ConfigOption.isValidFqbnWithOptions(fqbn)).to.be.equal(expectation); + }); + }); + + ([ + [ + 'foo:bar:baz', + JSON.parse('[{"label":"CPU Frequency","option":"xtal","values":[{"value":"80","label":"80 MHz","selected":true},{"value":"160","label":"160 MHz","selected":false}]},{"label":"VTables","option":"vt","values":[{"value":"flash","label":"Flash","selected":true},{"value":"heap","label":"Heap","selected":false},{"value":"iram","label":"IRAM","selected":false}]},{"label":"Exceptions","option":"exception","values":[{"value":"legacy","label":"Legacy (new can return nullptr)","selected":true},{"value":"disabled","label":"Disabled (new can abort)","selected":false},{"value":"enabled","label":"Enabled","selected":false}]},{"label":"SSL Support","option":"ssl","values":[{"value":"all","label":"All SSL ciphers (most compatible)","selected":true},{"value":"basic","label":"Basic SSL ciphers (lower ROM use)","selected":false}]},{"label":"Flash Size","option":"eesz","values":[{"value":"4M2M","label":"4MB (FS:2MB OTA:~1019KB)","selected":true},{"value":"4M3M","label":"4MB (FS:3MB OTA:~512KB)","selected":false},{"value":"4M1M","label":"4MB (FS:1MB OTA:~1019KB)","selected":false},{"value":"4M","label":"4MB (FS:none OTA:~1019KB)","selected":false}]},{"label":"lwIP Variant","option":"ip","values":[{"value":"lm2f","label":"v2 Lower Memory","selected":true},{"value":"hb2f","label":"v2 Higher Bandwidth","selected":false},{"value":"lm2n","label":"v2 Lower Memory (no features)","selected":false},{"value":"hb2n","label":"v2 Higher Bandwidth (no features)","selected":false},{"value":"lm6f","label":"v2 IPv6 Lower Memory","selected":false},{"value":"hb6f","label":"v2 IPv6 Higher Bandwidth","selected":false},{"value":"hb1","label":"v1.4 Higher Bandwidth","selected":false},{"value":"src","label":"v1.4 Compile from source","selected":false}]},{"label":"Debug port","option":"dbg","values":[{"value":"Disabled","label":"Disabled","selected":true},{"value":"Serial","label":"Serial","selected":false},{"value":"Serial1","label":"Serial1","selected":false}]},{"label":"Debug Level","option":"lvl","values":[{"value":"None____","label":"None","selected":true},{"value":"SSL","label":"SSL","selected":false},{"value":"TLS_MEM","label":"TLS_MEM","selected":false},{"value":"HTTP_CLIENT","label":"HTTP_CLIENT","selected":false},{"value":"HTTP_SERVER","label":"HTTP_SERVER","selected":false},{"value":"SSLTLS_MEM","label":"SSL+TLS_MEM","selected":false},{"value":"SSLHTTP_CLIENT","label":"SSL+HTTP_CLIENT","selected":false},{"value":"SSLHTTP_SERVER","label":"SSL+HTTP_SERVER","selected":false},{"value":"TLS_MEMHTTP_CLIENT","label":"TLS_MEM+HTTP_CLIENT","selected":false},{"value":"TLS_MEMHTTP_SERVER","label":"TLS_MEM+HTTP_SERVER","selected":false},{"value":"HTTP_CLIENTHTTP_SERVER","label":"HTTP_CLIENT+HTTP_SERVER","selected":false},{"value":"SSLTLS_MEMHTTP_CLIENT","label":"SSL+TLS_MEM+HTTP_CLIENT","selected":false},{"value":"SSLTLS_MEMHTTP_SERVER","label":"SSL+TLS_MEM+HTTP_SERVER","selected":false},{"value":"SSLHTTP_CLIENTHTTP_SERVER","label":"SSL+HTTP_CLIENT+HTTP_SERVER","selected":false},{"value":"TLS_MEMHTTP_CLIENTHTTP_SERVER","label":"TLS_MEM+HTTP_CLIENT+HTTP_SERVER","selected":false},{"value":"SSLTLS_MEMHTTP_CLIENTHTTP_SERVER","label":"SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER","selected":false},{"value":"CORE","label":"CORE","selected":false},{"value":"WIFI","label":"WIFI","selected":false},{"value":"HTTP_UPDATE","label":"HTTP_UPDATE","selected":false},{"value":"UPDATER","label":"UPDATER","selected":false},{"value":"OTA","label":"OTA","selected":false},{"value":"OOM","label":"OOM","selected":false},{"value":"MDNS","label":"MDNS","selected":false},{"value":"COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS","label":"CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS","selected":false},{"value":"SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS","label":"SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER+CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS","selected":false},{"value":"NoAssert-NDEBUG","label":"NoAssert-NDEBUG","selected":false}]},{"label":"Erase Flash","option":"wipe","values":[{"value":"none","label":"Only Sketch","selected":true},{"value":"sdk","label":"Sketch + WiFi Settings","selected":false},{"value":"all","label":"All Flash Contents","selected":false}]},{"label":"Upload Speed","option":"baud","values":[{"value":"115200","label":"115200","selected":true},{"value":"57600","label":"57600","selected":false},{"value":"230400","label":"230400","selected":false},{"value":"460800","label":"460800","selected":false},{"value":"921600","label":"921600","selected":false},{"value":"3000000","label":"3000000","selected":false}]}]'), + 'foo:bar:baz:xtal=80,vt=flash,exception=legacy,ssl=all,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200' + ], + [ + 'foo:bar:baz', + JSON.parse('[]'), + 'foo:bar:baz' + ], + [ + 'foo:bar:baz:xtal=80', + {}, + undefined + ] + ] as Array<[string, Array, string | undefined]>).forEach(([fqbn, configOptions, expectation]) => { + it(`should ${expectation ? `append` : 'throw an error when appending'}config options to ${fqbn}`, () => { + if (!expectation) { + try { + ConfigOption.decorate(fqbn, configOptions); + fail(`Expected a failure when decorating ${fqbn} with config options.`); + } catch (e) { + expect(e).to.be.instanceOf(ConfigOption.ConfigOptionError); + } + } else { + expect(ConfigOption.decorate(fqbn, configOptions)).to.be.equal(expectation); + } + }); + }); + + }); + +}); diff --git a/known-issues.txt b/known-issues.txt deleted file mode 100644 index adff23e4..00000000 --- a/known-issues.txt +++ /dev/null @@ -1,4 +0,0 @@ -Known issues: - - arduino-cli does not get stopped reliably upon app shutdown - - startup time is not as fast we'd like to have it - - in Electron on OSX, the application menu is incomplete on app startup (see https://github.com/theia-ide/theia/issues/5100) diff --git a/yarn.lock b/yarn.lock index 6c438218..09e702c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,17 +19,17 @@ semver "^5.5.0" "@babel/core@^7.5.5": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.6.tgz#27d7df9258a45c2e686b6f18b6c659e563aa4636" - integrity sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b" + integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.6" + "@babel/generator" "^7.8.7" "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.6" + "@babel/parser" "^7.8.7" "@babel/template" "^7.8.6" "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/types" "^7.8.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -39,12 +39,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.6.tgz#57adf96d370c9a63c241cd719f9111468578537a" - integrity sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg== +"@babel/generator@^7.8.6", "@babel/generator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.7.tgz#870b3cf7984f5297998152af625c4f3e341400f7" + integrity sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew== dependencies: - "@babel/types" "^7.8.6" + "@babel/types" "^7.8.7" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" @@ -64,22 +64,22 @@ "@babel/helper-explode-assignable-expression" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" - integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== +"@babel/helper-call-delegate@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz#28a279c2e6c622a6233da548127f980751324cab" + integrity sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ== dependencies: "@babel/helper-hoist-variables" "^7.8.3" "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.7" -"@babel/helper-compilation-targets@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.6.tgz#015b85db69e3a34240d5c2b761fc53eb9695f09c" - integrity sha512-UrJdk27hKVJSnibFcUWYLkCL0ZywTUoot8yii1lsHJcvwrypagmYKjHLMWivQPm4s6GdyygCL8fiH5EYLxhQwQ== +"@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== dependencies: "@babel/compat-data" "^7.8.6" - browserslist "^4.8.5" + browserslist "^4.9.1" invariant "^2.2.4" levenary "^1.1.1" semver "^5.5.0" @@ -243,10 +243,10 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.6.tgz#ba5c9910cddb77685a008e3c587af8d27b67962c" - integrity sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g== +"@babel/parser@^7.8.6", "@babel/parser@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.7.tgz#7b8facf95d25fef9534aad51c4ffecde1a61e26a" + integrity sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A== "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.8.3" @@ -539,12 +539,12 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" - integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== +"@babel/plugin-transform-parameters@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz#66fa2f1de4129b4e0447509223ac71bda4955395" + integrity sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g== dependencies: - "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-call-delegate" "^7.8.7" "@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" @@ -555,12 +555,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" - integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== dependencies: - regenerator-transform "^0.14.0" + regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.8.3": version "7.8.3" @@ -625,12 +625,12 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/preset-env@^7.5.5": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.6.tgz#2a0773b08589ecba4995fc71b1965e4f531af40b" - integrity sha512-M5u8llV9DIVXBFB/ArIpqJuvXpO+ymxcJ6e8ZAmzeK3sQeBNOD1y+rHvHCGG4TlEmsNpIrdecsHGHT8ZCoOSJg== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.7.tgz#1fc7d89c7f75d2d70c2b6768de6c2e049b3cb9db" + integrity sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw== dependencies: "@babel/compat-data" "^7.8.6" - "@babel/helper-compilation-targets" "^7.8.6" + "@babel/helper-compilation-targets" "^7.8.7" "@babel/helper-module-imports" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-proposal-async-generator-functions" "^7.8.3" @@ -670,9 +670,9 @@ "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" "@babel/plugin-transform-new-target" "^7.8.3" "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.4" + "@babel/plugin-transform-parameters" "^7.8.7" "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" "@babel/plugin-transform-reserved-words" "^7.8.3" "@babel/plugin-transform-shorthand-properties" "^7.8.3" "@babel/plugin-transform-spread" "^7.8.3" @@ -680,19 +680,19 @@ "@babel/plugin-transform-template-literals" "^7.8.3" "@babel/plugin-transform-typeof-symbol" "^7.8.4" "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/types" "^7.8.6" + "@babel/types" "^7.8.7" browserslist "^4.8.5" core-js-compat "^3.6.2" invariant "^2.2.2" levenary "^1.1.1" semver "^5.5.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" - integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d" + integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg== dependencies: - regenerator-runtime "^0.13.2" + regenerator-runtime "^0.13.4" "@babel/template@^7.8.3", "@babel/template@^7.8.6": version "7.8.6" @@ -718,19 +718,19 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.8.3", "@babel/types@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.6.tgz#629ecc33c2557fcde7126e58053127afdb3e6d01" - integrity sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA== +"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" + integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw== dependencies: esutils "^2.0.2" lodash "^4.17.13" to-fast-properties "^2.0.0" "@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9": - version "10.0.27" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.27.tgz#7895db204e2c1a991ae33d51262a3a44f6737303" - integrity sha512-Zp8BEpbMunFsTcqAK4D7YTm3MvCp1SekflSLJH8lze2fCcSZ/yMkXHo8kb3t1/1Tdd3hAqf3Fb7z9VZ+FMiC9w== + version "10.0.29" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" + integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ== dependencies: "@emotion/sheet" "0.9.4" "@emotion/stylis" "0.8.5" @@ -758,22 +758,22 @@ "@emotion/utils" "0.11.3" babel-plugin-emotion "^10.0.27" -"@emotion/hash@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.4.tgz#f14932887422c9056b15a8d222a9074a7dfa2831" - integrity sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A== +"@emotion/hash@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== "@emotion/memoize@0.7.4": version "0.7.4" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== -"@emotion/serialize@^0.11.15": - version "0.11.15" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.15.tgz#9a0f5873fb458d87d4f23e034413c12ed60a705a" - integrity sha512-YE+qnrmGwyR+XB5j7Bi+0GT1JWsdcjM/d4POu+TXkcnrRs4RFCCsi3d/Ebf+wSStHqAlTT2+dfd+b9N9EO2KBg== +"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": + version "0.11.16" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" + integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg== dependencies: - "@emotion/hash" "0.7.4" + "@emotion/hash" "0.8.0" "@emotion/memoize" "0.7.4" "@emotion/unitless" "0.7.5" "@emotion/utils" "0.11.3" @@ -1670,9 +1670,9 @@ universal-user-agent "^4.0.0" "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.3.1.tgz#40cd61c125a6161cfb3bfabc75805ac7a54213b4" - integrity sha512-rvJP1Y9A/+Cky2C3var1vsw3Lf5Rjn/0sojNl2AjCX+WbpIHYccaJ46abrZoIxMYnOToul6S9tPytUVkFI7CXQ== + version "2.3.2" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.3.2.tgz#63c1a786c65236a8b059024d0343353e260d5215" + integrity sha512-3nyOEch20ISn6MbVt/mBeDOkxO4ljx3oV+CnYNUT8n0JtUuMs0LpewZXpZ4ZWarI72qKc/YkxK9dkfjpncxuvg== dependencies: "@types/node" ">= 8" @@ -1776,9 +1776,9 @@ "@phosphor/virtualdom" "^1.2.0" "@primer/octicons-react@^9.0.0": - version "9.4.0" - resolved "https://registry.yarnpkg.com/@primer/octicons-react/-/octicons-react-9.4.0.tgz#19f6ed2eab82e78c2762315d19c7ce1677fcf4ed" - integrity sha512-TAPjzQaIrPqI5TpxNKkBTxS7b8Y1v7iMuiN5ZshhSp9GHbdymWKtCXRDk13lo6woDeSn/8tIdZTSerTR3c0bQA== + version "9.5.0" + resolved "https://registry.yarnpkg.com/@primer/octicons-react/-/octicons-react-9.5.0.tgz#636032e2494f3b0a1c98cf288028470c7109b484" + integrity sha512-7YmjwpBix3LClr6DSgB6HLSnAORPUPOYnid71qb7+tB85RVZu16gKqmz1L524/AO91MK/bToLJ7B9eBZ0wqsOw== dependencies: prop-types "^15.6.1" @@ -1799,16 +1799,16 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@theia/application-manager@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/application-manager/-/application-manager-0.17.0-next.c965552a.tgz#e0a889731ad069645f7fe1955695eb83e3fc8974" - integrity sha512-7mnb1lJIw9PBlgcF+BjifgI2+hy5/GTk54/WdbmqZj0qyQcgYi3ZuqBcLOoy1msUc6qX5KhiMBldsA5nEbC2cQ== +"@theia/application-manager@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/application-manager/-/application-manager-0.17.0-next.d0e00c5d.tgz#0ade957f09255de3eb7123bd1fb68519acdecef8" + integrity sha512-Z74ejabMwoSIr2DbCLusljFIgDpqhvxl0koLZFypzGx/BkcT8Bzc5uauMhAdB5AsnaCJQ16n29ONmPUOSuEfTA== dependencies: "@babel/core" "^7.5.5" "@babel/plugin-transform-classes" "^7.5.5" "@babel/plugin-transform-runtime" "^7.5.5" "@babel/preset-env" "^7.5.5" - "@theia/application-package" "0.17.0-next.c965552a" + "@theia/application-package" "0.17.0-next.d0e00c5d" "@theia/compression-webpack-plugin" "^3.0.0" "@types/fs-extra" "^4.0.2" "@types/webpack" "^4.41.2" @@ -1831,10 +1831,10 @@ webpack-cli "2.0.12" worker-loader "^1.1.1" -"@theia/application-package@0.17.0-next.c965552a", "@theia/application-package@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/application-package/-/application-package-0.17.0-next.c965552a.tgz#b7f53f32176a0a6a90ac86db46539e43c1c3d28f" - integrity sha512-rRhXttJxAyPWtw6bG9zKUmcrrddGoQ92P1QLp55sd0WE7VsrKliMrsODvmtKUHQyZogUMUwkQFC5EDnGNeEhMQ== +"@theia/application-package@0.17.0-next.d0e00c5d", "@theia/application-package@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/application-package/-/application-package-0.17.0-next.d0e00c5d.tgz#9b43332b8df94136c385a30b99cd9dbf5f824116" + integrity sha512-rCpWvoIfwZvy+Rb3kFWUrJrkPaqOT+nEW6n9FTKS4ZJxExtXGH+uC18MhPi09XHH74T9Ua42MLqq8yLmEwQI7g== dependencies: "@types/fs-extra" "^4.0.2" "@types/request" "^2.0.3" @@ -1847,24 +1847,24 @@ semver "^5.4.1" write-json-file "^2.2.0" -"@theia/callhierarchy@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/callhierarchy/-/callhierarchy-0.17.0-next.c965552a.tgz#dd4fa10ff56d31b310ed3d774632a0346f237d02" - integrity sha512-AQ4xW+byLbhhIFZClu17UT+k54UjXRlkMd+WYN+h+ArHzUmsBL+Jt0TnSTg7V/T68ROlKburopZpiwy2OLu9Tw== +"@theia/callhierarchy@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/callhierarchy/-/callhierarchy-0.17.0-next.d0e00c5d.tgz#b42aa1e807b4f4289afed75151ffef3a38338afb" + integrity sha512-tSUDS0dyFbeDi1ZQLkI3//SZttNfgI8DwhegGzAudXWqikOc9LYy7IIEM7AO+bsxkafxK4oOaoBkgW+7U/eK0w== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" ts-md5 "^1.2.2" "@theia/cli@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/cli/-/cli-0.17.0-next.c965552a.tgz#cf77310005d724a7e97c7490b1ea387b2d0d5d65" - integrity sha512-DHqkAd+3VY9RBgOG6DrdFgCyTeZxYZNSVikTctQvPIh16JNfNip93Gf5FJdBzKQ65vrxuqQYwN6tVi0nGRedYQ== + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/cli/-/cli-0.17.0-next.d0e00c5d.tgz#2796a4ae88d25f04d324f2ca406f13c813fc7341" + integrity sha512-VC78AmZ9dUG+KLd03Weba3TpAqZjXXJnTtMrwfb5zkBu9kDcxA970+xFAPPWvYumKtbR1kv/C4BLLYPSA9+aOA== dependencies: - "@theia/application-manager" "0.17.0-next.c965552a" - "@theia/application-package" "0.17.0-next.c965552a" + "@theia/application-manager" "0.17.0-next.d0e00c5d" + "@theia/application-package" "0.17.0-next.d0e00c5d" "@types/chai" "^4.2.7" "@types/mkdirp" "^0.5.2" "@types/mocha" "^5.2.7" @@ -1893,24 +1893,24 @@ serialize-javascript "^1.4.0" webpack-sources "^1.0.1" -"@theia/console@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/console/-/console-0.17.0-next.c965552a.tgz#90e26dc01d1641508c1a84a49113a65e1c7bce51" - integrity sha512-J7U5Wa5BMcvgMAacXzIOx46Wvy4WHAjnYTU5sJw6a7xuByTlBLjyerDWDCh7mjLc7zVtKLXGrODr6tJQ06Qfbg== +"@theia/console@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/console/-/console-0.17.0-next.d0e00c5d.tgz#91a07616532bf388ddf821ce2814b01bd3afb5b1" + integrity sha512-X8k6H8zD31k24z5RdsgNl6WInZk/vCCNBBCjy81dwz6PlF8S+B3wBMFOB2u1rJziyPo7YWMPxvBdC6rzdDm+Rg== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" anser "^1.4.7" -"@theia/core@0.17.0-next.c965552a", "@theia/core@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/core/-/core-0.17.0-next.c965552a.tgz#86b1d1aaa004ec223e1d5e96f3745f63305fd942" - integrity sha512-D1FgNDtJtutMESu7qr7bOUjbEKiIRePK/X6C9oNRDNP1g4VWn/xMxFcyoXR72itkkWUmDeu2P4XartCYLZ9zDQ== +"@theia/core@0.17.0-next.d0e00c5d", "@theia/core@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/core/-/core-0.17.0-next.d0e00c5d.tgz#c6b70051504989ebded7caa604ad65a313aae2e5" + integrity sha512-HbxjhQnvQKwAi4safEOsv2mavHc11LvN5tOZbu1xsmuC/ECbTSJx6u6YZJV5V2Gq/Aifzb8772Aoe1gGlNaiVQ== dependencies: "@babel/runtime" "^7.5.5" "@phosphor/widgets" "^1.9.3" "@primer/octicons-react" "^9.0.0" - "@theia/application-package" "0.17.0-next.c965552a" + "@theia/application-package" "0.17.0-next.d0e00c5d" "@types/body-parser" "^1.16.4" "@types/cookie" "^0.3.3" "@types/express" "^4.16.0" @@ -1950,9 +1950,9 @@ yargs "^11.1.0" "@theia/cpp@next": - version "0.16.0-next.f23b4017" - resolved "https://registry.yarnpkg.com/@theia/cpp/-/cpp-0.16.0-next.f23b4017.tgz#13333f22019ade3fb60d65c97e8ceeac3fa4cf9f" - integrity sha512-yw0BXd/7IrIsrju75+kg+VR6aj7E/0rtZmqsjoUQCQTO7unRq9I+bS+QG1fIhv8QjCw1jBVGvDBuS/XKIWge3A== + version "0.16.0-next.db05c684" + resolved "https://registry.yarnpkg.com/@theia/cpp/-/cpp-0.16.0-next.db05c684.tgz#c6158a4f7b296d440c4874cc6eb45946303ffe02" + integrity sha512-5Ae8qptSptJ+gKvT08Jc4XEEd1SWsoWI/i/EgbXsrKsCsLObHMGVVlLQKyZ1mavfDgDFO4fvYmbdVqM+r1hFAQ== dependencies: "@theia/core" next "@theia/editor" next @@ -1966,27 +1966,27 @@ "@theia/workspace" next string-argv "^0.1.1" -"@theia/debug@0.17.0-next.c965552a", "@theia/debug@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/debug/-/debug-0.17.0-next.c965552a.tgz#b63ed546455c328ec664d66989e1c89e1cfca27b" - integrity sha512-CCaGZ9T7hCzbT6FW2qwZn7JorBp/F2vjr5ARxUrfSbTZpEbkqayRppcso2Bn2nVeeUyzn1FAlF9JGbQQ+Fd1yw== +"@theia/debug@0.17.0-next.d0e00c5d", "@theia/debug@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/debug/-/debug-0.17.0-next.d0e00c5d.tgz#420ffb18ab13b0c9efb3722cda08c68131bdd0af" + integrity sha512-umSzVOdRPftv6FRfzEO5erpgu32z7JXBvLUywsBI1J+ipgyanxt5CJtfJTLNl4bWH5P++Al8zsQcxbLviINZ2A== dependencies: - "@theia/application-package" "0.17.0-next.c965552a" - "@theia/console" "0.17.0-next.c965552a" - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/markers" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" - "@theia/output" "0.17.0-next.c965552a" - "@theia/preferences" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/task" "0.17.0-next.c965552a" - "@theia/terminal" "0.17.0-next.c965552a" - "@theia/userstorage" "0.17.0-next.c965552a" - "@theia/variable-resolver" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/application-package" "0.17.0-next.d0e00c5d" + "@theia/console" "0.17.0-next.d0e00c5d" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/markers" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" + "@theia/output" "0.17.0-next.d0e00c5d" + "@theia/preferences" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/task" "0.17.0-next.d0e00c5d" + "@theia/terminal" "0.17.0-next.d0e00c5d" + "@theia/userstorage" "0.17.0-next.d0e00c5d" + "@theia/variable-resolver" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" "@types/p-debounce" "^1.0.1" jsonc-parser "^2.0.2" mkdirp "^0.5.0" @@ -1996,21 +1996,21 @@ unzip-stream "^0.3.0" vscode-debugprotocol "^1.32.0" -"@theia/editor@0.17.0-next.c965552a", "@theia/editor@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/editor/-/editor-0.17.0-next.c965552a.tgz#a027f98fce8612d50c2d2efa8c8f6f3b3791309f" - integrity sha512-MNe4ohCqoLtW/Xu1xnllFEKU8SmVPU9MMZlt9CinxSTszk5xzUnBVyGcYnDXpKRkGe/y4s2wndTog1M0rbYEjA== +"@theia/editor@0.17.0-next.d0e00c5d", "@theia/editor@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/editor/-/editor-0.17.0-next.d0e00c5d.tgz#8662099efa90159d986185e05b899fba1910dc05" + integrity sha512-MQzV7k+IOqTmDl2ybiUdBzvirKm2qezRxwRDnBaE1cXIJXHEvniJl8pzGr408i32vMAHpByeDO8WE16GPq8z2g== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/variable-resolver" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/variable-resolver" "0.17.0-next.d0e00c5d" "@types/base64-arraybuffer" "0.1.0" base64-arraybuffer "^0.1.5" "@theia/electron@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/electron/-/electron-0.17.0-next.c965552a.tgz#0a0ee5903c22155e6deae7754dc7691f95ba5c32" - integrity sha512-8+SLJOtmTri3FPWQk21z71FIGN3rq8vgTrXjlbZPUtiqQQ7TJgYocrPF2tJbXmIRRicRX01gZp723JQ/FVIgrg== + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/electron/-/electron-0.17.0-next.d0e00c5d.tgz#c7e06cd08c3454ffb57d3800efedff01bb86caeb" + integrity sha512-rHm4hC/J74A17c2fAjLYRIFaMXcHsU9irzy43LH3veAZhh1g0+8kiBNlk9OdWelY4bKib/yHjkgJ/cEfhqVHgg== dependencies: electron "^4.2.11" electron-download "^4.1.1" @@ -2021,26 +2021,26 @@ unzipper "^0.9.11" yargs "^11.1.0" -"@theia/file-search@0.17.0-next.c965552a", "@theia/file-search@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/file-search/-/file-search-0.17.0-next.c965552a.tgz#2a429337a207c64071b2456d198c4a0f12c5a43d" - integrity sha512-pCg+RUmROp2IAM5Z/1oR9pms50xgut1qQ7UsPXnZTQME4ErOeb7NUl0HPfkb1fcAAAYtoVoxIC9B+wIjyrUuLw== +"@theia/file-search@0.17.0-next.d0e00c5d", "@theia/file-search@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/file-search/-/file-search-0.17.0-next.d0e00c5d.tgz#c0ffc5b9215b561bc44223f860049489b990459f" + integrity sha512-yxuD73RHISx3cBEyJrjrv1J2CyneK7SnAYj6v8YzuVtfZtMLSvcON7k3YpRxFiCMOxXFWIPL27IyqoiGNrtNTQ== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" fuzzy "^0.1.3" vscode-ripgrep "^1.2.4" -"@theia/filesystem@0.17.0-next.c965552a", "@theia/filesystem@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/filesystem/-/filesystem-0.17.0-next.c965552a.tgz#94c9ef357c6aedd8a00d2de014980c6ada873ad8" - integrity sha512-b7Dyt/I5aFCiC5sYaVj2LwarRX1pGUVmVcRJuon53MzXImmVTKSi5LrJOQKmhtJTh4NKcO/Xz+BclAQi7kA2Wg== +"@theia/filesystem@0.17.0-next.d0e00c5d", "@theia/filesystem@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/filesystem/-/filesystem-0.17.0-next.d0e00c5d.tgz#5c5d51bdf223495c958a80436564ba1575fa747a" + integrity sha512-aR9hflpglzNf2aciziJpRs6DbfFgEgjjhWK+0pOpewAffwhQdihvdqI1ss/ygkDhhBjGg9DHmDUjpe2YaErZmw== dependencies: - "@theia/application-package" "0.17.0-next.c965552a" - "@theia/core" "0.17.0-next.c965552a" + "@theia/application-package" "0.17.0-next.d0e00c5d" + "@theia/core" "0.17.0-next.d0e00c5d" "@types/body-parser" "^1.17.0" "@types/rimraf" "^2.0.2" "@types/tar-fs" "^1.16.1" @@ -2061,17 +2061,18 @@ zip-dir "^1.0.2" "@theia/git@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/git/-/git-0.17.0-next.c965552a.tgz#a591dae52d0b7ce1ab890e2e13729b89baeaef2a" - integrity sha512-SrjxBuCHi1kb7//EpcGyBlT1vZSvtixwg4brFoyzjIxCGCtMVc80X0pA09ZiE0eXmwMjpIRmBwsU4pH0TKPFEg== + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/git/-/git-0.17.0-next.d0e00c5d.tgz#df07d36915ac85a621d7edf28a0f2b594eefe62e" + integrity sha512-DkX9MKJaOyluNmH2YGHpAwHilIfe629bO7eViPRp8LNFIpDkgoXLqk5oAbgg7+gHi1bdJ9CvzIT3vn0RybiRuQ== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/navigator" "0.17.0-next.c965552a" - "@theia/scm" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" + "@theia/scm" "0.17.0-next.d0e00c5d" + "@theia/scm-extra" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" "@types/diff" "^3.2.2" "@types/p-queue" "^2.3.1" diff "^3.4.0" @@ -2083,54 +2084,54 @@ p-queue "^2.4.2" ts-md5 "^1.2.2" -"@theia/languages@0.17.0-next.c965552a", "@theia/languages@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/languages/-/languages-0.17.0-next.c965552a.tgz#4d49a348341fff02432cf5165f54a9d3f964dd5e" - integrity sha512-sPQUdx3OkgXB/HdSiTP17KPFT7kakM910b3n79CefGF/suCTzQfRBMhAB+Vxe3JXhlNZHIX7AYWnmMKBoKTFsg== +"@theia/languages@0.17.0-next.d0e00c5d", "@theia/languages@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/languages/-/languages-0.17.0-next.d0e00c5d.tgz#436a2d2d1730a600b4f883187be7029396f17bbb" + integrity sha512-0nTXpK6CqWo7ItzhtXes76zn1WUg6TESD8RBimuZrvSnix+cEsRolPQoUldraW9xGjtFscCrmzFmow/NHEiPYQ== dependencies: - "@theia/application-package" "0.17.0-next.c965552a" - "@theia/core" "0.17.0-next.c965552a" - "@theia/output" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/application-package" "0.17.0-next.d0e00c5d" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/output" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" "@typefox/monaco-editor-core" "^0.18.0-next" "@types/uuid" "^3.4.3" monaco-languageclient "^0.10.2" uuid "^3.2.1" -"@theia/markers@0.17.0-next.c965552a", "@theia/markers@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/markers/-/markers-0.17.0-next.c965552a.tgz#02d6aef26bb86aa7393052a5410f77ffabb1455b" - integrity sha512-tidnHAhh9fTRmHdD3JQItjs4WJUbon0ynvXTFUjz+URm0ps0B8pcrbTUEnutvMCSvVp6rPUE7bV6n0Dn9ejxTw== +"@theia/markers@0.17.0-next.d0e00c5d", "@theia/markers@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/markers/-/markers-0.17.0-next.d0e00c5d.tgz#5d58ce3818df0bf5857e45df0172e8285114638b" + integrity sha512-mGfrsZRWnJ0mmXA7p8BkZzjWsVAB7fqq3ZF9qTikCk76Rtl2VZYzhCPxJUQgIcRtursVmAPcTkDPnlyzXWWPxQ== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/navigator" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" -"@theia/messages@0.17.0-next.c965552a", "@theia/messages@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/messages/-/messages-0.17.0-next.c965552a.tgz#df6da49a7138cc1336b91525f7d8c506a6bfae0e" - integrity sha512-btm9WRyOdwC86IE4Ej2ULta2/X0jxy+4Shz8KeG/TIsZa7xAFVr3/3CZUbVCoteQgRXnQPmniCAJW8TGTa2z7g== +"@theia/messages@0.17.0-next.d0e00c5d", "@theia/messages@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/messages/-/messages-0.17.0-next.d0e00c5d.tgz#3cc5bd00841959e2ac5a2793655a9c97927fa5a0" + integrity sha512-he7uu4dbEyWbllZWxugyykD0JwNq5ojPG0ZmTE5gEg4MGbnWhqwrZkBilP69ip7b/XMBOgqph9CW1fRrEBuvkg== dependencies: - "@theia/core" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" lodash.throttle "^4.1.1" markdown-it "^8.4.0" react-perfect-scrollbar "^1.5.3" ts-md5 "^1.2.2" -"@theia/monaco@0.17.0-next.c965552a", "@theia/monaco@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/monaco/-/monaco-0.17.0-next.c965552a.tgz#8a316c8b2ad615975becfbcc4be4f1fbbe6241b7" - integrity sha512-ybxM/OUaZ+bSATomDoBVOU++lwoDI6phrgTRdTgD0/IwCelu4ZBRMw/0Kf0toPaJbIrzrKvi2tCmQQW/h0j8IA== +"@theia/monaco@0.17.0-next.d0e00c5d", "@theia/monaco@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/monaco/-/monaco-0.17.0-next.d0e00c5d.tgz#abeabfbff3cafa65582d788d35864e6c895872ad" + integrity sha512-CAR/q2Lk1N/pYYsbpI+M5apNst7HRkWiAC/eehow45lbF1Wf1ttRwOhXKqlT1b+y2flDT7+m+eQUF8IBmUHsZQ== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/markers" "0.17.0-next.c965552a" - "@theia/outline-view" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/markers" "0.17.0-next.d0e00c5d" + "@theia/outline-view" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" deepmerge "2.0.1" fast-plist "^0.1.2" idb "^4.0.5" @@ -2140,14 +2141,14 @@ onigasm "2.2.1" vscode-textmate "^4.0.1" -"@theia/navigator@0.17.0-next.c965552a", "@theia/navigator@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/navigator/-/navigator-0.17.0-next.c965552a.tgz#5fbe9241fe160993316268887ced7fc56042109c" - integrity sha512-jIhLPIfyyqr480+HcO675O32yM6XXUbxO/6BsawYmMHOxUpRU5md8LcddwCUrX2wPStQcVHxy634sdYQHFPTgA== +"@theia/navigator@0.17.0-next.d0e00c5d", "@theia/navigator@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/navigator/-/navigator-0.17.0-next.d0e00c5d.tgz#44a688fee696ad5d5bc31f08d2c329f5237c24c6" + integrity sha512-TfC9Y8hR6yMqJ8H6fCNhX/zDdvAoQiaZB+pyT/IC2aw0BH1yrYmsBcO1Dm2nUEi72MsgI7zmbggQS3f4DCfsaQ== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" fuzzy "^0.1.3" minimatch "^3.0.4" @@ -2158,58 +2159,58 @@ dependencies: nan "2.10.0" -"@theia/outline-view@0.17.0-next.c965552a", "@theia/outline-view@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/outline-view/-/outline-view-0.17.0-next.c965552a.tgz#8bbe99426fa6baa4e540acd938bac1167785bceb" - integrity sha512-cZzbaqsrt2ImXhLRpqXixZJ+8qSFHrjSDR3KVOBQHkvpC9TFsbTfvRmEao3Mysw/EB/QaGVswm92bhNybDLIPg== +"@theia/outline-view@0.17.0-next.d0e00c5d", "@theia/outline-view@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/outline-view/-/outline-view-0.17.0-next.d0e00c5d.tgz#00bf0dceade1bd88102de4c2001d7c1db48d4358" + integrity sha512-k8xSq31fFBnTgBTJHiIo8FEJpApROJZC/oqdkfCyvyAK+RzjWmkzS7ILQY8r1aM/a31OQfaNiPW/LyrmHnT8Cg== dependencies: - "@theia/core" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" -"@theia/output@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/output/-/output-0.17.0-next.c965552a.tgz#22905afc938324ac71f57dfd7d68c31c25f18957" - integrity sha512-FocNO/uqis6L1HLO18qxo5Ewqulhi5o6Xl8yC39L4fHVfpyzn90Ei5UnfNL1x9aIwqRN8Zf1dxfUjY7HCmMXrw== +"@theia/output@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/output/-/output-0.17.0-next.d0e00c5d.tgz#9b250d0deb49d4978b055806837c06c9e25ec745" + integrity sha512-sNS5TRkGEK+sd2x7r+8WK52wwi1ptNM6F/shX2QnRz7L/dJzN6Y5af0tcU/CPF2BghCvBBIYa0Cl3eKSomlOEw== dependencies: - "@theia/core" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" "@theia/plugin-ext-vscode@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/plugin-ext-vscode/-/plugin-ext-vscode-0.17.0-next.c965552a.tgz#14e05785efa255ebaa0f38ad869e81148538445a" - integrity sha512-cQrf01QMMj+tFKP+RdLnl0N9ObRzit1ovULC0Bv0J3SL/C3DFlYcEKNcc3p2Q7z8Lf/zRjY35ixSX6AKtV7uEg== + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/plugin-ext-vscode/-/plugin-ext-vscode-0.17.0-next.d0e00c5d.tgz#8591bbb385608a428fded26264409555e02d740e" + integrity sha512-/mVOs6NFB0eaJOaE5j1VHZjN4G00Gm9z8AckCwxXjJH7TEOHTIw6jEE1MnG3lqQzh/uPAOr8ovnsChVSzN4aeA== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" - "@theia/plugin" "0.17.0-next.c965552a" - "@theia/plugin-ext" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" + "@theia/plugin" "0.17.0-next.d0e00c5d" + "@theia/plugin-ext" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" "@types/request" "^2.0.3" request "^2.82.0" -"@theia/plugin-ext@0.17.0-next.c965552a", "@theia/plugin-ext@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/plugin-ext/-/plugin-ext-0.17.0-next.c965552a.tgz#bb35a78681cc812613a6ee6e6b707345dc62d3f5" - integrity sha512-7/d2hhj5pEZZLoo1rNK9bh0Wf7aWfl6PA8t6Km4+gUmm/szBCOzUpG9DXMcF1va82PrzTOzowHVjWOKE3LlqLw== +"@theia/plugin-ext@0.17.0-next.d0e00c5d", "@theia/plugin-ext@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/plugin-ext/-/plugin-ext-0.17.0-next.d0e00c5d.tgz#ff8177a3290ecbce6f7aa0397cb95559e8af7c63" + integrity sha512-n0PpUzUHHvzwEYHbnbbCyv+yTFKytXONRtvSqorGK3Fyp1P4GeCUHeTaLn5a5p4ja6t74wm3NhJJBUgwuRmgCw== dependencies: - "@theia/callhierarchy" "0.17.0-next.c965552a" - "@theia/core" "0.17.0-next.c965552a" - "@theia/debug" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/file-search" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/languages" "0.17.0-next.c965552a" - "@theia/markers" "0.17.0-next.c965552a" - "@theia/messages" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" - "@theia/navigator" "0.17.0-next.c965552a" - "@theia/output" "0.17.0-next.c965552a" - "@theia/plugin" "0.17.0-next.c965552a" - "@theia/preferences" "0.17.0-next.c965552a" - "@theia/scm" "0.17.0-next.c965552a" - "@theia/search-in-workspace" "0.17.0-next.c965552a" - "@theia/task" "0.17.0-next.c965552a" - "@theia/terminal" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/callhierarchy" "0.17.0-next.d0e00c5d" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/debug" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/file-search" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/languages" "0.17.0-next.d0e00c5d" + "@theia/markers" "0.17.0-next.d0e00c5d" + "@theia/messages" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" + "@theia/output" "0.17.0-next.d0e00c5d" + "@theia/plugin" "0.17.0-next.d0e00c5d" + "@theia/preferences" "0.17.0-next.d0e00c5d" + "@theia/scm" "0.17.0-next.d0e00c5d" + "@theia/search-in-workspace" "0.17.0-next.d0e00c5d" + "@theia/task" "0.17.0-next.d0e00c5d" + "@theia/terminal" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" "@types/connect" "^3.4.32" "@types/mime" "^2.0.1" "@types/serve-static" "^1.13.3" @@ -2228,42 +2229,53 @@ vscode-debugprotocol "^1.32.0" vscode-textmate "^4.0.1" -"@theia/plugin@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/plugin/-/plugin-0.17.0-next.c965552a.tgz#b8ecefeee1e95845ab9cd31e47493f4a11c12a05" - integrity sha512-alPJwaWHLFCxQ0NS5cjGZmqyNWSlrFHWjC5/M+oHML+whGpGfWSPa8A6ZPKVaZZ84BTKssx6+hSaELRI99NkMg== +"@theia/plugin@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/plugin/-/plugin-0.17.0-next.d0e00c5d.tgz#efa25bb91f5904461c03aeccf6d615704c0b4719" + integrity sha512-sMzb9rAIFXfsyyFJN3QOe3BAnYF5sd9SFeSWqX/nhm1llZSRPVR1RfyI7otKCNfrFd+9+KVgoEfwcb+rW0lToQ== -"@theia/preferences@0.17.0-next.c965552a", "@theia/preferences@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/preferences/-/preferences-0.17.0-next.c965552a.tgz#2436b6b25b5224208b242c784a4d41ed8498858a" - integrity sha512-SZc2fpfCBg5KUDQO6lLkIjpmAvNaBMhUrcBQj2X2K1BWGRhDpvgQVOS1iu+Pzz1L0b6pKi+ZK6RMJA1TJobz4A== +"@theia/preferences@0.17.0-next.d0e00c5d", "@theia/preferences@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/preferences/-/preferences-0.17.0-next.d0e00c5d.tgz#5c66dd4fe76de5325d381f1e896d54a0ebbc9f4f" + integrity sha512-1Cicd9U8k90B8r4neupilWyAb68rJ5yO8o0N68qFH71wb95ndn/ZwDyhSqlOAyt1WUCFghhtgXEYuXxcaqI7kw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" - "@theia/userstorage" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" + "@theia/userstorage" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" jsonc-parser "^2.0.2" -"@theia/process@0.17.0-next.c965552a", "@theia/process@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/process/-/process-0.17.0-next.c965552a.tgz#9fafd8a0abc3616e85244bddde88f6aa49575421" - integrity sha512-50rejixnoSnmr3GObsxsOhyCN2YPpn9MfHPn9FXDwuwXCFxD+sODda3sorAHHxaEx0vojdVLnDqm/EBVLLPeOg== +"@theia/process@0.17.0-next.d0e00c5d", "@theia/process@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/process/-/process-0.17.0-next.d0e00c5d.tgz#a2c76e670b6f00639b68c7a7abc10bec68e17e02" + integrity sha512-unTWSjr/LEgclSZSPMJ0FPerrRoZWvjm4cq+Zc7613qIIGK9vvS5iBrYqdbJX/jjRBIfE+rUllMe7QIwDJdbJg== dependencies: - "@theia/core" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" "@theia/node-pty" "0.7.8-theia004" string-argv "^0.1.1" -"@theia/scm@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/scm/-/scm-0.17.0-next.c965552a.tgz#b4e6b6f73bf7754987b36cea930ee3dc2a52d5af" - integrity sha512-RpgfG7q5Gfbe0yaOGss0F52G32pLGFrdJ/vDYWn2M7Qtb++bEBeMCMyy+SA+zgrzbu1Gn2kJvKu6MFBziS74zQ== +"@theia/scm-extra@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/scm-extra/-/scm-extra-0.17.0-next.d0e00c5d.tgz#f43814fc677aa4155e6037631546f0cddeb67d4c" + integrity sha512-5mCGTfqBah0ba/5yjxi3LT37JTnCd77T75/3GB3HL/JNQFfOOt1zKTXATulP4Vk0y71WOGnA6ZGH1tlXZOVvhw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/navigator" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" + "@theia/scm" "0.17.0-next.d0e00c5d" + +"@theia/scm@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/scm/-/scm-0.17.0-next.d0e00c5d.tgz#94d9473da26b0a009ca7eac2df832ed951628d4a" + integrity sha512-bqvWGbuNgOoqMsJws0HXtOVOCXGhMaFPOGrNxULfL5Vbwy0m8Ub7XIgHoVDwuFNL54eynabpvqYg5FNlPSwv9w== + dependencies: + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" "@types/diff" "^3.2.2" "@types/p-debounce" "^1.0.1" diff "^3.4.0" @@ -2271,74 +2283,76 @@ react-autosize-textarea "^7.0.0" ts-md5 "^1.2.2" -"@theia/search-in-workspace@0.17.0-next.c965552a", "@theia/search-in-workspace@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/search-in-workspace/-/search-in-workspace-0.17.0-next.c965552a.tgz#c90c6a695d7a443e72b470d51106272d958edf89" - integrity sha512-38TuDlggF4nn+rY92VzuXUhCvlyJxcYhy6FEMYmQEUxeDmHcOwOHiJfs0uMRlfPoEaA84vKqgECstK840rBrSA== +"@theia/search-in-workspace@0.17.0-next.d0e00c5d", "@theia/search-in-workspace@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/search-in-workspace/-/search-in-workspace-0.17.0-next.d0e00c5d.tgz#3bd963bf95e227b2fdb340ed672fcd69f2fa8f8d" + integrity sha512-nVLsBGI1sEeAzEgdwK9/xoCUC9kst+29HGkB/sFgdbD7RK0I/ZS4n6jBTNI6kwoay5+/WpJ0BiOQH7L7oL15Pw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/navigator" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/navigator" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" vscode-ripgrep "^1.2.4" -"@theia/task@0.17.0-next.c965552a", "@theia/task@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/task/-/task-0.17.0-next.c965552a.tgz#826fcd51460f76e95bb73c842bacc02481a0f51b" - integrity sha512-nEpv5zmAHLPabXMojBlVu2BBsgBbWH0/+fY3aWu9irqtagfdP1dGs1zGYuMhvv9gVjdDiccMGojJ+yvlV2xEHg== +"@theia/task@0.17.0-next.d0e00c5d", "@theia/task@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/task/-/task-0.17.0-next.d0e00c5d.tgz#d1316ba2729cde521ad2a95e6946eadba6179a31" + integrity sha512-fJo8ekUVIHRGf/TaLXtZN7fNkw/CQ/gkE50YeIst+/T582+pHn9K0ddNpB5yxPovNaIW0h8LjsJ3xST/fql7jw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/markers" "0.17.0-next.c965552a" - "@theia/monaco" "0.17.0-next.c965552a" - "@theia/preferences" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/terminal" "0.17.0-next.c965552a" - "@theia/variable-resolver" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/markers" "0.17.0-next.d0e00c5d" + "@theia/monaco" "0.17.0-next.d0e00c5d" + "@theia/preferences" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/terminal" "0.17.0-next.d0e00c5d" + "@theia/variable-resolver" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" ajv "^6.5.3" jsonc-parser "^2.0.2" p-debounce "^2.1.0" vscode-uri "^1.0.8" -"@theia/terminal@0.17.0-next.c965552a", "@theia/terminal@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/terminal/-/terminal-0.17.0-next.c965552a.tgz#f092667838deac1697be09993ce8eaf048973277" - integrity sha512-YbMCnNHPZGe9urYhRZU2WOxRxhSZitsqkXzXzGHViJD0WId7NylVY3BLmEvY++mbA0Zgz5Shc1pU7Jysvkk6dA== +"@theia/terminal@0.17.0-next.d0e00c5d", "@theia/terminal@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/terminal/-/terminal-0.17.0-next.d0e00c5d.tgz#c834563a7c68f70bffb60cbeb3044d95bb32bba8" + integrity sha512-PeqMP35xAPVzjJjP/smWnWOEvW3wZAoSiu3eVGl0qyAi8uAQgskol/mO54Zk9qh2gX+3yQ613ykfela8cVhAtw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/editor" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/process" "0.17.0-next.c965552a" - "@theia/workspace" "0.17.0-next.c965552a" - xterm "3.13.0" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/editor" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/process" "0.17.0-next.d0e00c5d" + "@theia/workspace" "0.17.0-next.d0e00c5d" + xterm "^4.4.0" + xterm-addon-fit "^0.3.0" + xterm-addon-search "^0.5.0" -"@theia/userstorage@0.17.0-next.c965552a": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/userstorage/-/userstorage-0.17.0-next.c965552a.tgz#cd8b9123a53fca494c4e4d585bed8a2b3b25a6c8" - integrity sha512-X3n9omgMl9eEMxwgrImZ2r/LMEJGs0M0/AulZOdvhr5G0cUDqAJAiqsc+EAnJbHfmufloTgC6e+syWQGF/ocCg== +"@theia/userstorage@0.17.0-next.d0e00c5d": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/userstorage/-/userstorage-0.17.0-next.d0e00c5d.tgz#e633fa6f1828f3f4c1408990205b7734e395b5af" + integrity sha512-74RctvMleDA8Kt8AVo2cf+ufSNM/K6/BsHBGbQKcdBWMwr62TeQsS68/EO49iegErkJjQ+8ohpcBx+s9GjxMNw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" -"@theia/variable-resolver@0.17.0-next.c965552a", "@theia/variable-resolver@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/variable-resolver/-/variable-resolver-0.17.0-next.c965552a.tgz#5e0f4153a096229fe454a8a0ba4e47c236995057" - integrity sha512-GvU69JbuRkHAEGkQ4+j0QXACbDu6mbkzDJx2AdGUa0feqGslIzEB+LC50b/PSGL8E4NILm7cWriu+G0M59PlEg== +"@theia/variable-resolver@0.17.0-next.d0e00c5d", "@theia/variable-resolver@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/variable-resolver/-/variable-resolver-0.17.0-next.d0e00c5d.tgz#3c90a02d76e60bb52e673296681307c94b8f4675" + integrity sha512-28ZOwNTdfeEsx5OVjH4ZQ4qvQfTo3BXzSVEcNX5Qtc36PGHkqkHddgHBAN71HF7/5sHdeqkKDcbpSTBrqjixcw== dependencies: - "@theia/core" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" -"@theia/workspace@0.17.0-next.c965552a", "@theia/workspace@next": - version "0.17.0-next.c965552a" - resolved "https://registry.yarnpkg.com/@theia/workspace/-/workspace-0.17.0-next.c965552a.tgz#01b21a24956560fe99a3f660bd0866ea8dca6678" - integrity sha512-qaYCb9b+yfL/ivAeLHZI2RCplIAFM4eIoA643durhvx4OfLheKz51z58tgKg/LOeWVIlZwUGWbxBP9+q8m4VSg== +"@theia/workspace@0.17.0-next.d0e00c5d", "@theia/workspace@next": + version "0.17.0-next.d0e00c5d" + resolved "https://registry.yarnpkg.com/@theia/workspace/-/workspace-0.17.0-next.d0e00c5d.tgz#073ebff4f76475141485e557b3c20251f972d1de" + integrity sha512-LvOXtsp5P/xGUJdg0EjRJIBwONs7oxamG/t8vaUTAsXyUQcFXJSYpjBYoTp+THgMWcsGs1WlrJQRFtQKfUPGpw== dependencies: - "@theia/core" "0.17.0-next.c965552a" - "@theia/filesystem" "0.17.0-next.c965552a" - "@theia/variable-resolver" "0.17.0-next.c965552a" + "@theia/core" "0.17.0-next.d0e00c5d" + "@theia/filesystem" "0.17.0-next.d0e00c5d" + "@theia/variable-resolver" "0.17.0-next.d0e00c5d" ajv "^6.5.3" jsonc-parser "^2.0.2" moment "^2.21.0" @@ -2380,9 +2394,9 @@ "@types/chai" "*" "@types/chai@*", "@types/chai@^4.2.7": - version "4.2.9" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.9.tgz#194332625ed2ae914aef00b8d5ca3b77e7924cc6" - integrity sha512-NeXgZj+MFL4izGqA4sapdYzkzQG+MtGra9vhQ58dnmDY++VgJaRUws+aLVV5zRJCYJl/8s9IjMmhiUw1WsKSmw== + version "4.2.10" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.10.tgz#1122da40faabb81795580dc9f06c1e71e2ebbbe4" + integrity sha512-TlWWgb21+0LdkuFqEqfmy7NEgfB/7Jjux15fWQAh3P93gbmXuwTM/vxEdzW89APIcI2BgKR48yjeAkdeH+4qvQ== "@types/connect@*", "@types/connect@^3.4.32": version "3.4.33" @@ -2427,9 +2441,9 @@ "@types/range-parser" "*" "@types/express@^4.16.0": - version "4.17.2" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c" - integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA== + version "4.17.3" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.3.tgz#38e4458ce2067873b09a73908df488870c303bd9" + integrity sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "*" @@ -2531,14 +2545,14 @@ integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== "@types/node@*", "@types/node@>= 8": - version "13.7.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113" - integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA== + version "13.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589" + integrity sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ== "@types/node@^10.12.18", "@types/node@^10.14.22": - version "10.17.16" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.16.tgz#ee96ddac1a38d98d2c8a71c7df0cdad5758e8993" - integrity sha512-A4283YSA1OmnIivcpy/4nN86YlnKRiQp8PYwI2KdPCONEBN093QTb0gCtERtkLyVNGKKIGazTZ2nAmVzQU51zA== + version "10.17.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.17.tgz#7a183163a9e6ff720d86502db23ba4aade5999b8" + integrity sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q== "@types/p-debounce@^1.0.1": version "1.0.1" @@ -2681,9 +2695,9 @@ "@types/tar-stream" "*" "@types/tar-stream@*": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-1.6.1.tgz#67d759068ff781d976cad978893bb7a334ec8809" - integrity sha512-pYCDOPuRE+4tXFk1rSMYiuI+kSrXiJ4av1bboQbkcEBA2rqwEWfIn9kdMSH+5nYu58WksHuxwx+7kVbtg0Le7w== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-2.1.0.tgz#884b1cbe6c35ff459c05a5eba86b406805943ef6" + integrity sha512-s1UQxQUVMHbSkCC0X4qdoiWgHF8DoyY1JjQouFsnk/8ysoTdBaiCHud/exoAZzKDbzAXVc+ah6sczxGVMAohFw== dependencies: "@types/node" "*" @@ -2955,9 +2969,9 @@ accepts@~1.3.7: negotiator "0.6.2" acorn@^6.2.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" - integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== agent-base@4, agent-base@^4.3.0: version "4.3.0" @@ -3333,11 +3347,6 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3775,14 +3784,14 @@ babel-plugin-dynamic-import-node@^2.3.0: object.assign "^4.1.0" babel-plugin-emotion@^10.0.27: - version "10.0.28" - resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.28.tgz#731133577795ea04e5b1d11aff247fa0ad3fd364" - integrity sha512-h25EMmPxYVNOgsEkGIjCv2Ok+HzW/e/b5lf2v2U17T9k6y6g0ku3TG9b+jy94ZrqMh+b/njRF4uOQrwVr28QfQ== + version "10.0.29" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.29.tgz#89d8e497091fcd3d10331f097f1471e4cc3f35b4" + integrity sha512-7Jpi1OCxjyz0k163lKtqP+LHMg5z3S6A7vMBfHnF06l2unmtsOmFDzZBpGf0CWo1G4m8UACfVcDJiSiRuu/cSw== dependencies: "@babel/helper-module-imports" "^7.0.0" - "@emotion/hash" "0.7.4" + "@emotion/hash" "0.8.0" "@emotion/memoize" "0.7.4" - "@emotion/serialize" "^0.11.15" + "@emotion/serialize" "^0.11.16" babel-plugin-macros "^2.0.0" babel-plugin-syntax-jsx "^6.18.0" convert-source-map "^1.5.0" @@ -4530,13 +4539,13 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: caniuse-db "^1.0.30000639" electron-to-chromium "^1.2.7" -browserslist@^4.8.3, browserslist@^4.8.5: - version "4.9.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.0.tgz#ff85c390889e0f754d7bd8ad13412575cdcf5dc7" - integrity sha512-seffIXhwgB84+OCeT/aMjpZnsAsYDiMSC+CEs3UkF8iU64BZGYcu+TZYs/IBpo4nRi0vJywUJWYdbTsOhFTweg== +browserslist@^4.8.3, browserslist@^4.8.5, browserslist@^4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.1.tgz#01ffb9ca31a1aef7678128fc6a2253316aa7287c" + integrity sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw== dependencies: caniuse-lite "^1.0.30001030" - electron-to-chromium "^1.3.361" + electron-to-chromium "^1.3.363" node-releases "^1.1.50" btoa-lite@^1.0.0: @@ -4592,9 +4601,9 @@ buffer@^4.3.0: isarray "^1.0.0" buffer@^5.2.1: - version "5.4.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" - integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + version "5.5.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" + integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -4794,14 +4803,14 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30001030" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001030.tgz#0d832cbd1d8e6bdf6bd3f25d531b05c5787dbeb7" - integrity sha512-NegSvVCGfkDpHC3AosHhhn2CDVJoJXiH3LlMTKjc5GAwugaMHvsQLNItUD4RBOAvvOrw3Uz/XlYjT1ynW0rviA== + version "1.0.30001033" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001033.tgz#383288df833c85d83c2bfc3469245ec1fa1f881e" + integrity sha512-2ZReq+OHqHhsIQSiv8OVNhQ6Ht9eYJpwblZydHV8nI44Od6J5YUl3J9Wxvjry/v969jCHH5fR9+C6FwJ41XbOQ== caniuse-lite@^1.0.30001030: - version "1.0.30001030" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001030.tgz#78076c4c6d67d3e41d6eb9399853fb27fe6e44ee" - integrity sha512-QGK0W4Ft/Ac+zTjEiRJfwDNATvS3fodDczBXrH42784kcfqcDKpEPfN08N0HQjrAp8He/Jw8QiSS9QRn7XAbUw== + version "1.0.30001033" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001033.tgz#60c328fb56860de60f9a2cb419c31fb80587cba0" + integrity sha512-8Ibzxee6ibc5q88cM1usPsMpJOG5CTq0s/dKOmlekPbDGKt+UrnOOTPSjQz3kVo6yL7N4SB5xd+FGLHQmbzh6A== caseless@~0.12.0: version "0.12.0" @@ -5629,18 +5638,18 @@ css-loader@~0.26.1: source-list-map "^0.1.7" css-selector-tokenizer@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d" - integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA== + version "0.7.2" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz#11e5e27c9a48d90284f22d45061c303d7a25ad87" + integrity sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw== dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" + cssesc "^3.0.0" + fastparse "^1.1.2" + regexpu-core "^4.6.0" -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" - integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== "cssnano@>=2.6.1 <4", cssnano@^3.10.0: version "3.10.0" @@ -6209,10 +6218,10 @@ electron-store@^2.0.0: dependencies: conf "^2.0.0" -electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.361: - version "1.3.363" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.363.tgz#08756873e49446a92e0cee6c3cd9eb3c52043826" - integrity sha512-4w19wPBkeunBjOA53lNFT36IdOD3Tk1OoIDtTX+VToJUUDX42QfuhtsNKXv25wmSnoBOExM3kTbj7/WDNBwHuQ== +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.363: + version "1.3.374" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.374.tgz#eb539bfcac8ec51de417038548c3bc93745134bb" + integrity sha512-M4Y9onOJ4viRk3A4M/LH+r9+1zQioRZJvGJn/S/o7KaBJQLgFiaHMUlDwM0QMJd5ki6hFxKiWdC6jp5Ub0zMmw== electron@^4.2.11: version "4.2.12" @@ -6732,7 +6741,7 @@ fast-plist@^0.1.2: resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8" integrity sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg= -fastparse@^1.1.1: +fastparse@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== @@ -6893,9 +6902,9 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: pkg-dir "^3.0.0" find-cache-dir@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.0.tgz#4d74ed1fe9ef1731467ca24378e8f8f5c8b6ed11" - integrity sha512-PtXtQb7IrD8O+h6Cq1dbpJH5NzD8+9keN1zZ0YlpDzl1PwXEJEBj6u1Xa92t1Hwluoozd9TNKul5Hi2iqpsWwg== + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== dependencies: commondir "^1.0.1" make-dir "^3.0.2" @@ -6979,9 +6988,9 @@ flatten@^1.0.2: integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== flow-parser@^0.*: - version "0.119.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.119.1.tgz#c120c402e164c7e9379a8d84b2c838adaaa0e610" - integrity sha512-yFd4z6ZBXq//TJo/gtSzGKhz6wEVeI2m+6JB25JzXuRAOhM5Ze4xFkc3FSIStbYjrAx4H1IUiUTI/yy30oKp8A== + version "0.120.1" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.120.1.tgz#26781130575fee4a45ecae0240b9d037e2746b72" + integrity sha512-t5y9QoOegJuY+LCIjh0p6SGF7ItsxG5ycQApTSqWloutUZQ2gC0f6wMu91dab0/SSj2vH41bu5pDTLuvtP49ng== flush-write-stream@^1.0.0: version "1.1.1" @@ -7849,9 +7858,9 @@ homedir-polyfill@^1.0.1: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: - version "2.8.7" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.7.tgz#4d2e0d5248e1cfabc984b0f6a6d75fe36e679511" - integrity sha512-ChkjQtKJ3GI6SsI4O5jwr8q8EPrWCnxuc4Tbx+vRI5x6mDOpjKKltNo1lRlszw3xwgTOSns1ZRBiMmmwpcvLxg== + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== html-comment-regex@^1.1.0: version "1.1.2" @@ -9280,11 +9289,6 @@ make-dir@^3.0.2: dependencies: semver "^6.0.0" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - make-fetch-happen@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" @@ -9882,9 +9886,9 @@ ncp@^2.0.0, ncp@~2.0.0: integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= needle@^2.2.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528" - integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w== + version "2.3.3" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" + integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -10042,9 +10046,9 @@ node-pre-gyp@^0.12.0: tar "^4" node-releases@^1.1.50: - version "1.1.50" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.50.tgz#803c40d2c45db172d0410e4efec83aa8c6ad0592" - integrity sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ== + version "1.1.51" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.51.tgz#70d0e054221343d2966006bfbd4d98622cc00bd0" + integrity sha512-1eQEs6HFYY1kMXQPOLzCf7HdjReErmvn85tZESMczdCNVWP3Y7URYLBAyYynuI7yef1zj4HN5q+oB2x67QU0lw== dependencies: semver "^6.3.0" @@ -10074,9 +10078,9 @@ noop-logger@^0.1.1: abbrev "1" nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== dependencies: abbrev "1" osenv "^0.1.4" @@ -11345,9 +11349,9 @@ proxy-addr@~2.0.5: ipaddr.js "1.9.1" proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== prr@~1.0.1: version "1.0.1" @@ -11884,10 +11888,10 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.2: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" - integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91" + integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g== regenerator-transform@^0.10.0: version "0.10.1" @@ -11898,12 +11902,13 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" private "^0.1.6" -regenerator-transform@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" - integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== +regenerator-transform@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.2.tgz#949d9d87468ff88d5a7e4734ebb994a892de1ff2" + integrity sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ== dependencies: - private "^0.1.6" + "@babel/runtime" "^7.8.4" + private "^0.1.8" regex-cache@^0.4.2: version "0.4.4" @@ -11920,15 +11925,6 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -12583,7 +12579,7 @@ source-map-support@^0.4.15, source-map-support@^0.4.18: dependencies: source-map "^0.5.6" -source-map-support@^0.5.6, source-map-support@~0.5.12: +source-map-support@~0.5.12: version "0.5.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== @@ -13117,9 +13113,9 @@ terser-webpack-plugin@^1.4.3: worker-farm "^1.7.0" terser@^4.1.2: - version "4.6.4" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.4.tgz#40a0b37afbe5b57e494536815efa68326840fc00" - integrity sha512-5fqgBPLgVHZ/fVvqRhhUp9YUiGXhFJ9ZkrZWD9vQtFBR4QIGTnbsb+/kKqSqfgp3WnBwGWAFnedGTtmX1YTn0w== + version "4.6.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.6.tgz#da2382e6cafbdf86205e82fb9a115bd664d54863" + integrity sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -13352,17 +13348,6 @@ ts-md5@^1.2.2: resolved "https://registry.yarnpkg.com/ts-md5/-/ts-md5-1.2.7.tgz#b76471fc2fd38f0502441f6c3b9494ed04537401" integrity sha512-emODogvKGWi1KO1l9c6YxLMBn6CEH3VrH5mVPIyOtxBG52BvV4jP3GWz6bOZCz61nLgBc3ffQYE4+EHfCD+V7w== -ts-node@^8.6.2: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35" - integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg== - dependencies: - arg "^4.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.6" - yn "3.1.1" - tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.11.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" @@ -13820,9 +13805,9 @@ vm-browserify@^1.0.1: integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== vscode-debugadapter@^1.26.0, vscode-debugadapter@^1.37.1: - version "1.39.0" - resolved "https://registry.yarnpkg.com/vscode-debugadapter/-/vscode-debugadapter-1.39.0.tgz#8b2a1afb287e9be37e9fe88e2c05eb35f8724425" - integrity sha512-i8gU7H3N4EupmX4dMgh1DUS8PAy9AnB1je9QvZ4oWCbwrdREtOiB23cDGPRzyJDmcgoZLyikkrP05SyBCtRERA== + version "1.39.1" + resolved "https://registry.yarnpkg.com/vscode-debugadapter/-/vscode-debugadapter-1.39.1.tgz#c5d2565a1f27c95c6d2fc7a893ce94942570dc95" + integrity sha512-+WYpOcY0PiAEBILf6nIwbNVF8ig8gugWTKWhQ7Ds1884JXpVL336pG0xH66Nc1Z1W/KSzuXarm1gtccdwl6PKw== dependencies: mkdirp "^0.5.1" vscode-debugprotocol "1.39.0" @@ -13960,9 +13945,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-map "~0.6.1" webpack@^4.0.0: - version "4.41.6" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.6.tgz#12f2f804bf6542ef166755050d4afbc8f66ba7e1" - integrity sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA== + version "4.42.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" + integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -14145,9 +14130,9 @@ ws@^6.1.0: async-limiter "~1.0.0" ws@^7.1.2: - version "7.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" - integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A== + version "7.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" + integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== xdg-basedir@^2.0.0: version "2.0.0" @@ -14179,10 +14164,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.13.0.tgz#d0e06c3cf4c1f079aa83f646948457db3b04220b" - integrity sha512-FZVmvkkbkky3zldJ2NNOZ9h8jirtbGTlF4sIKMDrejR4wPsVZ3o4F++DQVkdeZqjAwtNOMoR17PMSOTZ+h070g== +xterm-addon-fit@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.3.0.tgz#341710741027de9d648a9f84415a01ddfdbbe715" + integrity sha512-kvkiqHVrnMXgyCH9Xn0BOBJ7XaWC/4BgpSWQy3SueqximgW630t/QOankgqkvk11iTOCwWdAY9DTyQBXUMN3lw== + +xterm-addon-search@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.5.0.tgz#cd3a2f8056084c28e236d4e732da37682010bcc2" + integrity sha512-zLVqVTrg5w2nk9fRj3UuVKCPo/dmFe/cLf3EM9Is5Dm6cgOoXmeo9eq2KgD8A0gquAflTFTf0ya2NaFmShHwyg== + +xterm@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589" + integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig== y18n@^3.2.1: version "3.2.1" @@ -14205,11 +14200,11 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yaml@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.7.2.tgz#f26aabf738590ab61efaca502358e48dc9f348b2" - integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw== + version "1.8.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.8.0.tgz#169fbcfa2081302dc9441d02b0b6fe667e4f74c9" + integrity sha512-6qI/tTx7OVtA4qNqD0OyutbM6Z9EKu4rxWm/2Y3FDEBQ4/2X2XAnyuRXMzAE2+1BPyqzksJZtrIwblOHg0IEzA== dependencies: - "@babel/runtime" "^7.6.3" + "@babel/runtime" "^7.8.7" yargs-parser@13.1.1, yargs-parser@^13.1.1: version "13.1.1" @@ -14329,9 +14324,9 @@ year@^0.2.1: integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: - version "2.8.0" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.8.0.tgz#003f7d3f506e868b86dbc1c1265a963a236807fa" - integrity sha512-BbJeEna23Qx90fBiJt1awcZ9okfPY/rP3xZYsk1rD3x8LuQgpo4BfegPvQT1sqqh2+gYVZmYZMv5pS8+Muyr9Q== + version "2.8.1" + resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.8.1.tgz#76c52fcccf26bcbd7ded35d9e22a9f3f1394d241" + integrity sha512-MV6yeJfnSsZBv/VuWvw82bN6hF6KIXRUwhEPaO+RHJAWeNCQAF+iYfBNsJOo4tx5Puch300h+DF9QZceKkbzQg== dependencies: chalk "^2.4.1" cross-spawn "^6.0.5" @@ -14380,11 +14375,6 @@ yeoman-generator@^2.0.3: through2 "^2.0.0" yeoman-environment "^2.0.5" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - zip-dir@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/zip-dir/-/zip-dir-1.0.2.tgz#253f907aead62a21acd8721d8b88032b2411c051"