mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-04-19 12:57:17 +00:00
Moving repo to bmci-labs
This commit is contained in:
commit
201351fea8
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules/
|
||||
# .node_modules is a hack for the electron builder.
|
||||
.node_modules/
|
||||
lib/
|
||||
build/
|
||||
!electron/build/
|
||||
src-gen/
|
||||
arduino-ide-*/webpack.config.js
|
||||
.DS_Store
|
20
.gitpod.yml
Normal file
20
.gitpod.yml
Normal file
@ -0,0 +1,20 @@
|
||||
image:
|
||||
file: Dockerfile
|
||||
|
||||
ports:
|
||||
- port: 3000
|
||||
onOpen: open-browser
|
||||
|
||||
tasks:
|
||||
- init: >
|
||||
yarn &&
|
||||
yarn --cwd ./arduino-ide-browser start
|
||||
|
||||
github:
|
||||
prebuilds:
|
||||
master: true
|
||||
branches: true
|
||||
pullRequests: true
|
||||
pullRequestsFromForks: true
|
||||
addComment: false
|
||||
addBadge: false
|
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Backend",
|
||||
"program": "${workspaceRoot}/arduino-ide-browser/src-gen/backend/main.js",
|
||||
"args": [
|
||||
"--hostname=0.0.0.0",
|
||||
"--port=3000",
|
||||
"--no-cluster",
|
||||
"--no-app-auto-install"
|
||||
],
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/arduino-ide-browser/src-gen/backend/*.js",
|
||||
"${workspaceRoot}/arduino-ide-browser/lib/**/*.js",
|
||||
"${workspaceRoot}/arduino-ide-extension/*/lib/**/*.js"
|
||||
],
|
||||
"smartStep": true,
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"outputCapture": "std"
|
||||
}
|
||||
]
|
||||
}
|
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER root
|
||||
RUN apt-get update -q --fix-missing && \
|
||||
apt-get install -y -q software-properties-common && \
|
||||
apt-get install -y -q --no-install-recommends \
|
||||
build-essential \
|
||||
libssl-dev \
|
||||
golang-go \
|
||||
libxkbfile-dev
|
||||
|
||||
RUN set -ex && \
|
||||
tmpdir=$(mktemp -d) && \
|
||||
curl -L -o $tmpdir/protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protoc-3.6.1-linux-x86_64.zip && \
|
||||
mkdir -p /usr/lib/protoc && cd /usr/lib/protoc && unzip $tmpdir/protoc.zip && \
|
||||
chmod -R 755 /usr/lib/protoc/include/google && \
|
||||
ln -s /usr/lib/protoc/bin/* /usr/bin && \
|
||||
rm $tmpdir/protoc.zip
|
19
README.md
Normal file
19
README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Arduino IDE PoC
|
||||
|
||||
> **Beware:** This is very much work-in-progress. Things can and probably will be broken, even on master.
|
||||
|
||||
This repo contains a proof-of-concept for an Arduino IDE based on Theia.
|
||||
It's built on top of a [version of the arduino-cli](https://github.com/cmaglie/arduino-cli/tree/daemon) that sports a gRPC interface.
|
||||
|
||||
## How to try (online)
|
||||
The easiest way to try the browser version is using Gitpod: https://gitpod.io/#github.com/typefox/arduino-poc
|
||||
|
||||
## How to try (offline)
|
||||
requires [protoc](https://github.com/protocolbuffers/protobuf/releases/tag/v3.7.1) to be in the `PATH` and some other [prerequisites](https://github.com/theia-ide/theia/blob/master/doc/Developing.md#prerequisites).
|
||||
|
||||
```
|
||||
git clone https://github.com/typefox/arduino-poc
|
||||
cd arduino-poc
|
||||
yarn
|
||||
yarn --cwd arduino-ide-electron start
|
||||
```
|
30
arduino-ide-browser/package.json
Normal file
30
arduino-ide-browser/package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "arduino-ide-browser",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@theia/core": "next",
|
||||
"@theia/editor": "next",
|
||||
"@theia/file-search": "next",
|
||||
"@theia/filesystem": "next",
|
||||
"@theia/languages": "next",
|
||||
"@theia/messages": "next",
|
||||
"@theia/monaco": "next",
|
||||
"@theia/navigator": "next",
|
||||
"@theia/preferences": "next",
|
||||
"@theia/process": "next",
|
||||
"@theia/terminal": "next",
|
||||
"@theia/workspace": "next",
|
||||
"@theia/textmate-grammars": "next",
|
||||
"arduino-ide-extension": "0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "next"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "theia build --mode development",
|
||||
"start": "theia start --root-dir=../workspace",
|
||||
"watch": "theia build --watch --mode development"
|
||||
}
|
||||
}
|
39
arduino-ide-electron/package.json
Normal file
39
arduino-ide-electron/package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "arduino-ide-electron",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@theia/core": "next",
|
||||
"@theia/editor": "next",
|
||||
"@theia/electron": "next",
|
||||
"@theia/file-search": "next",
|
||||
"@theia/filesystem": "next",
|
||||
"@theia/languages": "next",
|
||||
"@theia/messages": "next",
|
||||
"@theia/monaco": "next",
|
||||
"@theia/navigator": "next",
|
||||
"@theia/preferences": "next",
|
||||
"@theia/process": "next",
|
||||
"@theia/terminal": "next",
|
||||
"@theia/workspace": "next",
|
||||
"@theia/textmate-grammars": "next",
|
||||
"arduino-ide-extension": "0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "next"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "theia build --mode development",
|
||||
"start": "theia start --root-dir=../workspace",
|
||||
"watch": "theia build --watch --mode development"
|
||||
},
|
||||
"theia": {
|
||||
"target": "electron",
|
||||
"backend": {
|
||||
"config": {
|
||||
"startupTimeout": -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
arduino-ide-extension/.gitignore
vendored
Normal file
1
arduino-ide-extension/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
src/node/cli-protocol
|
1955
arduino-ide-extension/data/ino.tmLanguage.json
Normal file
1955
arduino-ide-extension/data/ino.tmLanguage.json
Normal file
File diff suppressed because it is too large
Load Diff
42
arduino-ide-extension/package.json
Normal file
42
arduino-ide-extension/package.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "arduino-ide-extension",
|
||||
"version": "0.0.1",
|
||||
"description": "An extension for Theia building the Arduino IDE",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@theia/core": "next",
|
||||
"@theia/editor": "next",
|
||||
"@theia/filesystem": "next",
|
||||
"@theia/languages": "next",
|
||||
"@theia/monaco": "next",
|
||||
"@theia/workspace": "next"
|
||||
},
|
||||
"scripts": {
|
||||
"generate-protoc": "./scripts/generate-protoc.sh",
|
||||
"prepare": "yarn run clean && yarn generate-protoc && yarn run build",
|
||||
"clean": "rimraf lib",
|
||||
"lint": "tslint -c ./tslint.json --project ./tsconfig.json",
|
||||
"build": "tsc && cp -rf src/node/cli-protocol lib/node && yarn lint",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/google-protobuf": "^3.2.7",
|
||||
"grpc-tools": "^1.7.3",
|
||||
"grpc_tools_node_protoc_ts": "^2.5.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"tslint": "^5.5.0",
|
||||
"typescript": "2.9.1"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"src",
|
||||
"build",
|
||||
"data"
|
||||
],
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"backend": "lib/node/arduino-backend-module",
|
||||
"frontend": "lib/browser/arduino-frontend-module"
|
||||
}
|
||||
]
|
||||
}
|
45
arduino-ide-extension/scripts/generate-protoc.sh
Executable file
45
arduino-ide-extension/scripts/generate-protoc.sh
Executable file
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT=`realpath -s $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
WORKDIR=/tmp/arduino-cli-protoc
|
||||
echo "Working in $WORKDIR"
|
||||
|
||||
# this could be a Git submodule, but that feels to clunky for just building the protobuf stuff
|
||||
mkdir -p $WORKDIR
|
||||
pushd $WORKDIR
|
||||
if [ ! -d arduino-cli ]; then
|
||||
git clone https://github.com/cmaglie/arduino-cli
|
||||
cd arduino-cli
|
||||
git checkout daemon
|
||||
cd -
|
||||
|
||||
mkdir -p go/src/github.com/arduino
|
||||
ln -s $PWD/arduino-cli go/src/github.com/arduino
|
||||
export GOPATH=$PWD/go
|
||||
cd go/src/github.com/arduino/arduino-cli
|
||||
GOOS=linux go build -o arduino-cli.linux
|
||||
# GOOS=darwin go build -o arduino-cli.darwin
|
||||
fi
|
||||
popd
|
||||
|
||||
# make sure the output path exists
|
||||
mkdir -p src/node/cli-protocol
|
||||
|
||||
export PATH=$PATH:$PWD/node_modules/.bin
|
||||
# generate js codes via grpc-tools
|
||||
grpc_tools_node_protoc \
|
||||
--js_out=import_style=commonjs,binary:./src/node/cli-protocol \
|
||||
--grpc_out=./src/node/cli-protocol \
|
||||
--plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` \
|
||||
-I /usr/lib/protoc/include \
|
||||
-I $WORKDIR/arduino-cli/rpc \
|
||||
$WORKDIR/arduino-cli/rpc/*.proto
|
||||
|
||||
# generate d.ts codes
|
||||
protoc \
|
||||
--plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
|
||||
--ts_out=./src/node/cli-protocol \
|
||||
-I /usr/lib/protoc/include \
|
||||
-I $WORKDIR/arduino-cli/rpc \
|
||||
$WORKDIR/arduino-cli/rpc/*.proto
|
13
arduino-ide-extension/src/browser/arduino-commands.ts
Normal file
13
arduino-ide-extension/src/browser/arduino-commands.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Command } from '@theia/core/lib/common/command';
|
||||
|
||||
export namespace ArduinoCommands {
|
||||
|
||||
export const VERIFY: Command = {
|
||||
id: 'arduino-verify'
|
||||
}
|
||||
|
||||
export const UPLOAD: Command = {
|
||||
id: 'arduino-upload'
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
import * as React from 'react';
|
||||
import { injectable, inject, postConstruct } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { EditorWidget } from '@theia/editor/lib/browser/editor-widget';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { CommandContribution, CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { DefaultFrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { BoardsService } from '../common/protocol/boards-service';
|
||||
import { ArduinoCommands } from './arduino-commands';
|
||||
import { ConnectedBoards } from './components/connected-boards';
|
||||
import { CoreService } from '../common/protocol/core-service';
|
||||
import { WorkspaceServiceExt } from './workspace-service-ext';
|
||||
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendContribution extends DefaultFrontendApplicationContribution implements TabBarToolbarContribution, CommandContribution {
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardService: BoardsService;
|
||||
|
||||
@inject(CoreService)
|
||||
protected readonly coreService: CoreService;
|
||||
|
||||
@inject(WorkspaceServiceExt)
|
||||
protected readonly workspaceServiceExt: WorkspaceServiceExt;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
// This is a hack. Otherwise, the backend services won't bind.
|
||||
await this.workspaceServiceExt.roots();
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
registry.registerItem({
|
||||
id: ArduinoCommands.VERIFY.id,
|
||||
command: ArduinoCommands.VERIFY.id,
|
||||
tooltip: 'Verify',
|
||||
group: 'arduino',
|
||||
text: '$(check)'
|
||||
});
|
||||
registry.registerItem({
|
||||
id: ArduinoCommands.UPLOAD.id,
|
||||
command: ArduinoCommands.UPLOAD.id,
|
||||
tooltip: 'Upload',
|
||||
group: 'arduino',
|
||||
text: '$(arrow-right)'
|
||||
});
|
||||
registry.registerItem({
|
||||
id: ConnectedBoards.TOOLBAR_ID,
|
||||
render: () => <ConnectedBoards boardsService={this.boardService}/>,
|
||||
isVisible: widget => this.isArduinoEditor(widget)
|
||||
})
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(ArduinoCommands.VERIFY, {
|
||||
isVisible: widget => this.isArduinoEditor(widget),
|
||||
isEnabled: widget => this.isArduinoEditor(widget),
|
||||
execute: async widget => {
|
||||
const uri = this.toUri(widget);
|
||||
if (uri) {
|
||||
const result = await this.coreService.compile({ uri: uri.toString() });
|
||||
console.log('compile result', result);
|
||||
}
|
||||
}
|
||||
});
|
||||
registry.registerCommand(ArduinoCommands.UPLOAD, {
|
||||
isVisible: widget => this.isArduinoEditor(widget),
|
||||
isEnabled: widget => this.isArduinoEditor(widget),
|
||||
execute: widget => {
|
||||
const uri = this.toUri(widget);
|
||||
if (uri) {
|
||||
this.messageService.info(`Uploading ${uri.toString()}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private isArduinoEditor(maybeEditorWidget: any): boolean {
|
||||
if (maybeEditorWidget instanceof EditorWidget) {
|
||||
return maybeEditorWidget.editor.uri.toString().endsWith('.ino');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private toUri(arg: any): URI | undefined {
|
||||
if (arg instanceof URI) {
|
||||
return arg;
|
||||
}
|
||||
if (typeof arg === 'string') {
|
||||
return new URI(arg);
|
||||
}
|
||||
if (arg instanceof EditorWidget) {
|
||||
return arg.editor.uri;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
70
arduino-ide-extension/src/browser/arduino-frontend-module.ts
Normal file
70
arduino-ide-extension/src/browser/arduino-frontend-module.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { ContainerModule, interfaces } from 'inversify';
|
||||
import { WidgetFactory } from '@theia/core/lib/browser/widget-manager';
|
||||
import { CommandContribution } from '@theia/core/lib/common/command';
|
||||
import { bindViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
|
||||
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/ws-connection-provider';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'
|
||||
import { LanguageGrammarDefinitionContribution } from '@theia/monaco/lib/browser/textmate';
|
||||
import { LibraryListWidget } from './library/library-list-widget';
|
||||
import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
|
||||
import { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { LibraryListWidgetFrontendContribution } from './library/list-widget-frontend-contribution';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { BoardsListWidget } from './boards/boards-list-widget';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
||||
import { WorkspaceServiceExt, WorkspaceServiceExtPath } from './workspace-service-ext';
|
||||
import { WorkspaceServiceExtImpl } from './workspace-service-ext-impl';
|
||||
|
||||
import '../../src/browser/style/index.css';
|
||||
|
||||
export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => {
|
||||
// Commands and toolbar items
|
||||
bind(ArduinoFrontendContribution).toSelf().inSingletonScope();
|
||||
bind(CommandContribution).toService(ArduinoFrontendContribution);
|
||||
bind(TabBarToolbarContribution).toService(ArduinoFrontendContribution);
|
||||
|
||||
// `ino` TextMate grammar
|
||||
bind(LanguageGrammarDefinitionContribution).to(ArduinoLanguageGrammarContribution).inSingletonScope();
|
||||
|
||||
// Library service
|
||||
bind(LibraryService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServicePath)).inSingletonScope();
|
||||
|
||||
// Library list widget
|
||||
bind(LibraryListWidget).toSelf();
|
||||
bindViewContribution(bind, LibraryListWidgetFrontendContribution);
|
||||
bind(WidgetFactory).toDynamicValue(context => ({
|
||||
id: LibraryListWidget.WIDGET_ID,
|
||||
createWidget: () => context.container.get(LibraryListWidget)
|
||||
}));
|
||||
bind(FrontendApplicationContribution).toService(LibraryListWidgetFrontendContribution);
|
||||
|
||||
// Boards service
|
||||
bind(BoardsService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath)).inSingletonScope();
|
||||
|
||||
// Boards list widget
|
||||
bind(BoardsListWidget).toSelf();
|
||||
bindViewContribution(bind, BoardsListWidgetFrontendContribution);
|
||||
bind(WidgetFactory).toDynamicValue(context => ({
|
||||
id: BoardsListWidget.WIDGET_ID,
|
||||
createWidget: () => context.container.get(BoardsListWidget)
|
||||
}));
|
||||
bind(FrontendApplicationContribution).toService(BoardsListWidgetFrontendContribution);
|
||||
|
||||
// Core service
|
||||
bind(CoreService)
|
||||
.toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath))
|
||||
.inSingletonScope();
|
||||
|
||||
// The workspace service extension
|
||||
bind(WorkspaceServiceExt).to(WorkspaceServiceExtImpl).inSingletonScope().onActivation(({ container }, workspaceServiceExt) => {
|
||||
WebSocketConnectionProvider.createProxy(container, WorkspaceServiceExtPath, workspaceServiceExt);
|
||||
// Eagerly active the core, library, and boards services.
|
||||
container.get(CoreService);
|
||||
container.get(LibraryService);
|
||||
container.get(BoardsService);
|
||||
return workspaceServiceExt;
|
||||
});
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
import { ListWidget } from './list-widget';
|
||||
|
||||
export class BoardsListWidget extends ListWidget {
|
||||
|
||||
static WIDGET_ID = 'boards-list-widget';
|
||||
static WIDGET_LABEL = 'Boards Manager';
|
||||
|
||||
protected widgetProps(): ListWidget.Props {
|
||||
return {
|
||||
id: BoardsListWidget.WIDGET_ID,
|
||||
title: BoardsListWidget.WIDGET_LABEL,
|
||||
iconClass: 'fa fa-microchip'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
|
||||
import { ListWidget } from './list-widget';
|
||||
import { BoardsListWidget } from './boards-list-widget';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidgetFrontendContribution extends AbstractViewContribution<ListWidget> implements FrontendApplicationContribution {
|
||||
|
||||
async initializeLayout(): Promise<void> {
|
||||
await this.openView();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendContribution {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
widgetId: BoardsListWidget.WIDGET_ID,
|
||||
widgetName: BoardsListWidget.WIDGET_LABEL,
|
||||
defaultWidgetOptions: {
|
||||
area: 'left',
|
||||
rank: 600
|
||||
},
|
||||
toggleCommandId: `${BoardsListWidget.WIDGET_ID}:toggle`,
|
||||
toggleKeybinding: 'ctrlcmd+shift+b'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
72
arduino-ide-extension/src/browser/boards/list-widget.tsx
Normal file
72
arduino-ide-extension/src/browser/boards/list-widget.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import * as React from 'react';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { Message } from '@phosphor/messaging';
|
||||
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { FilterableListContainer } from '../components/component-list/filterable-list-container';
|
||||
import { BoardsService } from '../../common/protocol/boards-service';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidget extends ReactWidget {
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(WindowService)
|
||||
protected readonly windowService: WindowService;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const { id, title, iconClass } = this.widgetProps();
|
||||
this.id = id;
|
||||
this.title.label = title;
|
||||
this.title.caption = title;
|
||||
this.title.iconClass = iconClass;
|
||||
this.title.closable = true;
|
||||
this.addClass(ListWidget.Styles.LIST_WIDGET_CLASS);
|
||||
this.node.tabIndex = 0; // To be able to set the focus on the widget.
|
||||
}
|
||||
|
||||
protected abstract widgetProps(): ListWidget.Props;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected onActivateRequest(msg: Message): void {
|
||||
super.onActivateRequest(msg);
|
||||
this.node.focus();
|
||||
this.render();
|
||||
}
|
||||
|
||||
protected onUpdateRequest(msg: Message): void {
|
||||
super.onUpdateRequest(msg);
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <FilterableListContainer
|
||||
service={this.boardsService}
|
||||
windowService={this.windowService}
|
||||
/>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace ListWidget {
|
||||
|
||||
/**
|
||||
* Props for customizing the abstract list widget.
|
||||
*/
|
||||
export interface Props {
|
||||
readonly id: string;
|
||||
readonly title: string;
|
||||
readonly iconClass: string;
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const LIST_WIDGET_CLASS = 'arduino-list-widget'
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
import * as React from 'react';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
|
||||
export class ComponentListItem extends React.Component<ComponentListItem.Props> {
|
||||
|
||||
private onClick = (event: React.SyntheticEvent<HTMLAnchorElement, Event>) => {
|
||||
const { target } = event.nativeEvent;
|
||||
if (target instanceof HTMLAnchorElement) {
|
||||
this.props.windowService.openNewWindow(target.href);
|
||||
event.nativeEvent.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const { item } = this.props;
|
||||
|
||||
const style = ComponentListItem.Styles;
|
||||
const name = <span className={style.NAME_CLASS}>{item.name}</span>;
|
||||
const author = <span className={style.AUTHOR_CLASS}>{item.author}</span>;
|
||||
const installedVersion = !!item.installedVersion && <React.Fragment>
|
||||
<span className={style.VERSION_CLASS}>Version {item.installedVersion}</span>
|
||||
<span className={style.INSTALLED_CLASS}>INSTALLED</span>
|
||||
</React.Fragment>;
|
||||
|
||||
const summary = <div className={style.SUMMARY_CLASS}>{item.summary}</div>;
|
||||
const description = !!item.description && <div className={style.DESCRIPTION_CLASS}>{item.description}</div>;
|
||||
|
||||
const moreInfo = !!item.moreInfoLink && <a href={item.moreInfoLink} onClick={this.onClick}>More info</a>;
|
||||
const install = item.installable && !item.installedVersion && <button className={style.INSTALL_BTN_CLASS}>INSTALL</button>;
|
||||
|
||||
return <div className={[style.LIST_ITEM_CLASS, style.NO_SELECT_CLASS].join(' ')}>
|
||||
<div className={style.HEADER_CLASS}>
|
||||
<span>{name} by {author}</span>
|
||||
{installedVersion}
|
||||
</div>
|
||||
<div className={style.CONTENT_CLASS}>
|
||||
{summary}
|
||||
{description}
|
||||
</div>
|
||||
<div className={style.FOOTER_CLASS}>
|
||||
{moreInfo}
|
||||
{install}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace ComponentListItem {
|
||||
|
||||
export interface Props {
|
||||
readonly item: ArduinoComponent;
|
||||
readonly windowService: WindowService;
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const LIST_ITEM_CLASS = 'component-list-item';
|
||||
export const HEADER_CLASS = 'header';
|
||||
export const CONTENT_CLASS = 'content';
|
||||
export const FOOTER_CLASS = 'footer';
|
||||
export const INSTALLED_CLASS = 'installed';
|
||||
export const NO_SELECT_CLASS = 'noselect';
|
||||
|
||||
export const NAME_CLASS = 'name';
|
||||
export const AUTHOR_CLASS = 'author';
|
||||
export const VERSION_CLASS = 'version';
|
||||
export const SUMMARY_CLASS = 'summary';
|
||||
export const DESCRIPTION_CLASS = 'description';
|
||||
export const INSTALL_BTN_CLASS = 'install';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { ComponentListItem } from './component-list-item';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
|
||||
export class ComponentList extends React.Component<ComponentList.Props> {
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <div>
|
||||
{this.props.items.map(item => <ComponentListItem key={item.name} item={item} windowService={this.props.windowService}/>)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace ComponentList {
|
||||
|
||||
export interface Props {
|
||||
readonly items: ArduinoComponent[];
|
||||
readonly windowService: WindowService;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import * as React from 'react';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { ComponentList } from './component-list';
|
||||
import { SearchBar } from './search-bar';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
|
||||
export class FilterableListContainer extends React.Component<FilterableListContainer.Props, FilterableListContainer.State> {
|
||||
|
||||
constructor(props: Readonly<FilterableListContainer.Props>) {
|
||||
super(props);
|
||||
this.state = {
|
||||
filterText: '',
|
||||
items: []
|
||||
};
|
||||
this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount(): void {
|
||||
this.handleFilterTextChange('');
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <div className={FilterableListContainer.Styles.FILTERABLE_LIST_CONTAINER_CLASS}>
|
||||
<SearchBar
|
||||
filterText={this.state.filterText}
|
||||
onFilterTextChanged={this.handleFilterTextChange}
|
||||
/>
|
||||
<ComponentList
|
||||
items={this.state.items}
|
||||
windowService={this.props.windowService}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
private handleFilterTextChange(filterText: string): void {
|
||||
this.props.service.search({ query: filterText }).then(result => {
|
||||
const { items } = result;
|
||||
this.setState({
|
||||
filterText,
|
||||
items
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace FilterableListContainer {
|
||||
|
||||
export interface Props {
|
||||
readonly service: ComponentSource;
|
||||
readonly windowService: WindowService;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
filterText: string;
|
||||
items: ArduinoComponent[];
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const FILTERABLE_LIST_CONTAINER_CLASS = 'filterable-list-container';
|
||||
}
|
||||
|
||||
export interface ComponentSource {
|
||||
search(req: { query: string }): Promise<{ items: ArduinoComponent[] }>
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export class SearchBar extends React.Component<SearchBar.Props> {
|
||||
|
||||
constructor(props: Readonly<SearchBar.Props>) {
|
||||
super(props);
|
||||
this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <form className={SearchBar.Styles.SEARCH_BAR_CLASS}>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='Search'
|
||||
size={1}
|
||||
value={this.props.filterText}
|
||||
onChange={this.handleFilterTextChange}
|
||||
/>
|
||||
</form>;
|
||||
}
|
||||
|
||||
private handleFilterTextChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
this.props.onFilterTextChanged(event.target.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace SearchBar {
|
||||
|
||||
export interface Props {
|
||||
filterText: string;
|
||||
onFilterTextChanged(filterText: string): void;
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const SEARCH_BAR_CLASS = 'search-bar';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
import * as React from 'react';
|
||||
// TODO: make this `async`.
|
||||
// import { Async } from 'react-select/lib/Async';
|
||||
import { BoardsService, Board } from '../../common/protocol/boards-service';
|
||||
|
||||
export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> {
|
||||
|
||||
static TOOLBAR_ID: 'connected-boards-toolbar';
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}>
|
||||
{this.select(this.state ? this.state.boards : undefined, this.state ? this.state.current : undefined)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.props.boardsService.connectedBoards().then(result => {
|
||||
const { boards, current } = result;
|
||||
this.setState({
|
||||
boards,
|
||||
current
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
private select(boards: Board[] | undefined, current: Board | undefined): React.ReactNode {
|
||||
// Initial pessimistic.
|
||||
const options = [<option>Loading...</option>];
|
||||
if (boards) {
|
||||
options.length = 0;
|
||||
options.push(...boards.map(b => b.name).map(name => <option value={name} key={name}>{name}</option>));
|
||||
}
|
||||
const onChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const current = (boards || []).find(board => board.name === event.target.value);
|
||||
this.setState({ current });
|
||||
};
|
||||
return <select
|
||||
onChange={onChange}
|
||||
value={current ? current.name : 'Loading...'}
|
||||
name={current ? current.name : 'Loading...'}
|
||||
>
|
||||
{options}
|
||||
</select>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace ConnectedBoards {
|
||||
|
||||
export interface Props {
|
||||
readonly boardsService: BoardsService;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
boards?: Board[];
|
||||
current?: Board;
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const CONNECTED_BOARDS_CLASS = 'connected-boards';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { LanguageGrammarDefinitionContribution, TextmateRegistry } from '@theia/monaco/lib/browser/textmate';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoLanguageGrammarContribution implements LanguageGrammarDefinitionContribution {
|
||||
|
||||
static INO_LANGUAGE_ID = 'ino';
|
||||
|
||||
registerTextmateLanguage(registry: TextmateRegistry) {
|
||||
monaco.languages.register({
|
||||
id: ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID,
|
||||
extensions: ['.ino'],
|
||||
aliases: ['INO', 'Ino', 'ino'],
|
||||
});
|
||||
|
||||
monaco.languages.setLanguageConfiguration(ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID, this.configuration);
|
||||
|
||||
const inoGrammar = require('../../../data/ino.tmLanguage.json');
|
||||
registry.registerTextmateGrammarScope('source.ino', {
|
||||
async getGrammarDefinition() {
|
||||
return {
|
||||
format: 'json',
|
||||
content: inoGrammar
|
||||
};
|
||||
}
|
||||
});
|
||||
registry.mapLanguageIdToTextmateGrammar(ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID, 'source.ino');
|
||||
}
|
||||
|
||||
private readonly configuration: monaco.languages.LanguageConfiguration = {
|
||||
comments: {
|
||||
lineComment: '//',
|
||||
blockComment: ['/*', '*/'],
|
||||
},
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')']
|
||||
],
|
||||
autoClosingPairs: [
|
||||
{ open: '[', close: ']' },
|
||||
{ open: '{', close: '}' },
|
||||
{ open: '(', close: ')' },
|
||||
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
|
||||
{ open: '"', close: '"', notIn: ['string'] },
|
||||
{ open: '/*', close: ' */', notIn: ['string'] }
|
||||
],
|
||||
surroundingPairs: [
|
||||
{ open: '{', close: '}' },
|
||||
{ open: '[', close: ']' },
|
||||
{ open: '(', close: ')' },
|
||||
{ open: '"', close: '"' },
|
||||
{ open: '\'', close: '\'' },
|
||||
],
|
||||
folding: {
|
||||
markers: {
|
||||
start: new RegExp('^\\s*#pragma\\s+region\\b'),
|
||||
end: new RegExp('^\\s*#pragma\\s+endregion\\b')
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { ListWidget } from './list-widget';
|
||||
|
||||
export class LibraryListWidget extends ListWidget {
|
||||
|
||||
static WIDGET_ID = 'library-list-widget';
|
||||
static WIDGET_LABEL = 'Library Manager';
|
||||
|
||||
protected widgetProps(): ListWidget.Props {
|
||||
return {
|
||||
id: LibraryListWidget.WIDGET_ID,
|
||||
title: LibraryListWidget.WIDGET_LABEL,
|
||||
iconClass: 'fa fa-book' // TODO: find a better icon
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
|
||||
import { ListWidget } from './list-widget';
|
||||
import { LibraryListWidget } from './library-list-widget';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidgetFrontendContribution extends AbstractViewContribution<ListWidget> implements FrontendApplicationContribution {
|
||||
|
||||
async initializeLayout(): Promise<void> {
|
||||
await this.openView();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class LibraryListWidgetFrontendContribution extends ListWidgetFrontendContribution {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
widgetId: LibraryListWidget.WIDGET_ID,
|
||||
widgetName: LibraryListWidget.WIDGET_LABEL,
|
||||
defaultWidgetOptions: {
|
||||
area: 'left',
|
||||
rank: 600
|
||||
},
|
||||
toggleCommandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
toggleKeybinding: 'ctrlcmd+shift+l'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
72
arduino-ide-extension/src/browser/library/list-widget.tsx
Normal file
72
arduino-ide-extension/src/browser/library/list-widget.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import * as React from 'react';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { Message } from '@phosphor/messaging';
|
||||
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { FilterableListContainer } from '../components/component-list/filterable-list-container';
|
||||
import { LibraryService } from '../../common/protocol/library-service';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidget extends ReactWidget {
|
||||
|
||||
@inject(LibraryService)
|
||||
protected readonly libraryService: LibraryService;
|
||||
|
||||
@inject(WindowService)
|
||||
protected readonly windowService: WindowService;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const { id, title, iconClass } = this.widgetProps();
|
||||
this.id = id;
|
||||
this.title.label = title;
|
||||
this.title.caption = title;
|
||||
this.title.iconClass = iconClass;
|
||||
this.title.closable = true;
|
||||
this.addClass(ListWidget.Styles.LIST_WIDGET_CLASS);
|
||||
this.node.tabIndex = 0; // To be able to set the focus on the widget.
|
||||
}
|
||||
|
||||
protected abstract widgetProps(): ListWidget.Props;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected onActivateRequest(msg: Message): void {
|
||||
super.onActivateRequest(msg);
|
||||
this.node.focus();
|
||||
this.render();
|
||||
}
|
||||
|
||||
protected onUpdateRequest(msg: Message): void {
|
||||
super.onUpdateRequest(msg);
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <FilterableListContainer
|
||||
service={this.libraryService}
|
||||
windowService={this.windowService}
|
||||
/>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace ListWidget {
|
||||
|
||||
/**
|
||||
* Props for customizing the abstract list widget.
|
||||
*/
|
||||
export interface Props {
|
||||
readonly id: string;
|
||||
readonly title: string;
|
||||
readonly iconClass: string;
|
||||
}
|
||||
|
||||
export namespace Styles {
|
||||
export const LIST_WIDGET_CLASS = 'arduino-list-widget'
|
||||
}
|
||||
|
||||
}
|
1
arduino-ide-extension/src/browser/style/index.css
Normal file
1
arduino-ide-extension/src/browser/style/index.css
Normal file
@ -0,0 +1 @@
|
||||
@import './list-widget.css';
|
76
arduino-ide-extension/src/browser/style/list-widget.css
Normal file
76
arduino-ide-extension/src/browser/style/list-widget.css
Normal file
@ -0,0 +1,76 @@
|
||||
.arduino-list-widget {
|
||||
color: var(--theia-ui-font-color1);
|
||||
}
|
||||
|
||||
.arduino-list-widget .search-bar > input {
|
||||
margin: 0px 5px 0px 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.component-list-item {
|
||||
padding: 10px;
|
||||
font-size: var(--theia-ui-font-size1);
|
||||
}
|
||||
|
||||
.component-list-item:hover {
|
||||
background: var(--theia-accent-color4);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.component-list-item:hover .meta-info {
|
||||
color: var(--theia-ui-font-color1);
|
||||
}
|
||||
|
||||
.component-list-item .meta-info {
|
||||
color: var(--theia-ui-font-color3);
|
||||
}
|
||||
|
||||
.component-list-item .header {
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.component-list-item .header .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.component-list-item .header .author {
|
||||
font-weight: bold;
|
||||
color: var(--theia-ui-font-color2);
|
||||
}
|
||||
|
||||
.component-list-item .header .version {
|
||||
margin-left: auto;
|
||||
justify-self: end;
|
||||
color: var(--theia-ui-font-color2);
|
||||
}
|
||||
|
||||
.component-list-item .header .installed {
|
||||
margin-left: 4px;
|
||||
justify-self: end;
|
||||
background-color: var(--theia-accent-color2);
|
||||
padding: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.component-list-item .footer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.component-list-item .footer a {
|
||||
color: var(--theia-brand-color1);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.component-list-item .footer .install {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.component-list-item a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.component-list-item strong.installed {
|
||||
color: rgb(0, 151, 157)
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { WorkspaceServiceExt } from './workspace-service-ext';
|
||||
|
||||
/**
|
||||
* This is a workaround to be able to inject the workspace service to the backend with its service path.
|
||||
*/
|
||||
@injectable()
|
||||
export class WorkspaceServiceExtImpl implements WorkspaceServiceExt {
|
||||
|
||||
@inject(WorkspaceService)
|
||||
protected readonly delegate: WorkspaceService;
|
||||
|
||||
async roots(): Promise<string[]> {
|
||||
const stats = await this.delegate.roots;
|
||||
return stats.map(stat => stat.uri);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export const WorkspaceServiceExtPath = '/services/workspace-service-ext';
|
||||
export const WorkspaceServiceExt = Symbol('WorkspaceServiceExt');
|
||||
export interface WorkspaceServiceExt {
|
||||
roots(): Promise<string[]>;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
|
||||
export interface ArduinoComponent {
|
||||
readonly name: string;
|
||||
readonly author: string;
|
||||
readonly summary: string;
|
||||
readonly description: string;
|
||||
readonly moreInfoLink?: string;
|
||||
|
||||
readonly availableVersions: string[];
|
||||
readonly installable: boolean;
|
||||
|
||||
readonly installedVersion?: string;
|
||||
}
|
11
arduino-ide-extension/src/common/protocol/boards-service.ts
Normal file
11
arduino-ide-extension/src/common/protocol/boards-service.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ArduinoComponent } from "./arduino-component";
|
||||
|
||||
export const BoardsServicePath = '/services/boards-service';
|
||||
export const BoardsService = Symbol('BoardsService');
|
||||
export interface BoardsService {
|
||||
connectedBoards(): Promise<{ boards: Board[], current?: Board }>;
|
||||
search(options: { query?: string }): Promise<{ items: Board[] }>;
|
||||
}
|
||||
|
||||
export interface Board extends ArduinoComponent {
|
||||
}
|
14
arduino-ide-extension/src/common/protocol/core-service.ts
Normal file
14
arduino-ide-extension/src/common/protocol/core-service.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export const CoreServicePath = '/services/core-service';
|
||||
export const CoreService = Symbol('CoreService');
|
||||
export interface CoreService {
|
||||
compile(options: CoreService.Compile.Options): Promise<string>;
|
||||
upload(): Promise<void>;
|
||||
}
|
||||
|
||||
export namespace CoreService {
|
||||
export namespace Compile {
|
||||
export interface Options {
|
||||
readonly uri: string;
|
||||
}
|
||||
}
|
||||
}
|
16
arduino-ide-extension/src/common/protocol/library-service.ts
Normal file
16
arduino-ide-extension/src/common/protocol/library-service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ArduinoComponent } from "./arduino-component";
|
||||
|
||||
export const LibraryServicePath = '/services/library-service';
|
||||
export const LibraryService = Symbol('LibraryService');
|
||||
export interface LibraryService {
|
||||
search(options: { query?: string }): Promise<{ items: Library[] }>;
|
||||
}
|
||||
|
||||
export interface Library extends ArduinoComponent {
|
||||
readonly builtIn?: boolean;
|
||||
}
|
||||
|
||||
export namespace Library {
|
||||
// TODO: figure out whether we need a dedicated `version` type.
|
||||
export type Version = string;
|
||||
}
|
66
arduino-ide-extension/src/node/arduino-backend-module.ts
Normal file
66
arduino-ide-extension/src/node/arduino-backend-module.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { ContainerModule } from 'inversify';
|
||||
import { ArduinoDaemon } from './arduino-daemon';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { LibraryServiceImpl } from './library-service-impl';
|
||||
import { BoardsServiceImpl } from './boards-service-impl';
|
||||
import { CoreServiceImpl } from './core-service-impl';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
|
||||
import { WorkspaceServiceExtPath, WorkspaceServiceExt } from '../browser/workspace-service-ext';
|
||||
import { CoreClientProviderImpl } from './core-client-provider-impl';
|
||||
import { CoreClientProviderPath, CoreClientProvider } from './core-client-provider';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
||||
bind(BackendApplicationContribution).toService(ArduinoDaemon);
|
||||
|
||||
// Library service
|
||||
const libraryServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(LibraryServiceImpl).toSelf().inSingletonScope();
|
||||
bind(LibraryService).toService(LibraryServiceImpl);
|
||||
bindBackendService(LibraryServicePath, LibraryService);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(libraryServiceConnectionModule);
|
||||
|
||||
// Boards service
|
||||
const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(BoardsServiceImpl).toSelf().inSingletonScope();
|
||||
bind(BoardsService).toService(BoardsServiceImpl);
|
||||
bindBackendService(BoardsServicePath, BoardsService);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(boardsServiceConnectionModule);
|
||||
|
||||
// Arduino core client provider per Theia connection.
|
||||
const coreClientProviderConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(CoreClientProviderImpl).toSelf().inSingletonScope();
|
||||
bind(CoreClientProvider).toService(CoreClientProviderImpl);
|
||||
bindBackendService(CoreClientProviderPath, CoreClientProvider);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(coreClientProviderConnectionModule);
|
||||
|
||||
// Core service -> `verify` and `upload`. One per Theia connection.
|
||||
const connectionConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(CoreServiceImpl).toSelf().inSingletonScope();
|
||||
bind(CoreService).toService(CoreServiceImpl);
|
||||
bindBackendService(BoardsServicePath, BoardsService);
|
||||
bindBackendService(CoreClientProviderPath, CoreClientProvider);
|
||||
bindBackendService(CoreServicePath, CoreService);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(connectionConnectionModule);
|
||||
|
||||
// Bind the workspace service extension to the backend per Theia connection.
|
||||
// So that we can access the workspace roots of the frontend.
|
||||
const workspaceServiceExtConnectionModule = ConnectionContainerModule.create(({ bindFrontendService }) => {
|
||||
bindFrontendService(WorkspaceServiceExtPath, WorkspaceServiceExt);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(workspaceServiceExtConnectionModule);
|
||||
|
||||
// Logger for the Arduino daemon
|
||||
bind(ILogger).toDynamicValue(ctx => {
|
||||
const parentLogger = ctx.container.get<ILogger>(ILogger);
|
||||
return parentLogger.child('daemon');
|
||||
}).inSingletonScope().whenTargetNamed('daemon');
|
||||
});
|
46
arduino-ide-extension/src/node/arduino-daemon.ts
Normal file
46
arduino-ide-extension/src/node/arduino-daemon.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import * as os from 'os';
|
||||
import { exec } from 'child_process';
|
||||
import { join, resolve } from 'path';
|
||||
import { inject, injectable, named } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { DaemonLog } from './daemon-log';
|
||||
|
||||
const EXECUTABLE_PATH = resolve(join(__dirname, '..', '..', 'build', `arduino-cli.${os.platform()}`))
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDaemon implements BackendApplicationContribution {
|
||||
|
||||
@inject(ILogger)
|
||||
@named('daemon')
|
||||
protected readonly logger: ILogger
|
||||
|
||||
protected isReady = new Deferred<boolean>();
|
||||
|
||||
async onStart() {
|
||||
try {
|
||||
const daemon = exec(`${EXECUTABLE_PATH} --debug daemon`, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
console.log(err || new Error(stderr));
|
||||
return;
|
||||
}
|
||||
console.log(stdout);
|
||||
});
|
||||
if (daemon.stdout) {
|
||||
daemon.stdout.on('data', data => DaemonLog.log(this.logger, data.toString()));
|
||||
}
|
||||
if (daemon.stderr) {
|
||||
daemon.stderr.on('data', data => DaemonLog.log(this.logger, data.toString()));
|
||||
}
|
||||
if (daemon.stderr) {
|
||||
daemon.on('exit', (code, signal) => DaemonLog.log(this.logger, `Daemon exited with code: ${code}. Signal was: ${signal}.`));
|
||||
}
|
||||
await new Promise((resolve, reject) => setTimeout(resolve, 2000));
|
||||
this.isReady.resolve();
|
||||
} catch (error) {
|
||||
this.isReady.reject(error || new Error('failed to start arduino-cli'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
arduino-ide-extension/src/node/boards-service-impl.ts
Normal file
37
arduino-ide-extension/src/node/boards-service-impl.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { BoardsService, Board } from '../common/protocol/boards-service';
|
||||
import { PlatformSearchReq, PlatformSearchResp } from './cli-protocol/core_pb';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceImpl implements BoardsService {
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
async connectedBoards(): Promise<{ boards: Board[], current?: Board }> {
|
||||
return { boards: [] };
|
||||
}
|
||||
|
||||
async search(options: { query?: string }): Promise<{ items: Board[] }> {
|
||||
let items: Board[] = [];
|
||||
|
||||
const { client, instance } = await this.coreClientProvider.getClient();
|
||||
|
||||
const req = new PlatformSearchReq();
|
||||
req.setSearchArgs(options.query || "");
|
||||
req.setInstance(instance);
|
||||
const resp = await new Promise<PlatformSearchResp>((resolve, reject) => client.platformSearch(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)));
|
||||
items = resp.getSearchOutputList().map(o => <Board>{
|
||||
name: o.getName(),
|
||||
author: "Someone",
|
||||
availableVersions: [],
|
||||
description: "lorem ipsum sit dolor amet",
|
||||
installable: false,
|
||||
summary: "has none"
|
||||
});
|
||||
|
||||
return { items };
|
||||
}
|
||||
|
||||
}
|
91
arduino-ide-extension/src/node/core-client-provider-impl.ts
Normal file
91
arduino-ide-extension/src/node/core-client-provider-impl.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import * as grpc from 'grpc';
|
||||
import { ArduinoCoreClient } from './cli-protocol/commands_grpc_pb';
|
||||
import { InitResp, InitReq, Configuration, UpdateIndexReq, UpdateIndexResp } from './cli-protocol/commands_pb';
|
||||
import { WorkspaceServiceExt } from '../browser/workspace-service-ext';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { CoreClientProvider, Client } from './core-client-provider';
|
||||
|
||||
@injectable()
|
||||
export class CoreClientProviderImpl implements CoreClientProvider {
|
||||
|
||||
@inject(FileSystem)
|
||||
protected readonly fileSystem: FileSystem;
|
||||
|
||||
@inject(WorkspaceServiceExt)
|
||||
protected readonly workspaceServiceExt: WorkspaceServiceExt;
|
||||
|
||||
protected clients = new Map<string, Client>();
|
||||
|
||||
async getClient(workspaceRootOrResourceUri?: string): Promise<Client> {
|
||||
const roots = await this.workspaceServiceExt.roots();
|
||||
if (!workspaceRootOrResourceUri) {
|
||||
return this.getOrCreateClient(roots[0]);
|
||||
}
|
||||
const root = roots
|
||||
.sort((left, right) => right.length - left.length) // Longest "paths" first
|
||||
.map(uri => new URI(uri))
|
||||
.find(uri => uri.isEqualOrParent(new URI(workspaceRootOrResourceUri)));
|
||||
if (!root) {
|
||||
console.warn(`Could not retrieve the container workspace root for URI: ${workspaceRootOrResourceUri}.`);
|
||||
console.warn(`Falling back to ${roots[0]}`);
|
||||
return this.getOrCreateClient(roots[0]);
|
||||
}
|
||||
return this.getOrCreateClient(root.toString());
|
||||
}
|
||||
|
||||
protected async getOrCreateClient(rootUri: string): Promise<Client> {
|
||||
const existing = this.clients.get(rootUri);
|
||||
if (existing) {
|
||||
console.debug(`Reusing existing client for ${rootUri}.`);
|
||||
return existing;
|
||||
}
|
||||
|
||||
console.info(` >>> Creating and caching a new client for ${rootUri}...`);
|
||||
const client = new ArduinoCoreClient('localhost:50051', grpc.credentials.createInsecure());
|
||||
const config = new Configuration();
|
||||
const path = await this.fileSystem.getFsPath(rootUri);
|
||||
if (!path) {
|
||||
throw new Error(`Could not resolve file-system path of URI: ${rootUri}.`);
|
||||
}
|
||||
config.setSketchbookdir(path);
|
||||
config.setDatadir(path);
|
||||
config.setDownloadsdir(path);
|
||||
|
||||
const initReq = new InitReq();
|
||||
initReq.setConfiguration(config);
|
||||
const initResp = await new Promise<InitResp>((resolve, reject) => client.init(initReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)));
|
||||
const instance = initResp.getInstance();
|
||||
if (!instance) {
|
||||
throw new Error(`Could not retrieve instance from the initialize response.`);
|
||||
}
|
||||
const updateReq = new UpdateIndexReq();
|
||||
updateReq.setInstance(instance);
|
||||
const updateResp = client.updateIndex(updateReq);
|
||||
updateResp.on('data', (o: UpdateIndexResp) => {
|
||||
const progress = o.getDownloadProgress();
|
||||
if (progress) {
|
||||
if (progress.getCompleted()) {
|
||||
console.log(`Download${progress.getFile() ? ` of ${progress.getFile()}` : ''} completed.`);
|
||||
} else {
|
||||
console.log(`Downloading${progress.getFile() ? ` ${progress.getFile()}:` : ''} ${progress.getDownloaded()}.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
// TODO: revisit this!!!
|
||||
// `updateResp.on('data'` is called only when running, for instance, `compile`. It does not run eagerly.
|
||||
// await new Promise<void>((resolve, reject) => {
|
||||
// updateResp.on('close', resolve);
|
||||
// updateResp.on('error', reject);
|
||||
// });
|
||||
|
||||
const result = {
|
||||
client,
|
||||
instance
|
||||
}
|
||||
this.clients.set(rootUri, result);
|
||||
console.info(` <<< New client has been successfully created and cached for ${rootUri}.`);
|
||||
return result;
|
||||
}
|
||||
}
|
13
arduino-ide-extension/src/node/core-client-provider.ts
Normal file
13
arduino-ide-extension/src/node/core-client-provider.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Instance } from './cli-protocol/common_pb';
|
||||
import { ArduinoCoreClient } from './cli-protocol/commands_grpc_pb';
|
||||
|
||||
export const CoreClientProviderPath = '/services/core-client-provider';
|
||||
export const CoreClientProvider = Symbol('CoreClientProvider');
|
||||
export interface CoreClientProvider {
|
||||
getClient(workspaceRootOrResourceUri?: string): Promise<Client>;
|
||||
}
|
||||
|
||||
export interface Client {
|
||||
readonly client: ArduinoCoreClient;
|
||||
readonly instance: Instance;
|
||||
}
|
84
arduino-ide-extension/src/node/core-service-impl.ts
Normal file
84
arduino-ide-extension/src/node/core-service-impl.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
|
||||
import { CoreService } from '../common/protocol/core-service';
|
||||
import { CompileReq } from './cli-protocol/compile_pb';
|
||||
import { BoardsService } from '../common/protocol/boards-service';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { PlatformInstallReq } from './cli-protocol/core_pb';
|
||||
import { LibraryInstallReq } from './cli-protocol/lib_pb';
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceImpl implements CoreService {
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(FileSystem)
|
||||
protected readonly fileSystem: FileSystem;
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
async compile(options: CoreService.Compile.Options): Promise<string> {
|
||||
console.log('compile', options);
|
||||
const { uri } = options;
|
||||
const sketchpath = await this.fileSystem.getFsPath(options.uri);
|
||||
if (!sketchpath) {
|
||||
throw new Error(`Cannot resolve FS path for URI: ${uri}.`);
|
||||
}
|
||||
const { client, instance } = await this.coreClientProvider.getClient(uri);
|
||||
// const boards = await this.boardsService.connectedBoards();
|
||||
// if (!boards.current) {
|
||||
// throw new Error(`No selected board. The connected boards were: ${boards.boards}.`);
|
||||
// }
|
||||
// https://github.com/cmaglie/arduino-cli/blob/bd5e78701e7546787649d3cca6b21c5d22d0e438/cli/compile/compile.go#L78-L88
|
||||
|
||||
const installPlatformReq = new PlatformInstallReq();
|
||||
installPlatformReq.setArchitecture('samd');
|
||||
installPlatformReq.setVersion('1.6.0');
|
||||
installPlatformReq.setInstance(instance);
|
||||
const resp = client.platformInstall(installPlatformReq);
|
||||
console.log(resp);
|
||||
|
||||
|
||||
|
||||
const installLibReq = new LibraryInstallReq();
|
||||
installLibReq.setInstance(instance);
|
||||
installLibReq.setName('arduino:samd');
|
||||
const installResp = client.libraryInstall(installLibReq);
|
||||
const xxx = await new Promise<string>((resolve, reject) => {
|
||||
const chunks: Buffer[] = [];
|
||||
installResp.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
installResp.on('error', error => reject(error));
|
||||
installResp.on('end', () => resolve(Buffer.concat(chunks).toString('utf8').trim()))
|
||||
});
|
||||
console.log('xxx', xxx);
|
||||
|
||||
const compilerReq = new CompileReq();
|
||||
compilerReq.setInstance(instance);
|
||||
compilerReq.setSketchpath(sketchpath);
|
||||
compilerReq.setFqbn('arduino:samd'/*boards.current.name*/);
|
||||
// request.setShowproperties(false);
|
||||
// request.setPreprocess(false);
|
||||
// request.setBuildcachepath('');
|
||||
// request.setBuildpath('');
|
||||
// request.setBuildpropertiesList([]);
|
||||
// request.setWarnings('none');
|
||||
// request.setVerbose(true);
|
||||
// request.setQuiet(false);
|
||||
// request.setVidpid('');
|
||||
// request.setExportfile('');
|
||||
const result = client.compile(compilerReq);
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const chunks: Buffer[] = [];
|
||||
result.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
result.on('error', error => reject(error));
|
||||
result.on('end', () => resolve(Buffer.concat(chunks).toString('utf8').trim()))
|
||||
});
|
||||
}
|
||||
|
||||
upload(): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
}
|
67
arduino-ide-extension/src/node/daemon-log.ts
Normal file
67
arduino-ide-extension/src/node/daemon-log.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { ILogger, LogLevel } from '@theia/core/lib/common/logger';
|
||||
|
||||
export interface DaemonLog {
|
||||
readonly time: string;
|
||||
readonly level: DaemonLog.Level;
|
||||
readonly msg: string;
|
||||
}
|
||||
|
||||
export namespace DaemonLog {
|
||||
|
||||
export type Level = 'info' | 'debug' | 'warning' | 'error';
|
||||
|
||||
export function is(arg: any | undefined): arg is DaemonLog {
|
||||
return !!arg
|
||||
&& typeof arg.time === 'string'
|
||||
&& typeof arg.level === 'string'
|
||||
&& typeof arg.msg === 'string'
|
||||
}
|
||||
|
||||
export function toLogLevel(log: DaemonLog): LogLevel {
|
||||
const { level } = log;
|
||||
switch (level) {
|
||||
case 'info': return LogLevel.INFO;
|
||||
case 'debug': return LogLevel.DEBUG;
|
||||
case 'error': return LogLevel.ERROR;
|
||||
case 'warning': return LogLevel.WARN;
|
||||
default: return LogLevel.INFO;
|
||||
}
|
||||
}
|
||||
|
||||
export function log(logger: ILogger, toLog: string): void {
|
||||
const segments = toLog.split('time').filter(s => s.trim().length > 0);
|
||||
for (const segment of segments) {
|
||||
const maybeDaemonLog = parse(`time${segment}`.trim());
|
||||
if (is(maybeDaemonLog)) {
|
||||
const { msg } = maybeDaemonLog;
|
||||
logger.log(toLogLevel(maybeDaemonLog), msg);
|
||||
} else {
|
||||
logger.info(toLog.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Super naive.
|
||||
function parse(toLog: string): string | DaemonLog {
|
||||
const rawSegments = toLog.split(/(\s+)/)
|
||||
.map(segment => segment.replace(/['"]+/g, ''))
|
||||
.map(segment => segment.trim())
|
||||
.filter(segment => segment.length > 0);
|
||||
|
||||
const timeIndex = rawSegments.findIndex(segment => segment.startsWith('time='));
|
||||
const levelIndex = rawSegments.findIndex(segment => segment.startsWith('level='));
|
||||
const msgIndex = rawSegments.findIndex(segment => segment.startsWith('msg='));
|
||||
if (rawSegments.length > 2
|
||||
&& timeIndex !== -1
|
||||
&& levelIndex !== -1
|
||||
&& msgIndex !== -1) {
|
||||
return {
|
||||
time: rawSegments[timeIndex].split('=')[1],
|
||||
level: rawSegments[levelIndex].split('=')[1] as Level,
|
||||
msg: [rawSegments[msgIndex].split('=')[1], ...rawSegments.slice(msgIndex + 1)].join(' ')
|
||||
}
|
||||
}
|
||||
// Otherwise, log the string as is.
|
||||
return toLog;
|
||||
}
|
||||
}
|
46
arduino-ide-extension/src/node/library-service-impl.ts
Normal file
46
arduino-ide-extension/src/node/library-service-impl.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { Library, LibraryService } from '../common/protocol/library-service';
|
||||
|
||||
@injectable()
|
||||
export class LibraryServiceImpl implements LibraryService {
|
||||
|
||||
async search(options: { query?: string; }): Promise<{ items: Library[] }> {
|
||||
const { query } = options;
|
||||
const allItems: Library[] = [
|
||||
<Library>{
|
||||
name: 'Keyboard',
|
||||
availableVersions: ['1.0.0', '1.0.1', '1.02'],
|
||||
author: 'Arduino',
|
||||
summary: 'Allows an Arduino/Genuino board with USB capabilities to act as a Keyboard',
|
||||
description: 'This library plugs on the HID library. It can be used with or without other HIG-based libraries (Mouse, Gamepad etc)',
|
||||
installedVersion: '1.0.1',
|
||||
moreInfoLink: 'https://www.arduino.cc/reference/en/language/functions/usb/keyboard/',
|
||||
builtIn: true
|
||||
},
|
||||
<Library>{
|
||||
name: 'Mouse',
|
||||
availableVersions: ['1.0.0', '1.0.1'],
|
||||
author: 'Arduino',
|
||||
summary: 'Allows an Arduino board with USB capabilities to act as a Mouse. For Leonardo/Micro only',
|
||||
description: 'This library plugs on the HID library. Can be used with ot without other HID-based libraries (Keyboard, Gamepad etc)',
|
||||
installedVersion: '1.0.1',
|
||||
moreInfoLink: 'https://www.arduino.cc/reference/en/language/functions/usb/mouse/',
|
||||
builtIn: true
|
||||
},
|
||||
<Library>{
|
||||
name: 'USBHost',
|
||||
availableVersions: ['1.0.0', '1.0.1', '1.02', '1.0.3', '1.0.3', '1.0.4', '1.0.5'],
|
||||
author: 'Arduino',
|
||||
summary: 'Allows communication with USB peripherals like mice, keyboard, and thumbdrives.',
|
||||
// tslint:disable-next-line:max-line-length
|
||||
description: 'This USBHost library allows an Arduino Due board to appear as a USB host, enabling it to communicate with peripherals like USB mice and keyboards. USBHost does not support devices that ace corrected through USB hubs. This includes some keyboards that have an internal hub.',
|
||||
moreInfoLink: 'https://www.arduino.cc/en/Reference/USBHost',
|
||||
installable: true
|
||||
}
|
||||
];
|
||||
return {
|
||||
items: allItems.filter(item => !query || item.name.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) !== -1)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
16
arduino-ide-extension/src/node/util.ts
Normal file
16
arduino-ide-extension/src/node/util.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import * as grpc from "grpc";
|
||||
import * as jspb from "google-protobuf";
|
||||
|
||||
export type GrpcMethod<Req, Resp> = (request: Req, callback: (error: grpc.ServiceError | null, response: Resp) => void) => grpc.ClientUnaryCall
|
||||
|
||||
export function promisify<M extends GrpcMethod<Req, Resp>, Req, Resp extends jspb.Message>(m: M, req: Req): Promise<Resp> {
|
||||
return new Promise<Resp>((resolve, reject) => {
|
||||
m(req, (err, resp) => {
|
||||
if (!!err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(resp);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
30
arduino-ide-extension/tsconfig.json
Normal file
30
arduino-ide-extension/tsconfig.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noImplicitAny": true,
|
||||
"noEmitOnError": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"strictNullChecks": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"target": "es5",
|
||||
"outDir": "lib",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"files": [
|
||||
"../node_modules/@theia/monaco/src/typings/monaco/index.d.ts"
|
||||
]
|
||||
}
|
38
arduino-ide-extension/tslint.json
Normal file
38
arduino-ide-extension/tslint.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"rules": {
|
||||
"class-name": true,
|
||||
"comment-format": [true, "check-space"],
|
||||
"curly": false,
|
||||
"forin": false,
|
||||
"indent": [true, "spaces"],
|
||||
"max-line-length": [true, 180],
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"one-line": [true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"radix": true,
|
||||
"trailing-comma": [false],
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
"typedef-whitespace": [true, {
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}],
|
||||
"variable-name": false,
|
||||
"whitespace": [true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
19
electron/.gitignore
vendored
Normal file
19
electron/.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# The working-copy folder we use to package the application.
|
||||
working-copy/
|
||||
|
||||
# Ignore all Theia generated things.
|
||||
*.log
|
||||
src-gen/
|
||||
node_modules/
|
||||
build/yarn.lock
|
||||
webpack.config.js
|
||||
lib/
|
||||
|
||||
# The electron-builder output.
|
||||
dist/
|
||||
|
||||
# `dotenv` can provide dynamic input for the elecrton-builder. e.g.: commitish for the build.
|
||||
electron-builder.env
|
||||
|
||||
# The generated `package.json` under the `build` folder.
|
||||
build/package.json
|
48
electron/README.md
Normal file
48
electron/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
## Electron
|
||||
|
||||
All-in-one packager producing the `Arduino-PoC` Electron-based application.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The prerequisites are defined [here](https://github.com/theia-ide/theia/blob/master/doc/Developing.md#prerequisites).
|
||||
|
||||
### Build:
|
||||
To build the Arduino-PoC Electron-based Theia application you have to do the followings:
|
||||
```bash
|
||||
yarn --cwd ./electron/packager/
|
||||
```
|
||||
|
||||
The packaged application will be under the `./electron/build/dist` folder.
|
||||
|
||||
### CI:
|
||||
The electron packager runs when:
|
||||
- the build is manually triggered by the user, or
|
||||
- on scheduled (CRON) jobs.
|
||||
|
||||
### Creating a Release Draft:
|
||||
One can create a GitHub release draft, tag the source, and upload the artifacts to GitHub with Azure.
|
||||
- Go to the Azure [build](https://dev.azure.com/typefox/Arduino/_build) page.
|
||||
- Click on `Queue` in the top right corner.
|
||||
- Set the branch to `master` or leave as is if it is already showing `master`.
|
||||
- Add the `Release.Tag` pipeline variable and set the desired release version. Note, the version must start with `v` and we recommend naming tags that fit within [semantic versioning](https://semver.org).
|
||||
|
||||

|
||||
|
||||
- Click on `Queue`.
|
||||
- 🎈🎉
|
||||
|
||||
|
||||
### Publishing the Release Draft:
|
||||
One has to manually publish the GitHub release.
|
||||
- Go to the [release page](https://github.com/TypeFox/arduino-poc/releases) of the arduino-poc repository.
|
||||
- Select your release draft.
|
||||
- Click on `Edit`.
|
||||
|
||||

|
||||
|
||||
- Optionally, you can adjust the release draft if you want.
|
||||
|
||||

|
||||
|
||||
- Select `Publish release`.
|
||||
- ✨
|
BIN
electron/build/resources/icon.icns
Normal file
BIN
electron/build/resources/icon.icns
Normal file
Binary file not shown.
BIN
electron/build/resources/icon.ico
Normal file
BIN
electron/build/resources/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 359 KiB |
76
electron/build/template-package.json
Normal file
76
electron/build/template-package.json
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
"name": "arduino-electron",
|
||||
"description": "Arduino-PoC Electron",
|
||||
"main": "src-gen/frontend/electron-main.js",
|
||||
"author": "TypeFox",
|
||||
"dependencies": {
|
||||
"arduino-ide-extension": "file:../working-copy/arduino-ide-extension"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron-builder": "^20.36.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "theia build --mode development",
|
||||
"build:release": "theia build --mode production",
|
||||
"package": "electron-builder --publish=never",
|
||||
"package:preview": "electron-builder --dir"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/TypeFox/arduino-poc.git"
|
||||
},
|
||||
"build": {
|
||||
"productName": "Arduino-PoC",
|
||||
"appId": "arduino.PoC",
|
||||
"asar": false,
|
||||
"directories": {
|
||||
"buildResources": "resources"
|
||||
},
|
||||
"files": [
|
||||
"src-gen/**/*",
|
||||
"lib/**/*",
|
||||
"!node_modules/**/*.{ts,map}",
|
||||
"!node_modules/**/*.spec.js",
|
||||
"!node_modules/@theia/**/test/*",
|
||||
"!node_modules/@theia/**/src/*",
|
||||
"!node_modules/@theia/java/download",
|
||||
"!node_modules/@theia/**/lib/*browser/*",
|
||||
"!node_modules/@typefox/monaco-editor-core/*",
|
||||
"!node_modules/oniguruma/*",
|
||||
"!node_modules/onigasm/*"
|
||||
],
|
||||
"win": {
|
||||
"target": [
|
||||
"zip"
|
||||
],
|
||||
"artifactName": "${productName}-${env.ARDUINO_VERSION}-${os}.${ext}"
|
||||
},
|
||||
"mac": {
|
||||
"target": [
|
||||
"dmg"
|
||||
],
|
||||
"artifactName": "${productName}-${env.ARDUINO_VERSION}-${os}.${ext}",
|
||||
"darkModeSupport": true
|
||||
},
|
||||
"dmg": {
|
||||
"icon": "resources/icon.icns",
|
||||
"iconSize": 128,
|
||||
"contents": [
|
||||
{
|
||||
"x": 380,
|
||||
"y": 240,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
},
|
||||
{
|
||||
"x": 122,
|
||||
"y": 240,
|
||||
"type": "file"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
31
electron/packager/cli
Executable file
31
electron/packager/cli
Executable file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
const { versionInfo } = require('./utils');
|
||||
const yargs = require('yargs');
|
||||
|
||||
(() => {
|
||||
yargs
|
||||
.command({
|
||||
command: 'name',
|
||||
describe: 'Returns with the application name we build. The name includes the full application name with the version, the platform and the file extension.',
|
||||
handler: () => {
|
||||
const { platform } = process;
|
||||
let ext = undefined;
|
||||
let os = undefined;
|
||||
if (platform === 'darwin') {
|
||||
ext = 'dmg';
|
||||
os = 'mac';
|
||||
} else if (platform === 'win32') {
|
||||
ext = 'zip';
|
||||
os = 'win';
|
||||
} else {
|
||||
process.stderr.write(`Unexpected platform: ${platform}.`);
|
||||
process.exit(1);
|
||||
}
|
||||
process.stdout.write(`Arduino-PoC-${versionInfo().version}-${os}.${ext}`);
|
||||
process.exit(0);
|
||||
}
|
||||
})
|
||||
.demandCommand(1)
|
||||
.argv;
|
||||
})();
|
188
electron/packager/index.js
Normal file
188
electron/packager/index.js
Normal file
@ -0,0 +1,188 @@
|
||||
//@ts-check
|
||||
|
||||
(async () => {
|
||||
|
||||
const fs = require('fs');
|
||||
const join = require('path').join;
|
||||
const shell = require('shelljs');
|
||||
const utils = require('./utils');
|
||||
const { version, release } = utils.versionInfo();
|
||||
|
||||
echo(`📦 Building ${release ? 'release ' : ''}version '${version}'...`);
|
||||
|
||||
const workingCopy = 'working-copy';
|
||||
|
||||
/**
|
||||
* Relative path from the `__dirname` to the root where the `arduino-ide-extension` and the `arduino-ide-electron` folders are.
|
||||
* This could come handy when moving the location of the `electron/packager`.
|
||||
*/
|
||||
const rootPath = join('..', '..');
|
||||
|
||||
// This is a HACK! We rename the root `node_modules` to something else. Otherwise, due to the hoisting,
|
||||
// multiple Theia extensions will be picked up.
|
||||
if (fs.existsSync(path(rootPath, 'node_modules'))) {
|
||||
// We either do this or change the project structure.
|
||||
echo('🔧 >>> [Hack] Renaming the root \'node_modules\' folder to \'.node_modules\'...');
|
||||
mv('-f', path(rootPath, 'node_modules'), path(rootPath, '.node_modules'));
|
||||
echo('👌 <<< [Hack] Renamed the root \'node_modules\' folder to \'.node_modules\'.')
|
||||
}
|
||||
|
||||
//---------------------------+
|
||||
// Clean the previous state. |
|
||||
//---------------------------+
|
||||
// rm -rf ../working-copy
|
||||
rm('-rf', path('..', workingCopy));
|
||||
// rm -rf ../build/dist
|
||||
rm('-rf', path('..', 'build', 'dist'));
|
||||
// rm -rf ../build/package.json
|
||||
rm('-rf', path('..', 'build', 'package.json'));
|
||||
|
||||
//----------------------------------------------------------------------------------------------+
|
||||
// Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. |
|
||||
//----------------------------------------------------------------------------------------------+
|
||||
mkdir('-p', path('..', workingCopy));
|
||||
for (const name of ['arduino-ide-extension', 'arduino-ide-electron', 'yarn.lock', 'package.json', 'lerna.json']) {
|
||||
cp('-rf', path(rootPath, name), path('..', workingCopy));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------+
|
||||
// No need to build the `arduino-ide-browser` example. |
|
||||
//-----------------------------------------------------+
|
||||
//@ts-ignore
|
||||
let pkg = require('../working-copy/package.json');
|
||||
const workspaces = pkg.workspaces;
|
||||
// We cannot remove the `arduino-ide-electron`. Otherwise, there is not way to collect the unused dependencies.
|
||||
const dependenciesToRemove = ['arduino-ide-browser'];
|
||||
for (const dependencyToRemove of dependenciesToRemove) {
|
||||
const index = workspaces.indexOf(dependencyToRemove);
|
||||
if (index !== -1) {
|
||||
workspaces.splice(index, 1);
|
||||
}
|
||||
}
|
||||
pkg.workspaces = workspaces;
|
||||
fs.writeFileSync(path('..', workingCopy, 'package.json'), JSON.stringify(pkg, null, 2));
|
||||
|
||||
//-------------------------------------------------------------------------------------------------+
|
||||
// Rebuild the extension with the copied `yarn.lock`. It is a must to use the same Theia versions. |
|
||||
//-------------------------------------------------------------------------------------------------+
|
||||
exec(`yarn --cwd ${path('..', workingCopy)}`, 'Building the Arduino Theia extensions');
|
||||
// Collect all unused dependencies by the backend. We have to remove them from the electron app.
|
||||
// The `bundle.js` already contains everything we need for the frontend.
|
||||
// We have to do it before changing the dependencies to `local-path`.
|
||||
const unusedDependencies = await utils.collectUnusedDependencies('../working-copy/arduino-ide-electron/');
|
||||
|
||||
//------------------------------------------------------------------------------------+
|
||||
// Merge the `working-copy/package.json` with `electron/build/template-package.json`. |
|
||||
//------------------------------------------------------------------------------------+
|
||||
// @ts-ignore
|
||||
pkg = require('../working-copy/arduino-ide-electron/package.json');
|
||||
// @ts-ignore
|
||||
const template = require('../build/template-package.json');
|
||||
template.build.files = [ ...template.build.files, ...unusedDependencies.map(name => `!node_modules/${name}`) ];
|
||||
pkg.dependencies = { ...pkg.dependencies, ...template.dependencies };
|
||||
pkg.devDependencies = { ...pkg.devDependencies, ...template.devDependencies };
|
||||
fs.writeFileSync(path('..', 'build', 'package.json'), JSON.stringify({
|
||||
...pkg,
|
||||
...template,
|
||||
dependencies: pkg.dependencies,
|
||||
devDependencies: pkg.devDependencies
|
||||
}, null, 2));
|
||||
|
||||
echo(`📜 Effective 'package.json' for the Arduino-PoC application is:
|
||||
-----------------------
|
||||
${fs.readFileSync(path('..', 'build', 'package.json')).toString()}
|
||||
-----------------------
|
||||
`);
|
||||
|
||||
//-------------------------------------------------------------------------------------------+
|
||||
// Install all private and public dependencies for the electron application and build Theia. |
|
||||
//-------------------------------------------------------------------------------------------+
|
||||
exec(`yarn --cwd ${path('..', 'build')}`, 'Installing dependencies');
|
||||
exec(`yarn --cwd ${path('..', 'build')} build${release ? ':release' : ''}`, 'Building the Arduino-PoC application');
|
||||
|
||||
//------------------------------------------------------------------------------+
|
||||
// Create a throw away dotenv file which we use to feed the builder with input. |
|
||||
//------------------------------------------------------------------------------+
|
||||
const dotenv = 'electron-builder.env';
|
||||
if (fs.existsSync(path('..', 'build', dotenv))) {
|
||||
rm('-rf', path('..', 'build', dotenv));
|
||||
}
|
||||
// For the releases we use the desired tag as is defined by `$(Release.Tag)` from Azure.
|
||||
// For the preview builds we use the version from the `electron/build/package.json` with the short commit hash.
|
||||
fs.writeFileSync(path('..', 'build', dotenv), `ARDUINO_VERSION=${version}`);
|
||||
|
||||
//-----------------------------------+
|
||||
// Package the electron application. |
|
||||
//-----------------------------------+
|
||||
exec(`yarn --cwd ${path('..', 'build')} package`, `Packaging your Arduino-PoC application`);
|
||||
echo(`🎉 Success. Your application is at: ${path('..', 'build', 'dist')}`);
|
||||
|
||||
restore();
|
||||
|
||||
//--------+
|
||||
// Utils. |
|
||||
//--------+
|
||||
function exec(command, toEcho) {
|
||||
if (toEcho) {
|
||||
echo(`⏱️ >>> ${toEcho}...`);
|
||||
}
|
||||
const { code, stderr, stdout } = shell.exec(command);
|
||||
if (code !== 0) {
|
||||
echo(`🔥 Error when executing ${command} => ${stderr}`);
|
||||
shell.exit(1);
|
||||
}
|
||||
if (toEcho) {
|
||||
echo(`👌 <<< ${toEcho}.`);
|
||||
}
|
||||
return stdout;
|
||||
}
|
||||
|
||||
function cp(options, source, destination) {
|
||||
shell.cp(options, source, destination);
|
||||
assertNoError();
|
||||
}
|
||||
|
||||
function rm(options, ...files) {
|
||||
shell.rm(options, files);
|
||||
assertNoError();
|
||||
}
|
||||
|
||||
function mv(options, source, destination) {
|
||||
shell.mv(options, source, destination);
|
||||
assertNoError();
|
||||
}
|
||||
|
||||
function mkdir(options, ...dir) {
|
||||
shell.mkdir(options, dir);
|
||||
assertNoError();
|
||||
}
|
||||
|
||||
function echo(command) {
|
||||
return shell.echo(command);
|
||||
}
|
||||
|
||||
function assertNoError() {
|
||||
const error = shell.error();
|
||||
if (error) {
|
||||
echo(error);
|
||||
restore();
|
||||
shell.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function restore() {
|
||||
if (fs.existsSync(path(rootPath, '.node_modules'))) {
|
||||
echo('🔧 >>> [Restore] Renaming the root \'.node_modules\' folder to \'node_modules\'...');
|
||||
mv('-f', path(rootPath, '.node_modules'), path(rootPath, 'node_modules'));
|
||||
echo('👌 >>> [Restore] Renamed the root \'.node_modules\' folder to \'node_modules\'.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins tha path from `__dirname`.
|
||||
*/
|
||||
function path(...paths) {
|
||||
return join(__dirname, ...paths);
|
||||
}
|
||||
|
||||
})();
|
22
electron/packager/package.json
Normal file
22
electron/packager/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "packager",
|
||||
"version": "1.0.0",
|
||||
"description": "Packager for the Arduino-PoC electron application",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"package": "node index.js",
|
||||
"cli": "./cli"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"depcheck": "^0.7.1",
|
||||
"shelljs": "^0.8.3",
|
||||
"yargs": "^12.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0"
|
||||
}
|
||||
}
|
100
electron/packager/utils.js
Normal file
100
electron/packager/utils.js
Normal file
@ -0,0 +1,100 @@
|
||||
//@ts-check
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const shell = require('shelljs');
|
||||
const depcheck = require('depcheck');
|
||||
|
||||
/**
|
||||
* Returns with the version info for the artifact.
|
||||
* If the `RELEASE_TAG` environment variable is set, we us that.
|
||||
* Falls back to the commit SHA if the `RELEASE_TAG` is the `$(Release.Tag)` string.
|
||||
* Otherwise, we concatenate the version of the extracted from `theia-app/electron-app/package.json`
|
||||
* and append the short commit SHA.
|
||||
*/
|
||||
function versionInfo() {
|
||||
if (typeof process.env.RELEASE_TAG === 'undefined' || /* Azure -> */ process.env.RELEASE_TAG === '$(Release.Tag)') {
|
||||
return {
|
||||
version: `${targetVersion()}-${currentCommitish()}`,
|
||||
release: false
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
version: process.env.RELEASE_TAG,
|
||||
release: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns with the absolute path of the `theia-app/electron-app/`.
|
||||
*/
|
||||
function arduinoExtensionPath() {
|
||||
// TODO: be smarter and locate the extension with Git: `git rev-parse --show-toplevel`.
|
||||
return path.join(__dirname, '..', '..', 'arduino-ide-extension');
|
||||
}
|
||||
|
||||
/**
|
||||
* The version extracted from the `package.json` of the `arduino-ide-extension`. Falls back to `x.x.x`.
|
||||
*/
|
||||
function targetVersion() {
|
||||
return JSON.parse(fs.readFileSync(path.join(arduinoExtensionPath(), 'package.json'), { encoding: 'utf8' })).version || 'x.x.x';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns with the trimmed result of the `git rev-parse --short HEAD` as the current commitish if `git` is on the `PATH`.
|
||||
* Otherwise, it returns with `DEV_BUILD`.
|
||||
*/
|
||||
function currentCommitish() {
|
||||
try {
|
||||
const gitPath = shell.which('git');
|
||||
const error = shell.error();
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
const { stderr, stdout } = shell.exec(`"${gitPath}" rev-parse --short HEAD`, { silent: true });
|
||||
if (stderr) {
|
||||
throw new Error(stderr.toString().trim());
|
||||
}
|
||||
return stdout.toString().trim();
|
||||
} catch (e) {
|
||||
return 'DEV_BUILD';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to an array of `npm` package names that are declared in the `package.json` but **not** used by the project.
|
||||
*/
|
||||
function collectUnusedDependencies(pathToProject = process.cwd()) {
|
||||
const p = path.isAbsolute(pathToProject) ? pathToProject : path.resolve(process.cwd(), pathToProject);
|
||||
console.log(`⏱️ >>> Collecting unused backend dependencies for ${p}.`);
|
||||
return new Promise(resolve => {
|
||||
depcheck(p, {
|
||||
ignoreDirs: [
|
||||
'frontend'
|
||||
],
|
||||
parsers: {
|
||||
'*.js': depcheck.parser.es6,
|
||||
'*.jsx': depcheck.parser.jsx
|
||||
},
|
||||
detectors: [
|
||||
depcheck.detector.requireCallExpression,
|
||||
depcheck.detector.importDeclaration
|
||||
],
|
||||
specials: [
|
||||
depcheck.special.eslint,
|
||||
depcheck.special.webpack
|
||||
]
|
||||
}, unused => {
|
||||
const { dependencies } = unused
|
||||
if (dependencies && dependencies.length > 0) {
|
||||
console.log(`👌 <<< The following unused dependencies have been found: ${JSON.stringify(dependencies, null, 2)}`);
|
||||
} else {
|
||||
console.log('👌 <<< No unused dependencies have been found.');
|
||||
}
|
||||
resolve(dependencies);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { versionInfo, collectUnusedDependencies };
|
723
electron/packager/yarn.lock
Normal file
723
electron/packager/yarn.lock
Normal file
@ -0,0 +1,723 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/code-frame@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
|
||||
integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.0.0"
|
||||
|
||||
"@babel/generator@^7.2.2":
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.2.tgz#fff31a7b2f2f3dad23ef8e01be45b0d5c2fc0132"
|
||||
integrity sha512-f3QCuPppXxtZOEm5GWPra/uYUjmNQlu9pbAD8D/9jze4pTY83rTtB1igTBSwvkeNlC5gR24zFFkz+2WHLFQhqQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.3.2"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.17.10"
|
||||
source-map "^0.5.0"
|
||||
trim-right "^1.0.1"
|
||||
|
||||
"@babel/helper-function-name@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
|
||||
integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
|
||||
dependencies:
|
||||
"@babel/helper-get-function-arity" "^7.0.0"
|
||||
"@babel/template" "^7.1.0"
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@babel/helper-get-function-arity@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
|
||||
integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813"
|
||||
integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==
|
||||
dependencies:
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@babel/highlight@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
|
||||
integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==
|
||||
dependencies:
|
||||
chalk "^2.0.0"
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.1":
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.2.tgz#95cdeddfc3992a6ca2a1315191c1679ca32c55cd"
|
||||
integrity sha512-QzNUC2RO1gadg+fs21fi0Uu0OuGNzRKEmgCxoLNzbCdoprLwjfmZwzUrpUNfJPaVRwBpDY47A17yYEGWyRelnQ==
|
||||
|
||||
"@babel/template@^7.1.0":
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
|
||||
integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/parser" "^7.2.2"
|
||||
"@babel/types" "^7.2.2"
|
||||
|
||||
"@babel/traverse@^7.2.3":
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8"
|
||||
integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.2.2"
|
||||
"@babel/helper-function-name" "^7.1.0"
|
||||
"@babel/helper-split-export-declaration" "^7.0.0"
|
||||
"@babel/parser" "^7.2.3"
|
||||
"@babel/types" "^7.2.2"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.10"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.2.2", "@babel/types@^7.3.2":
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.2.tgz#424f5be4be633fff33fb83ab8d67e4a8290f5a2f"
|
||||
integrity sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.17.10"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
builtin-modules@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.0.0.tgz#1e587d44b006620d90286cc7a9238bbc6129cab1"
|
||||
integrity sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg==
|
||||
|
||||
camelcase@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
|
||||
integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
cliui@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
|
||||
integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
|
||||
dependencies:
|
||||
string-width "^2.1.1"
|
||||
strip-ansi "^4.0.0"
|
||||
wrap-ansi "^2.0.0"
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
cross-spawn@^6.0.0:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
|
||||
dependencies:
|
||||
nice-try "^1.0.4"
|
||||
path-key "^2.0.1"
|
||||
semver "^5.5.0"
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
debug@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decamelize@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
depcheck@^0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/depcheck/-/depcheck-0.7.1.tgz#d4ef8511620fc5c783dafe27887cfdab533b1215"
|
||||
integrity sha512-apCWM7uXYt7LZa5StGLY5UwNba0f6qMHA+gskcxti3PhcEfTMgqJMPW3CSSnRbVZb70QzbjLTESBCvZ+T00V2g==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.3.1"
|
||||
"@babel/traverse" "^7.2.3"
|
||||
builtin-modules "^3.0.0"
|
||||
deprecate "^1.0.0"
|
||||
deps-regex "^0.1.4"
|
||||
js-yaml "^3.4.2"
|
||||
lodash "^4.17.11"
|
||||
minimatch "^3.0.2"
|
||||
please-upgrade-node "^3.1.1"
|
||||
require-package-name "^2.0.1"
|
||||
resolve "^1.10.0"
|
||||
walkdir "0.0.12"
|
||||
yargs "^12.0.1"
|
||||
|
||||
deprecate@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/deprecate/-/deprecate-1.1.0.tgz#bbd069d62b232175b4e8459b2650cd2bad51f4b8"
|
||||
integrity sha512-b5dDNQYdy2vW9WXUD8+RQlfoxvqztLLhDE+T7Gd37I5E8My7nJkKu6FmhdDeRWJ8B+yjZKuwjCta8pgi8kgSqA==
|
||||
|
||||
deps-regex@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/deps-regex/-/deps-regex-0.1.4.tgz#518667b7691460a5e7e0a341be76eb7ce8090184"
|
||||
integrity sha1-UYZnt2kUYKXn4KNBvnbrfOgJAYQ=
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
esprima@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
|
||||
|
||||
execa@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
|
||||
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^4.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
find-up@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
|
||||
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
|
||||
dependencies:
|
||||
locate-path "^3.0.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
get-caller-file@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
||||
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
|
||||
|
||||
get-stream@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
|
||||
dependencies:
|
||||
pump "^3.0.0"
|
||||
|
||||
glob@^7.0.0:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@^11.1.0:
|
||||
version "11.10.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.10.0.tgz#1e09776dffda5e01816b3bb4077c8b59c24eaa50"
|
||||
integrity sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ==
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
interpret@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
|
||||
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
|
||||
|
||||
invert-kv@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
|
||||
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
|
||||
|
||||
is-fullwidth-code-point@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
|
||||
integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-fullwidth-code-point@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
js-yaml@^3.4.2:
|
||||
version "3.12.1"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600"
|
||||
integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
lcid@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
|
||||
integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
|
||||
dependencies:
|
||||
invert-kv "^2.0.0"
|
||||
|
||||
locate-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
|
||||
integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
|
||||
dependencies:
|
||||
p-locate "^3.0.0"
|
||||
path-exists "^3.0.0"
|
||||
|
||||
lodash@^4.17.10, lodash@^4.17.11:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
|
||||
map-age-cleaner@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
|
||||
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
|
||||
dependencies:
|
||||
p-defer "^1.0.0"
|
||||
|
||||
mem@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a"
|
||||
integrity sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==
|
||||
dependencies:
|
||||
map-age-cleaner "^0.1.1"
|
||||
mimic-fn "^1.0.0"
|
||||
p-is-promise "^2.0.0"
|
||||
|
||||
mimic-fn@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
|
||||
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
|
||||
|
||||
minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
ms@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-locale@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
|
||||
integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
|
||||
dependencies:
|
||||
execa "^1.0.0"
|
||||
lcid "^2.0.0"
|
||||
mem "^4.0.0"
|
||||
|
||||
p-defer@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
|
||||
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||
|
||||
p-is-promise@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5"
|
||||
integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==
|
||||
|
||||
p-limit@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68"
|
||||
integrity sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==
|
||||
dependencies:
|
||||
p-try "^2.0.0"
|
||||
|
||||
p-locate@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
|
||||
integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
|
||||
dependencies:
|
||||
p-limit "^2.0.0"
|
||||
|
||||
p-try@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
|
||||
integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==
|
||||
|
||||
path-exists@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
|
||||
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
path-key@^2.0.0, path-key@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
|
||||
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
please-upgrade-node@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz#ed320051dfcc5024fae696712c8288993595e8ac"
|
||||
integrity sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==
|
||||
dependencies:
|
||||
semver-compare "^1.0.0"
|
||||
|
||||
pump@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
rechoir@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
||||
integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
|
||||
dependencies:
|
||||
resolve "^1.1.6"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
|
||||
|
||||
require-main-filename@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
|
||||
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
|
||||
|
||||
require-package-name@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
|
||||
integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=
|
||||
|
||||
resolve@^1.1.6, resolve@^1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
|
||||
integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
semver-compare@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||
integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
|
||||
|
||||
semver@^5.5.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
|
||||
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
|
||||
|
||||
shelljs@^0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
|
||||
integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
||||
|
||||
source-map@^0.5.0:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
string-width@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
|
||||
dependencies:
|
||||
code-point-at "^1.0.0"
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
string-width@^2.0.0, string-width@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
dependencies:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
||||
|
||||
trim-right@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
|
||||
|
||||
walkdir@0.0.12:
|
||||
version "0.0.12"
|
||||
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.12.tgz#2f24f1ade64aab1e458591d4442c8868356e9281"
|
||||
integrity sha512-HFhaD4mMWPzFSqhpyDG48KDdrjfn409YQuVW7ckZYhW4sE87mYtWifdB/+73RA7+p4s4K18n5Jfx1kHthE1gBw==
|
||||
|
||||
which-module@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
||||
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
|
||||
|
||||
which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wrap-ansi@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
||||
integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
|
||||
dependencies:
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
"y18n@^3.2.1 || ^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
|
||||
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
|
||||
|
||||
yargs-parser@^11.1.1:
|
||||
version "11.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
|
||||
integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
|
||||
dependencies:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
||||
yargs@^12.0.1, yargs@^12.0.5:
|
||||
version "12.0.5"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
|
||||
integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
|
||||
dependencies:
|
||||
cliui "^4.0.0"
|
||||
decamelize "^1.2.0"
|
||||
find-up "^3.0.0"
|
||||
get-caller-file "^1.0.1"
|
||||
os-locale "^3.0.0"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^1.0.1"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^2.0.0"
|
||||
which-module "^2.0.0"
|
||||
y18n "^3.2.1 || ^4.0.0"
|
||||
yargs-parser "^11.1.1"
|
BIN
electron/static/azure-create-gh-release.jpg
Normal file
BIN
electron/static/azure-create-gh-release.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
BIN
electron/static/edit-gh-release-draft.jpg
Normal file
BIN
electron/static/edit-gh-release-draft.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
electron/static/publish-gh-release.jpg
Normal file
BIN
electron/static/publish-gh-release.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
11
lerna.json
Normal file
11
lerna.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"lerna": "2.4.0",
|
||||
"version": "independent",
|
||||
"useWorkspaces": true,
|
||||
"npmClient": "yarn",
|
||||
"command": {
|
||||
"run": {
|
||||
"stream": true
|
||||
}
|
||||
}
|
||||
}
|
22
package.json
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "arduino-poc",
|
||||
"version": "0.0.1",
|
||||
"description": "A proof-of-concent demonstrating an Arduino IDE built using Theia",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/TypeFox/arduino-poc.git",
|
||||
"author": "Christian Weichel <christian.weichel@typefox.io>",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"lerna": "^3.13.3"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "lerna run prepare",
|
||||
"start": "cd arduino-ide-browser && yarn start"
|
||||
},
|
||||
"workspaces": [
|
||||
"arduino-ide-electron",
|
||||
"arduino-ide-browser",
|
||||
"arduino-ide-extension"
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user