├── .gitignore ├── media ├── view.gif ├── symfony.png ├── autocomplete.gif ├── dark │ ├── goto.svg │ ├── cancel.svg │ └── search.svg ├── light │ ├── goto.svg │ ├── cancel.svg │ └── search.svg └── logo.svg ├── .gitattributes ├── src ├── symfony │ ├── Searchable.ts │ ├── AbstractContainerStoreListener.ts │ ├── provider │ │ ├── ContainerProviderInterface.ts │ │ ├── CacheContainerProvider.ts │ │ └── ConsoleContainerProvider.ts │ ├── RouteDefinition.ts │ ├── Parameter.ts │ ├── ServiceDefinition.ts │ ├── ComposerJSON.ts │ ├── ContainerCacheManager.ts │ └── ContainerStore.ts ├── mvc │ ├── containerview │ │ ├── AbstractContainerTreeItem.ts │ │ ├── ParameterTreeItem.ts │ │ ├── ParameterViewProvider.ts │ │ ├── RouteDefinitionViewProvider.ts │ │ ├── ServiceDefintionViewProvider.ts │ │ ├── RouteDefinitionTreeItem.ts │ │ ├── ServiceDefinitionTreeItem.ts │ │ └── AbstractContainerViewProvider.ts │ ├── editing │ │ ├── definition │ │ │ ├── ConfigurationFileServiceDefinitionProvider.ts │ │ │ ├── PHPServiceDefinitionProvider.ts │ │ │ └── AbstractServiceDefinitionProvider.ts │ │ ├── quickpick │ │ │ └── ServiceQuickPickItem.ts │ │ ├── autocomplete │ │ │ ├── ParameterCompletionItem.ts │ │ │ ├── ConfigurationFileServiceCompletionItem.ts │ │ │ ├── PHPServiceCompletionItem.ts │ │ │ ├── PHPServiceProvider.ts │ │ │ └── ConfigurationFileProvider.ts │ │ ├── EditingUtils.ts │ │ ├── hover │ │ │ └── ContainerHoverProvider.ts │ │ └── codeaction │ │ │ ├── ServiceDocumentationCodeAction.ts │ │ │ └── ServiceDocumentationCodeActionProvider.ts │ ├── PHPClassesController.ts │ ├── ParametersCommandController.ts │ ├── RoutesCommandController.ts │ ├── FileWatchController.ts │ ├── ServicesCommandController.ts │ └── AutocompleteController.ts ├── php │ ├── provider │ │ ├── PHPClassProviderInterface.ts │ │ ├── CachePHPClassProvider.ts │ │ └── ParserPHPClassProvider.ts │ ├── PHPUse.ts │ ├── PHPClassCacheManager.ts │ ├── PHPClass.ts │ ├── PromiseUtils.ts │ └── PHPClassStore.ts ├── test │ ├── extension.test.ts │ └── index.ts └── extension.ts ├── .vscodeignore ├── .vscode ├── settings.json ├── tasks.json └── launch.json ├── tsconfig.json ├── ENVIRONMENTS.md ├── LICENSE ├── vsc-extension-quickstart.md ├── CONTRIBUTING.md ├── CHANGELOG.md ├── README.md ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | *.log 6 | -------------------------------------------------------------------------------- /media/view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheNouillet/symfony-vscode/HEAD/media/view.gif -------------------------------------------------------------------------------- /media/symfony.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheNouillet/symfony-vscode/HEAD/media/symfony.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /media/autocomplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheNouillet/symfony-vscode/HEAD/media/autocomplete.gif -------------------------------------------------------------------------------- /src/symfony/Searchable.ts: -------------------------------------------------------------------------------- 1 | export interface Searchable { 2 | acceptSearchCriteria(criteria: string): number 3 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | src/** 6 | .gitignore 7 | tsconfig.json 8 | vsc-extension-quickstart.md 9 | tslint.json -------------------------------------------------------------------------------- /src/mvc/containerview/AbstractContainerTreeItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | 3 | export abstract class AbstractContainerTreeItem extends vscode.TreeItem { 4 | constructor(label: string, state: vscode.TreeItemCollapsibleState) { 5 | super(label, state) 6 | } 7 | 8 | abstract get childrenItems(): vscode.TreeItem[] 9 | } -------------------------------------------------------------------------------- /src/php/provider/PHPClassProviderInterface.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClass } from "../PHPClass"; 3 | 4 | export interface PHPClassProviderInterface { 5 | canUpdateAllUris(): boolean 6 | canUpdateUri(uri: vscode.Uri): boolean 7 | updateAllUris(): Promise 8 | updateUri(uri: vscode.Uri): Promise 9 | } -------------------------------------------------------------------------------- /src/php/PHPUse.ts: -------------------------------------------------------------------------------- 1 | export class PHPUse { 2 | public className: string 3 | public alias: string 4 | 5 | constructor(className: string, alias?: string) { 6 | this.className = className 7 | this.alias = alias 8 | } 9 | 10 | get shortName(): string { 11 | if(this.alias) { 12 | return this.alias 13 | } else { 14 | return this.className.split('\\').pop() 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/symfony/AbstractContainerStoreListener.ts: -------------------------------------------------------------------------------- 1 | import { ServiceDefinition } from "./ServiceDefinition"; 2 | import { RouteDefinition } from "./RouteDefinition"; 3 | import { Parameter } from "./Parameter"; 4 | 5 | export abstract class AbstractContainerStoreListener 6 | { 7 | onServicesChanges(servicesDefinitions: ServiceDefinition[]){} 8 | onRoutesChanges(routesDefinitions: RouteDefinition[]){} 9 | onParametersChanges(parameters: Parameter[]){} 10 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /src/mvc/editing/definition/ConfigurationFileServiceDefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { AbstractServiceDefinitionProvider } from "./AbstractServiceDefinitionProvider"; 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | 4 | export class ConfigurationFileServiceDefinitionProvider extends AbstractServiceDefinitionProvider { 5 | acceptServiceDefinition(hoveredWord: string, serviceDefinition: ServiceDefinition): boolean { 6 | return hoveredWord === serviceDefinition.id || hoveredWord === serviceDefinition.className 7 | } 8 | } -------------------------------------------------------------------------------- /src/mvc/PHPClassesController.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClassStore } from "../php/PHPClassStore"; 3 | import { PHPClassCacheManager } from "../php/PHPClassCacheManager"; 4 | 5 | export class PHPClassesController { 6 | protected _phpClassStore: PHPClassStore 7 | 8 | constructor(phpClassStore: PHPClassStore) { 9 | this._phpClassStore = phpClassStore 10 | vscode.commands.registerCommand('symfony-vscode.refreshPHPClasses', () => { 11 | this._phpClassStore.clearCacheAndRefreshAll() 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /media/dark/goto.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /media/light/goto.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /src/symfony/provider/ContainerProviderInterface.ts: -------------------------------------------------------------------------------- 1 | import { ServiceDefinition } from "../ServiceDefinition"; 2 | import { RouteDefinition } from "../RouteDefinition"; 3 | import { Parameter } from "../Parameter"; 4 | 5 | export interface ContainerProviderInterface { 6 | canProvideServiceDefinitions(): boolean 7 | canProvideRouteDefinitions(): boolean 8 | canProvideParameters(): boolean 9 | provideServiceDefinitions(): Promise 10 | provideRouteDefinitions(): Promise 11 | provideParameters(): Promise 12 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /src/mvc/editing/quickpick/ServiceQuickPickItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | 4 | export class ServiceQuickPickItem implements vscode.QuickPickItem { 5 | public serviceDefinition: ServiceDefinition 6 | 7 | constructor(serviceDefinition: ServiceDefinition) { 8 | this.serviceDefinition = serviceDefinition 9 | } 10 | 11 | get label(): string { 12 | return this.serviceDefinition.id 13 | } 14 | 15 | get detail(): string { 16 | return this.serviceDefinition.className 17 | } 18 | } -------------------------------------------------------------------------------- /src/mvc/editing/definition/PHPServiceDefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { AbstractServiceDefinitionProvider } from "./AbstractServiceDefinitionProvider"; 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | 4 | export class PHPServiceDefinitionProvider extends AbstractServiceDefinitionProvider { 5 | acceptServiceDefinition(hoveredWord: string, serviceDefinition: ServiceDefinition): boolean { 6 | if(serviceDefinition.isServiceIdAClassName()) { 7 | return false 8 | } else { 9 | return hoveredWord === serviceDefinition.id 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/mvc/editing/autocomplete/ParameterCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { Parameter } from "../../../symfony/Parameter"; 3 | 4 | export class ParameterCompletionItem extends vscode.CompletionItem { 5 | public parameter: Parameter 6 | 7 | constructor(parameter: Parameter) { 8 | super(parameter.name, vscode.CompletionItemKind.Property) 9 | this.parameter = parameter 10 | } 11 | 12 | public get detail(): string { 13 | return this.parameter.name 14 | } 15 | 16 | public get documentation(): string { 17 | return "Of value : " + this.parameter.value 18 | } 19 | } -------------------------------------------------------------------------------- /src/mvc/editing/autocomplete/ConfigurationFileServiceCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | 4 | export class ConfigurationFileServiceCompletionItem extends vscode.CompletionItem { 5 | private _serviceDefinition: ServiceDefinition 6 | 7 | constructor(serviceDefinition: ServiceDefinition) { 8 | super(serviceDefinition.id, vscode.CompletionItemKind.Reference) 9 | this._serviceDefinition = serviceDefinition 10 | } 11 | 12 | public get detail(): string { 13 | return this._serviceDefinition.id 14 | } 15 | 16 | public get documentation(): string { 17 | return "Of class " + this._serviceDefinition.className 18 | } 19 | } -------------------------------------------------------------------------------- /src/mvc/containerview/ParameterTreeItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { Parameter } from "../../symfony/Parameter"; 3 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 4 | 5 | export class ParameterTreeItem extends AbstractContainerTreeItem { 6 | private _parameter: Parameter 7 | 8 | constructor( 9 | parameter: Parameter 10 | ) { 11 | super(parameter.name, vscode.TreeItemCollapsibleState.Collapsed) 12 | this._parameter = parameter 13 | } 14 | 15 | get tooltip() { 16 | return this._parameter.value 17 | } 18 | 19 | get childrenItems(): vscode.TreeItem[] { 20 | return [new vscode.TreeItem("Value : " + this._parameter.value, vscode.TreeItemCollapsibleState.None)] 21 | } 22 | } -------------------------------------------------------------------------------- /media/dark/cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /media/light/cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/test/extension.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Note: This example test is leveraging the Mocha test framework. 3 | // Please refer to their documentation on https://mochajs.org/ for help. 4 | // 5 | 6 | // The module 'assert' provides assertion methods from node 7 | import * as assert from 'assert'; 8 | 9 | // You can import and use all API from the 'vscode' module 10 | // as well as import your extension to test it 11 | // import * as vscode from 'vscode'; 12 | // import * as myExtension from '../extension'; 13 | 14 | // Defines a Mocha test suite to group tests of similar kind together 15 | suite("Extension Tests", function () { 16 | 17 | // Defines a Mocha unit test 18 | test("Something 1", function() { 19 | assert.equal(-1, [1, 2, 3].indexOf(5)); 20 | assert.equal(-1, [1, 2, 3].indexOf(0)); 21 | }); 22 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | /* Strict Type-Checking Option */ 12 | "strict": false, /* enable all strict type-checking options */ 13 | /* Additional Checks */ 14 | "noUnusedLocals": false /* Report errors on unused locals. */ 15 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 16 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 17 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | ".vscode-test" 22 | ] 23 | } -------------------------------------------------------------------------------- /src/mvc/editing/autocomplete/PHPServiceCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | 4 | export class PHPServiceCompletionItem extends vscode.CompletionItem { 5 | private _serviceDefinition: ServiceDefinition 6 | 7 | constructor(serviceDefinition: ServiceDefinition) { 8 | super(serviceDefinition.id, vscode.CompletionItemKind.Reference) 9 | this._serviceDefinition = serviceDefinition 10 | } 11 | 12 | public get insertText(): string { 13 | if(!this._serviceDefinition.isServiceIdAClassName()) { 14 | return this._serviceDefinition.id 15 | } else { 16 | return this._serviceDefinition.className + "::class" 17 | } 18 | } 19 | 20 | public get detail(): string { 21 | return this._serviceDefinition.id 22 | } 23 | 24 | public get documentation(): string { 25 | return "Of class " + this._serviceDefinition.className 26 | } 27 | } -------------------------------------------------------------------------------- /ENVIRONMENTS.md: -------------------------------------------------------------------------------- 1 | # Settings for different environments 2 | 3 | This file sums up settings to put in your VSCode, so that the extension can work and help you developping your Symfony projects. 4 | 5 | ## Windows 6 | 7 | You have to change the PHP path if you're working on Windows : 8 | 9 | ```json 10 | { 11 | "symfony-vscode.phpExecutablePath": "c:\\xampp\\php\\php.exe" 12 | } 13 | ``` 14 | 15 | 16 | ## Docker 17 | 18 | [Docker](https://www.docker.com/) is used to perform containerization. 19 | 20 | ```json 21 | { 22 | "symfony-vscode.shellExecutable": "/bin/bash", 23 | "symfony-vscode.shellCommand": "docker exec /bin/sh -c 'cd && php \"$@\"' -- " 24 | } 25 | ``` 26 | 27 | ## eZ Launchpad 28 | 29 | [eZ Launchpad](https://ezsystems.github.io/launchpad) is used to quickly install and deploy [eZ Platform](https://www.ezplatform.com) web sites. 30 | 31 | ```json 32 | { 33 | "symfony-vscode.shellExecutable": "/bin/bash", 34 | "symfony-vscode.shellCommand": "ez docker:sfrun \"$@\" -- " 35 | } 36 | ``` -------------------------------------------------------------------------------- /src/mvc/editing/autocomplete/PHPServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../../../symfony/ContainerStore"; 3 | import { PHPServiceCompletionItem } from "./PHPServiceCompletionItem"; 4 | 5 | export class PHPServiceProvider implements vscode.CompletionItemProvider { 6 | 7 | private _containerStore: ContainerStore 8 | 9 | constructor(containerStore: ContainerStore) { 10 | this._containerStore = containerStore 11 | } 12 | 13 | provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) { 14 | let result: vscode.CompletionItem[] = [] 15 | let serviceDefinitions = this._containerStore.serviceDefinitionList 16 | serviceDefinitions.forEach(serviceDefinition => { 17 | if(serviceDefinition.public) { 18 | let item = new PHPServiceCompletionItem(serviceDefinition) 19 | result.push(item) 20 | } 21 | }); 22 | return result 23 | } 24 | } -------------------------------------------------------------------------------- /src/test/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING 3 | // 4 | // This file is providing the test runner to use when running extension tests. 5 | // By default the test runner in use is Mocha based. 6 | // 7 | // You can provide your own test runner if you want to override it by exporting 8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension 9 | // host can call to run the tests. The test runner is expected to use console.log 10 | // to report the results back to the caller. When the tests are finished, return 11 | // a possible error to the callback or null if none. 12 | 13 | import * as testRunner from 'vscode/lib/testrunner'; 14 | 15 | // You can directly control Mocha options by uncommenting the following lines 16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info 17 | testRunner.configure({ 18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) 19 | useColors: true // colored output from test results 20 | }); 21 | 22 | module.exports = testRunner; -------------------------------------------------------------------------------- /src/symfony/RouteDefinition.ts: -------------------------------------------------------------------------------- 1 | import { Searchable } from "./Searchable"; 2 | 3 | export class RouteDefinition implements Searchable { 4 | public id: string 5 | public path: string 6 | public method: string 7 | public action: string 8 | 9 | constructor(id: string, path: string, method: string, action: string) { 10 | this.id = id 11 | this.path = path 12 | this.method = method 13 | this.action = action 14 | } 15 | 16 | acceptSearchCriteria(criteria: string): number { 17 | if (this.id && this.id.match(criteria)) { 18 | return 2 19 | } 20 | if (this.path && this.path.match(criteria)) { 21 | return 2 22 | } 23 | if (this.action && this.action.match(criteria)) { 24 | return 2 25 | } 26 | return 0 27 | } 28 | 29 | static fromJSON(jsonRouteDefinition: RouteDefinition): RouteDefinition { 30 | return new RouteDefinition( 31 | jsonRouteDefinition.id, jsonRouteDefinition.path, jsonRouteDefinition.method, jsonRouteDefinition.action 32 | ) 33 | } 34 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Veber Axel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/mvc/containerview/ParameterViewProvider.ts: -------------------------------------------------------------------------------- 1 | import { Parameter } from "../../symfony/Parameter"; 2 | import { AbstractContainerViewProvider } from "./AbstractContainerViewProvider"; 3 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 4 | import { ParameterTreeItem } from "./ParameterTreeItem"; 5 | 6 | export class ParameterViewProvider extends AbstractContainerViewProvider { 7 | private _parameters: Parameter[] = [] 8 | 9 | constructor() { 10 | super() 11 | } 12 | 13 | onParametersChanges(parameters: Parameter[]) { 14 | this._parameters = parameters 15 | this._onDidChangeTreeData.fire() 16 | } 17 | 18 | getTreeItems(): AbstractContainerTreeItem[] { 19 | let treeItems: ParameterTreeItem[] = [] 20 | 21 | this._parameters.forEach(parameter => { 22 | if(this.acceptSearchable(parameter)) { 23 | treeItems.push(new ParameterTreeItem(parameter)) 24 | } 25 | }); 26 | 27 | return treeItems 28 | } 29 | 30 | protected _getSearchItemContext(): string { 31 | return 'symfony-vscode.searchItem.parameter' 32 | } 33 | } -------------------------------------------------------------------------------- /media/dark/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 12 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /media/light/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 12 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/symfony/Parameter.ts: -------------------------------------------------------------------------------- 1 | import { Searchable } from "./Searchable"; 2 | 3 | export class Parameter implements Searchable { 4 | public name: string 5 | public value: string 6 | 7 | constructor(name: string, value: any) { 8 | this.name = name 9 | 10 | if (value === null) { 11 | this.value = "null" 12 | } else if (typeof value === "string") { 13 | this.value = value 14 | } else if (typeof value === "number") { 15 | this.value = value.toString() 16 | } else if (typeof value === "boolean") { 17 | this.value = value ? "true" : "false" 18 | } else if (typeof value === "object" && Array.isArray(value)) { 19 | this.value = "array" 20 | } else { 21 | this.value = typeof value 22 | } 23 | } 24 | 25 | acceptSearchCriteria(criteria: string): number { 26 | if (this.name && this.name.match(criteria)) { 27 | return 2 28 | } 29 | if (this.value && this.value.match(criteria)) { 30 | return 2 31 | } 32 | return 0 33 | } 34 | 35 | static fromJSON(jsonParameter: Parameter): Parameter { 36 | return new Parameter(jsonParameter.name, jsonParameter.value) 37 | } 38 | } -------------------------------------------------------------------------------- /src/symfony/ServiceDefinition.ts: -------------------------------------------------------------------------------- 1 | import { Searchable } from "./Searchable"; 2 | 3 | export class ServiceDefinition implements Searchable { 4 | public id: string 5 | public className: string 6 | public public: boolean 7 | public alias: string 8 | 9 | constructor(id: string, className: string, isPublic: boolean, alias: string) { 10 | this.id = id 11 | this.className = className 12 | this.public = isPublic 13 | this.alias = alias 14 | } 15 | 16 | public isServiceIdAClassName(): boolean { 17 | return this.id.match(/([A-Z]|\\)/) !== null 18 | } 19 | 20 | public acceptSearchCriteria(criteria: string): number { 21 | if(this.id && this.id.match(criteria)) { 22 | return 2 23 | } 24 | if(this.className && this.className.match(criteria)) { 25 | return 2 26 | } 27 | if(this.alias && this.alias.match(criteria)) { 28 | return 1 29 | } 30 | return 0 31 | } 32 | 33 | static fromJSON(jsonServiceDefinition: ServiceDefinition): ServiceDefinition { 34 | return new ServiceDefinition( 35 | jsonServiceDefinition.id, jsonServiceDefinition.className, jsonServiceDefinition.public, jsonServiceDefinition.alias 36 | ) 37 | } 38 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ] 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "runtimeExecutable": "${execPath}", 25 | "args": [ 26 | "--extensionDevelopmentPath=${workspaceFolder}", 27 | "--extensionTestsPath=${workspaceFolder}/out/test" 28 | ], 29 | "outFiles": [ 30 | "${workspaceFolder}/out/test/**/*.js" 31 | ], 32 | "preLaunchTask": "npm: watch" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /src/php/provider/CachePHPClassProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClassProviderInterface } from "./PHPClassProviderInterface" 3 | import { PHPClass } from "../PHPClass" 4 | import { PHPClassCacheManager } from "../PHPClassCacheManager"; 5 | 6 | export class CachePHPClassProvider implements PHPClassProviderInterface { 7 | 8 | protected _cacheManager: PHPClassCacheManager 9 | 10 | protected static NO_CLASS_IN_CACHE = "No cached classes" 11 | 12 | constructor(cacheManager: PHPClassCacheManager) { 13 | this._cacheManager = cacheManager 14 | } 15 | 16 | canUpdateAllUris(): boolean { 17 | return this._cacheManager.hasCachedData() 18 | } 19 | 20 | canUpdateUri(uri: vscode.Uri): boolean { 21 | return false 22 | } 23 | 24 | updateAllUris(): Promise { 25 | return new Promise((resolve, reject) => { 26 | if(this._cacheManager.hasCachedData()) { 27 | resolve(this._cacheManager.get()) 28 | } else { 29 | reject(CachePHPClassProvider.NO_CLASS_IN_CACHE) 30 | } 31 | }) 32 | } 33 | 34 | updateUri(uri: vscode.Uri): Promise { 35 | return new Promise((resolve) => { 36 | resolve([]) 37 | }) 38 | } 39 | } -------------------------------------------------------------------------------- /src/php/PHPClassCacheManager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClass } from "./PHPClass"; 3 | 4 | export class PHPClassCacheManager { 5 | 6 | protected _memento: vscode.Memento 7 | 8 | public static CACHE_KEY = "cached_php_store" 9 | 10 | constructor(memento: vscode.Memento) { 11 | this._memento = memento 12 | } 13 | 14 | hasCachedData() : boolean { 15 | return this._memento.get(PHPClassCacheManager.CACHE_KEY) !== undefined 16 | } 17 | 18 | get(): PHPClass[] { 19 | return this._memento.get(PHPClassCacheManager.CACHE_KEY).map(jsonPhpClass => { 20 | return PHPClass.fromJSON(jsonPhpClass) 21 | }) 22 | } 23 | 24 | set(phpClasses: PHPClass[]): Thenable { 25 | return this._memento.update(PHPClassCacheManager.CACHE_KEY, phpClasses) 26 | } 27 | 28 | clear(): Thenable { 29 | return this._memento.update(PHPClassCacheManager.CACHE_KEY, undefined) 30 | } 31 | 32 | clearClassByUri(phpClassUri: vscode.Uri): Thenable { 33 | let classes = this.get() 34 | let newClasses = [] 35 | classes.forEach(phpClass => { 36 | if(phpClass.documentUri !== phpClassUri) { 37 | newClasses.push(phpClass) 38 | } 39 | }); 40 | 41 | return this.set(newClasses) 42 | } 43 | } -------------------------------------------------------------------------------- /src/mvc/ParametersCommandController.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../symfony/ContainerStore"; 3 | import { ParameterViewProvider } from "./containerview/ParameterViewProvider"; 4 | 5 | export class ParametersCommandController { 6 | private _containerStore: ContainerStore 7 | private _parameterViewProvider: ParameterViewProvider 8 | 9 | constructor(containerStore: ContainerStore, parameterViewProvider: ParameterViewProvider) { 10 | this._containerStore = containerStore 11 | this._parameterViewProvider = parameterViewProvider 12 | 13 | vscode.commands.registerCommand('symfony-vscode.refreshParameters', () => { 14 | this._containerStore.clearCacheAndRefreshParameters() 15 | }) 16 | vscode.commands.registerCommand('symfony-vscode.searchForParameters', () => { 17 | vscode.window.showInputBox({ 18 | prompt: "Criteria (e.g. \"app\", \"doctrine\" ...)", 19 | value: this._parameterViewProvider.previousSearchCriteria 20 | }).then(criteria => { 21 | if(criteria !== undefined) { 22 | this._parameterViewProvider.setCriteria(criteria) 23 | } 24 | }) 25 | }) 26 | vscode.commands.registerCommand('symfony-vscode.clearParametersSearch', () => this._parameterViewProvider.clearCriteria()) 27 | } 28 | } -------------------------------------------------------------------------------- /src/mvc/editing/EditingUtils.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | 3 | export class EditingUtils { 4 | static getWordRange(document: vscode.TextDocument, position: vscode.Position): vscode.Range { 5 | let beginPosition = position.with() 6 | let endPosition = position.with() 7 | while(document.getText(new vscode.Range(beginPosition.translate(0, -1), beginPosition)).match(/[A-Za-z0-9_.\\~]/)) { 8 | beginPosition = beginPosition.translate(0, -1) 9 | } 10 | while(document.getText(new vscode.Range(endPosition.translate(0, 1), endPosition.translate(0, 2))).match(/[A-Za-z0-9_.\\~]/)) { 11 | endPosition = endPosition.translate(0, 1) 12 | } 13 | return new vscode.Range(beginPosition, endPosition.translate(0, 1)) 14 | } 15 | 16 | static getLineStartPosition(document: vscode.TextDocument, line: number): vscode.Position { 17 | let blanksCharacters = [" ", "\t"] 18 | let currentPosition = new vscode.Position(line, 0) 19 | while(blanksCharacters.indexOf(document.getText(new vscode.Range(currentPosition, currentPosition.translate(0, 1)))) !== -1) { 20 | 21 | currentPosition = currentPosition.translate(0, 1) 22 | if(!document.validatePosition(currentPosition)) { 23 | return currentPosition 24 | } 25 | } 26 | 27 | return currentPosition 28 | } 29 | } -------------------------------------------------------------------------------- /src/mvc/editing/hover/ContainerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ContainerStore } from "../../../symfony/ContainerStore" 3 | import { EditingUtils } from "../EditingUtils"; 4 | 5 | export class ContainerHoverProvider implements vscode.HoverProvider { 6 | private _containerStore: ContainerStore 7 | 8 | constructor(containerStore: ContainerStore) { 9 | this._containerStore = containerStore 10 | } 11 | 12 | provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { 13 | let wordRange = EditingUtils.getWordRange(document, position) 14 | let hoveredWord = document.getText(wordRange) 15 | let serviceDefinition = this._containerStore.serviceDefinitionList.find(serviceDefinition => { 16 | return hoveredWord === serviceDefinition.id 17 | }); 18 | if(serviceDefinition !== undefined) { 19 | return new vscode.Hover(serviceDefinition.className, wordRange) 20 | } else { 21 | let parameterDefinition = this._containerStore.parameterList.find(parameterDefinition => { 22 | return hoveredWord === parameterDefinition.name 23 | }) 24 | if(parameterDefinition !== undefined) { 25 | return new vscode.Hover("Value : " + parameterDefinition.value, wordRange) 26 | } else { 27 | return null 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/mvc/containerview/RouteDefinitionViewProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { RouteDefinition } from "../../symfony/RouteDefinition"; 3 | import { RouteDefinitionTreeItem } from "./RouteDefinitionTreeItem"; 4 | import { AbstractContainerViewProvider } from "./AbstractContainerViewProvider"; 5 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 6 | 7 | export class RouteDefinitionViewProvider extends AbstractContainerViewProvider { 8 | private _routesDefinitions: RouteDefinition[] = [] 9 | private _displayPaths: boolean = false 10 | 11 | constructor() { 12 | super() 13 | } 14 | 15 | onRoutesChanges(routesDefinitions: RouteDefinition[]) { 16 | this._routesDefinitions = routesDefinitions 17 | this._onDidChangeTreeData.fire() 18 | } 19 | 20 | togglePathsDisplay(): void { 21 | this._displayPaths = !this._displayPaths 22 | this._onDidChangeTreeData.fire() 23 | } 24 | 25 | getTreeItems(): AbstractContainerTreeItem[] { 26 | let treeItems: RouteDefinitionTreeItem[] = [] 27 | 28 | this._routesDefinitions.forEach(routeDefinition => { 29 | if(this.acceptSearchable(routeDefinition)) { 30 | treeItems.push(new RouteDefinitionTreeItem(routeDefinition, this._displayPaths)) 31 | } 32 | }); 33 | 34 | return treeItems 35 | } 36 | 37 | protected _getSearchItemContext(): string { 38 | return 'symfony-vscode.searchItem.route' 39 | } 40 | } -------------------------------------------------------------------------------- /src/mvc/containerview/ServiceDefintionViewProvider.ts: -------------------------------------------------------------------------------- 1 | import { ServiceDefinition } from "../../symfony/ServiceDefinition"; 2 | import { ServiceDefinitionTreeItem } from "./ServiceDefinitionTreeItem"; 3 | import { AbstractContainerViewProvider } from "./AbstractContainerViewProvider"; 4 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 5 | 6 | export class ServiceDefintionViewProvider extends AbstractContainerViewProvider { 7 | private _servicesDefinitions: ServiceDefinition[] = [] 8 | private _displayClasses: boolean = false 9 | 10 | constructor() { 11 | super() 12 | } 13 | 14 | onServicesChanges(servicesDefinitions: ServiceDefinition[]) { 15 | this._servicesDefinitions = servicesDefinitions 16 | this._onDidChangeTreeData.fire() 17 | } 18 | 19 | toggleClassDisplay(): void { 20 | this._displayClasses = !this._displayClasses 21 | this._onDidChangeTreeData.fire() 22 | } 23 | 24 | getTreeItems(): AbstractContainerTreeItem[] { 25 | let treeItems: ServiceDefinitionTreeItem[] = [] 26 | 27 | this._servicesDefinitions.forEach(serviceDefinition => { 28 | if(this.acceptSearchable(serviceDefinition)) { 29 | treeItems.push(new ServiceDefinitionTreeItem(serviceDefinition, this._displayClasses)) 30 | } 31 | }); 32 | 33 | return treeItems 34 | } 35 | 36 | protected _getSearchItemContext(): string { 37 | return 'symfony-vscode.searchItem.service' 38 | } 39 | } -------------------------------------------------------------------------------- /src/mvc/RoutesCommandController.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../symfony/ContainerStore"; 3 | import { RouteDefinitionViewProvider } from "./containerview/RouteDefinitionViewProvider"; 4 | 5 | export class RoutesCommandController { 6 | private _containerStore: ContainerStore 7 | private _routeDefinitionViewProvider: RouteDefinitionViewProvider 8 | 9 | constructor(containerStore: ContainerStore, routeDefintionViewProvider: RouteDefinitionViewProvider) { 10 | this._containerStore = containerStore 11 | this._routeDefinitionViewProvider = routeDefintionViewProvider 12 | 13 | vscode.commands.registerCommand('symfony-vscode.refreshRouteDefinitions', () => { 14 | this._containerStore.clearCacheAndRefreshRoutes() 15 | }) 16 | vscode.commands.registerCommand('symfony-vscode.togglePathDisplay', () => this._routeDefinitionViewProvider.togglePathsDisplay()) 17 | vscode.commands.registerCommand('symfony-vscode.searchForRoutes', () => { 18 | vscode.window.showInputBox({ 19 | prompt: "Criteria (e.g. \"AppBundle\", \"product\" ...)", 20 | value: this._routeDefinitionViewProvider.previousSearchCriteria 21 | }).then(criteria => { 22 | if(criteria !== undefined) { 23 | this._routeDefinitionViewProvider.setCriteria(criteria) 24 | } 25 | }) 26 | }) 27 | vscode.commands.registerCommand('symfony-vscode.clearRoutesSearch', () => this._routeDefinitionViewProvider.clearCriteria()) 28 | } 29 | } -------------------------------------------------------------------------------- /src/mvc/FileWatchController.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../symfony/ContainerStore"; 3 | import { PHPClassStore } from "../php/PHPClassStore"; 4 | 5 | export class FileWatchController { 6 | private _containerStore: ContainerStore 7 | private _phpClassStore: PHPClassStore 8 | private _disposable: vscode.Disposable 9 | private _configuration = vscode.workspace.getConfiguration("symfony-vscode") 10 | 11 | constructor(containerStore: ContainerStore, phpClassStore: PHPClassStore) { 12 | this._containerStore = containerStore 13 | this._phpClassStore = phpClassStore 14 | let fileNameRegExp = this._getFileNameRegExp() 15 | 16 | let subscriptions: vscode.Disposable[] = [] 17 | vscode.workspace.onDidSaveTextDocument(e => { 18 | if(e.fileName.match(fileNameRegExp)) { 19 | this._containerStore.clearCacheAndRefreshAll() 20 | } 21 | if(e.fileName.match(/\.php$/)) { 22 | this._phpClassStore.clearCacheAndRefresh(e.uri) 23 | } 24 | }, this, subscriptions) 25 | 26 | this._disposable = vscode.Disposable.from(...subscriptions) 27 | } 28 | 29 | protected _getFileNameRegExp(): RegExp { 30 | let extensions: string[] = this._configuration.get('fileWatchingPatterns') 31 | extensions = extensions.map((ext) => { 32 | return '.' + ext 33 | }) 34 | return new RegExp("(" + extensions.join('|') + ")$") 35 | } 36 | 37 | public dispose() { 38 | this._disposable.dispose() 39 | } 40 | } -------------------------------------------------------------------------------- /src/mvc/containerview/RouteDefinitionTreeItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { RouteDefinition } from "../../symfony/RouteDefinition"; 3 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 4 | 5 | export class RouteDefinitionTreeItem extends AbstractContainerTreeItem { 6 | private _routeDefinition: RouteDefinition 7 | private _displayPath: boolean 8 | 9 | constructor( 10 | routeDefinition: RouteDefinition, 11 | displayPath: boolean = false 12 | ) { 13 | super(displayPath ? routeDefinition.path + " [" + routeDefinition.method + "]" : routeDefinition.id, vscode.TreeItemCollapsibleState.Collapsed) 14 | this._routeDefinition = routeDefinition 15 | this._displayPath = displayPath 16 | } 17 | 18 | get tooltip() { 19 | return this._routeDefinition.path + " [" + this._routeDefinition.method + "]" 20 | } 21 | 22 | get childrenItems(): vscode.TreeItem[] { 23 | let children: vscode.TreeItem[] = [] 24 | 25 | if(this._displayPath) { 26 | children.push(new vscode.TreeItem("Id : " + this._routeDefinition.id, vscode.TreeItemCollapsibleState.None)) 27 | } else { 28 | children.push(new vscode.TreeItem("Path : " + this._routeDefinition.path, vscode.TreeItemCollapsibleState.None)) 29 | } 30 | children.push(new vscode.TreeItem("Method : " + this._routeDefinition.method, vscode.TreeItemCollapsibleState.None)) 31 | children.push(new vscode.TreeItem("Action : " + this._routeDefinition.action, vscode.TreeItemCollapsibleState.None)) 32 | 33 | return children 34 | } 35 | } -------------------------------------------------------------------------------- /src/mvc/ServicesCommandController.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../symfony/ContainerStore"; 3 | import { ServiceDefintionViewProvider } from "./containerview/ServiceDefintionViewProvider"; 4 | 5 | export class ServicesCommandController { 6 | private _containerStore: ContainerStore 7 | private _serviceDefinitionViewProvider: ServiceDefintionViewProvider 8 | 9 | constructor(containerStore: ContainerStore, serviceDefinitionViewProvider: ServiceDefintionViewProvider) { 10 | this._containerStore = containerStore 11 | this._serviceDefinitionViewProvider = serviceDefinitionViewProvider 12 | 13 | vscode.commands.registerCommand('symfony-vscode.refreshServiceDefinitions', () => { 14 | this._containerStore.clearCacheAndRefreshServices() 15 | }) 16 | vscode.commands.registerCommand('symfony-vscode.toggleClassDisplay', () => this._serviceDefinitionViewProvider.toggleClassDisplay()) 17 | vscode.commands.registerCommand('symfony-vscode.searchForServices', () => { 18 | vscode.window.showInputBox({ 19 | prompt: "Criteria (e.g. \"AppBundle\", \"acme.helper\" ...)", 20 | value: this._serviceDefinitionViewProvider.previousSearchCriteria 21 | }).then(criteria => { 22 | if(criteria !== undefined) { 23 | this._serviceDefinitionViewProvider.setCriteria(criteria) 24 | } 25 | }) 26 | }) 27 | vscode.commands.registerCommand('symfony-vscode.clearServicesSearch', () => this._serviceDefinitionViewProvider.clearCriteria()) 28 | } 29 | } -------------------------------------------------------------------------------- /src/symfony/ComposerJSON.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import * as fs from "graceful-fs" 3 | import * as stripJsonComments from "strip-json-comments"; 4 | 5 | export class ComposerJSON { 6 | 7 | public initialize(): Promise<{symfonyVersion: number, uri: vscode.Uri}> { 8 | return new Promise((resolve, reject) => { 9 | if(vscode.workspace.workspaceFolders === undefined) { 10 | reject("No workspace folder opened") 11 | } 12 | vscode.workspace.findFiles("**/composer.json").then(uris => { 13 | if(uris.length == 0) { 14 | reject("No composer.json file detected in the current workspace") 15 | } else { 16 | uris.forEach(uri => { 17 | let composerObj = JSON.parse(stripJsonComments(fs.readFileSync(uri.fsPath).toString())) 18 | if(composerObj.require !== undefined) { 19 | Object.keys(composerObj.require).forEach(key => { 20 | if(key === "symfony/symfony" || key == "symfony/framework-bundle") { 21 | resolve({ 22 | symfonyVersion: parseInt(composerObj.require[key].match(/\d/)), 23 | uri: uri 24 | }) 25 | } 26 | }) 27 | } 28 | }); 29 | reject("No composer.json file wih Symfony as dependency detected") 30 | } 31 | }) 32 | }) 33 | } 34 | } -------------------------------------------------------------------------------- /src/mvc/editing/codeaction/ServiceDocumentationCodeAction.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | import { EditingUtils } from "../EditingUtils"; 4 | 5 | export class ServiceDocumentationCodeAction extends vscode.CodeAction { 6 | constructor(document: vscode.TextDocument, range: vscode.Range, serviceDefinition: ServiceDefinition) { 7 | super("Include PHPDoc tag for Symfony service", vscode.CodeActionKind.QuickFix) 8 | 9 | let uri: vscode.Uri = document.uri 10 | let position: vscode.Position = EditingUtils.getLineStartPosition(document, range.start.line) 11 | let newText = this._getTextToInsert(document, position, serviceDefinition) 12 | 13 | let edit = new vscode.WorkspaceEdit() 14 | edit.insert(uri, position, newText) 15 | this.edit = edit 16 | } 17 | 18 | private _getTextToInsert(document: vscode.TextDocument, position: vscode.Position, serviceDefinition: ServiceDefinition) { 19 | let variableName: string = "" 20 | let textLine: string = document.lineAt(position.line).text 21 | let variableMatching = textLine.match(/^[ |\t]*(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/) 22 | if(variableMatching) { 23 | variableName = variableMatching[0].trim() 24 | } 25 | 26 | let indentationSubstring: string = document.getText(new vscode.Range( 27 | new vscode.Position(position.line, 0), position 28 | )) 29 | let textToInsert: string = "/** @var \\" + serviceDefinition.className + " " + variableName + " */\n" + indentationSubstring 30 | 31 | return textToInsert 32 | } 33 | } -------------------------------------------------------------------------------- /src/php/PHPClass.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPUse } from "./PHPUse"; 3 | 4 | export class PHPClass { 5 | public className: string 6 | public documentUri: vscode.Uri 7 | public methods: string[] = [] 8 | public classPosition: vscode.Position 9 | public uses: PHPUse[] = [] 10 | protected _classNameArray: string[] = [] 11 | 12 | public constructor(className: string, documentUri: vscode.Uri) { 13 | this.className = className 14 | this.documentUri = documentUri 15 | this._classNameArray = this.className.split('\\') 16 | } 17 | 18 | public addMethod(method: string) { 19 | this.methods.push(method) 20 | } 21 | 22 | public isInNamespaceOf(namespace: string): boolean { 23 | return this._classNameArray.indexOf(namespace) != -1 24 | } 25 | 26 | public isController(): boolean { 27 | return this.isInNamespaceOf('Controller') 28 | } 29 | 30 | get shortClassName(): string { 31 | return this._classNameArray[this._classNameArray.length - 1] 32 | } 33 | 34 | static fromJSON(jsonPhpClass: PHPClass): PHPClass { 35 | let uri = vscode.Uri.file(jsonPhpClass.documentUri.fsPath) 36 | let position = new vscode.Position(jsonPhpClass.classPosition.line, jsonPhpClass.classPosition.character) 37 | let phpClass = new PHPClass(jsonPhpClass.className, uri) 38 | phpClass.classPosition = position 39 | jsonPhpClass.methods.forEach(method => { 40 | phpClass.addMethod(method) 41 | }) 42 | jsonPhpClass.uses.forEach(use => { 43 | phpClass.uses.push(new PHPUse(use.className, use.alias)) 44 | }) 45 | 46 | return phpClass 47 | } 48 | } -------------------------------------------------------------------------------- /src/mvc/containerview/ServiceDefinitionTreeItem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ServiceDefinition } from "../../symfony/ServiceDefinition"; 3 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 4 | 5 | export class ServiceDefinitionTreeItem extends AbstractContainerTreeItem { 6 | public serviceDefinition: ServiceDefinition 7 | private _displayClass: boolean 8 | 9 | constructor( 10 | serviceDefinition: ServiceDefinition, 11 | displayClass: boolean = false 12 | ) { 13 | super(displayClass ? serviceDefinition.className : serviceDefinition.id, vscode.TreeItemCollapsibleState.Collapsed) 14 | this.serviceDefinition = serviceDefinition 15 | this._displayClass = displayClass 16 | } 17 | 18 | get tooltip(): string { 19 | return this.serviceDefinition.className 20 | } 21 | 22 | get childrenItems(): vscode.TreeItem[] { 23 | let children: vscode.TreeItem[] = [] 24 | 25 | if(this._displayClass) { 26 | children.push(new vscode.TreeItem("Id : " + this.serviceDefinition.id, vscode.TreeItemCollapsibleState.None)) 27 | } 28 | if(this.serviceDefinition.alias !== null) { 29 | children.push(new vscode.TreeItem("Alias : " + this.serviceDefinition.alias, vscode.TreeItemCollapsibleState.None)) 30 | } 31 | if(!this._displayClass) { 32 | children.push(new vscode.TreeItem("Class : " + this.serviceDefinition.className, vscode.TreeItemCollapsibleState.None)) 33 | } 34 | children.push(new vscode.TreeItem("Is public : " + (this.serviceDefinition.public ? "true" : "false"), vscode.TreeItemCollapsibleState.None)) 35 | 36 | return children 37 | } 38 | 39 | get contextValue(): string { 40 | return 'symfony-vscode.service' 41 | } 42 | } -------------------------------------------------------------------------------- /src/mvc/editing/definition/AbstractServiceDefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClassStore } from "../../../php/PHPClassStore"; 3 | import { EditingUtils } from "../EditingUtils"; 4 | import { ContainerStore } from "../../../symfony/ContainerStore"; 5 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 6 | 7 | export abstract class AbstractServiceDefinitionProvider implements vscode.DefinitionProvider { 8 | protected _containerStore: ContainerStore 9 | protected _phpClassStore: PHPClassStore 10 | 11 | constructor(containerStore: ContainerStore, phpClassStore: PHPClassStore) { 12 | this._containerStore = containerStore 13 | this._phpClassStore = phpClassStore 14 | } 15 | 16 | provideDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { 17 | let wordRange = EditingUtils.getWordRange(document, position) 18 | let hoveredWord = document.getText(wordRange) 19 | let serviceDefinition = this._containerStore.serviceDefinitionList.find(service => { 20 | return this.acceptServiceDefinition(hoveredWord, service) 21 | }); 22 | if(serviceDefinition !== undefined) { 23 | return this.getLocationOfService(serviceDefinition) 24 | } else { 25 | return null 26 | } 27 | } 28 | 29 | getLocationOfService(serviceDefinition: ServiceDefinition): vscode.Location { 30 | let phpClass = this._phpClassStore.getPhpClass(serviceDefinition.className) 31 | if(phpClass) { 32 | return new vscode.Location(phpClass.documentUri, phpClass.classPosition) 33 | } else { 34 | return null 35 | } 36 | } 37 | 38 | abstract acceptServiceDefinition(hoveredWord: string, serviceDefinition: ServiceDefinition): boolean 39 | } -------------------------------------------------------------------------------- /src/mvc/editing/autocomplete/ConfigurationFileProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContainerStore } from "../../../symfony/ContainerStore"; 3 | import { ConfigurationFileServiceCompletionItem } from "./ConfigurationFileServiceCompletionItem"; 4 | import { ParameterCompletionItem } from "./ParameterCompletionItem"; 5 | import { EditingUtils } from "../EditingUtils"; 6 | 7 | export class ConfigurationFileProvider implements vscode.CompletionItemProvider { 8 | 9 | private _containerStore: ContainerStore 10 | 11 | constructor(containerStore: ContainerStore) { 12 | this._containerStore = containerStore 13 | } 14 | 15 | provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.CompletionItem[] { 16 | let result: vscode.CompletionItem[] = [] 17 | let serviceDefinitions = this._containerStore.serviceDefinitionList 18 | let parameters = this._containerStore.parameterList 19 | let wordRange = EditingUtils.getWordRange(document, position) 20 | let previousCharacter = document.getText(new vscode.Range(wordRange.start.translate(0, -1), wordRange.start)) 21 | 22 | if (previousCharacter === "@") { 23 | serviceDefinitions.forEach(serviceDefinition => { 24 | if (!serviceDefinition.isServiceIdAClassName()) { 25 | let item = new ConfigurationFileServiceCompletionItem(serviceDefinition) 26 | result.push(item) 27 | } 28 | }); 29 | } else { 30 | serviceDefinitions.forEach(serviceDefinition => { 31 | let item = new ConfigurationFileServiceCompletionItem(serviceDefinition) 32 | result.push(item) 33 | }); 34 | parameters.forEach(parameter => { 35 | let item = new ParameterCompletionItem(parameter) 36 | result.push(item) 37 | }) 38 | } 39 | return result 40 | } 41 | } -------------------------------------------------------------------------------- /src/php/PromiseUtils.ts: -------------------------------------------------------------------------------- 1 | export class PromiseUtils { 2 | /** 3 | * Taken from https://stackoverflow.com/questions/38385419/throttle-amount-of-promises-open-at-a-given-time 4 | * Performs a list of callable actions (promise factories) so that only a limited 5 | * number of promises are pending at any given time. 6 | * 7 | * @param listOfCallableActions An array of callable functions, which should 8 | * return promises. 9 | * @param limit The maximum number of promises to have pending at once. 10 | * @returns A Promise that resolves to the full list of values when everything is done. 11 | */ 12 | static throttleActions(listOfCallableActions, limit): Promise { 13 | // We'll need to store which is the next promise in the list. 14 | let i = 0; 15 | let resultArray = new Array(listOfCallableActions.length); 16 | 17 | // Now define what happens when any of the actions completes. Javascript is 18 | // (mostly) single-threaded, so only one completion handler will call at a 19 | // given time. Because we return doNextAction, the Promise chain continues as 20 | // long as there's an action left in the list. 21 | function doNextAction() { 22 | if (i < listOfCallableActions.length) { 23 | // Save the current value of i, so we can put the result in the right place 24 | let actionIndex = i++; 25 | let nextAction = listOfCallableActions[actionIndex]; 26 | return Promise.resolve(nextAction()) 27 | .then(result => { // Save results to the correct array index. 28 | resultArray[actionIndex] = result; 29 | return; 30 | }).then(doNextAction); 31 | } 32 | } 33 | 34 | // Now start up the original number of promises. 35 | // i advances in calls to doNextAction. 36 | let listOfPromises = []; 37 | while (i < limit && i < listOfCallableActions.length) { 38 | listOfPromises.push(doNextAction()); 39 | } 40 | return Promise.all(listOfPromises).then(() => resultArray); 41 | } 42 | } -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | * This folder contains all of the files necessary for your extension. 5 | * `package.json` - this is the manifest file in which you declare your extension and command. 6 | The sample plugin registers a command and defines its title and command name. With this information 7 | VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | The file exports one function, `activate`, which is called the very first time your extension is 10 | activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 11 | We pass the function containing the implementation of the command as the second parameter to 12 | `registerCommand`. 13 | 14 | ## Get up and running straight away 15 | * Press `F5` to open a new window with your extension loaded. 16 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 17 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 18 | * Find output from your extension in the debug console. 19 | 20 | ## Make changes 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | * You can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`. 26 | 27 | ## Run tests 28 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests`. 29 | * Press `F5` to run the tests in a new window with your extension loaded. 30 | * See the output of the test result in the debug console. 31 | * Make changes to `test/extension.test.ts` or create new test files inside the `test` folder. 32 | * By convention, the test runner will only consider files matching the name pattern `**.test.ts`. 33 | * You can create folders inside the `test` folder to structure your tests any way you want. 34 | -------------------------------------------------------------------------------- /src/symfony/provider/CacheContainerProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ContainerProviderInterface } from "./ContainerProviderInterface"; 3 | import { RouteDefinition } from "../RouteDefinition"; 4 | import { Parameter } from "../Parameter"; 5 | import { ServiceDefinition } from "../ServiceDefinition"; 6 | import { ContainerCacheManager } from "../ContainerCacheManager"; 7 | 8 | export class CacheContainerProvider implements ContainerProviderInterface { 9 | protected _cacheManager: ContainerCacheManager 10 | 11 | protected static NO_SERVICES_IN_CACHE = "No services in cache" 12 | protected static NO_ROUTES_IN_CACHE = "No routes in cache" 13 | protected static NO_PARAMETERS_IN_CACHE = "No parameters in cache" 14 | 15 | constructor(cacheManager: ContainerCacheManager) { 16 | this._cacheManager = cacheManager 17 | } 18 | 19 | canProvideServiceDefinitions(): boolean { 20 | return this._cacheManager.hasCachedServices() 21 | } 22 | canProvideRouteDefinitions(): boolean { 23 | return this._cacheManager.hasCachedRoutes() 24 | } 25 | canProvideParameters(): boolean { 26 | return this._cacheManager.hasCachedParameters() 27 | } 28 | 29 | provideServiceDefinitions(): Promise { 30 | return new Promise((resolve, reject) => { 31 | if(this._cacheManager.hasCachedServices()) { 32 | resolve(this._cacheManager.getServices()) 33 | } else { 34 | reject(CacheContainerProvider.NO_SERVICES_IN_CACHE) 35 | } 36 | }) 37 | } 38 | provideRouteDefinitions(): Promise { 39 | return new Promise((resolve, reject) => { 40 | if(this._cacheManager.hasCachedRoutes()) { 41 | resolve(this._cacheManager.getRoutes()) 42 | } else { 43 | reject(CacheContainerProvider.NO_ROUTES_IN_CACHE) 44 | } 45 | }) 46 | } 47 | provideParameters(): Promise { 48 | return new Promise((resolve, reject) => { 49 | if(this._cacheManager.hasCachedParameters()) { 50 | resolve(this._cacheManager.getParameters()) 51 | } else { 52 | reject(CacheContainerProvider.NO_PARAMETERS_IN_CACHE) 53 | } 54 | }) 55 | } 56 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Creating issues 4 | 5 | You don't have to code to contribute to this project ! 6 | 7 | Creating issues is the way to go if you have something in mind that can help Symfony support on VSCode. 8 | 9 | The philosophy behind the extension is : 10 | * The extension must work without any further configuration, juste by creating a simple Symfony 2+ project, following instructions on the official documentation. 11 | * Even if features such as autocomplete can be hard to implement, data visualization, quick code access or even an SVG on a button can be a plus. 12 | * The extension must have enough settings to work on most common work environments (for example : Dockerized Symfony projects). 13 | 14 | This means that there are 2 types of issues : 15 | * The extension is not working (correctly or not at all) in your work environment. Please create an issue describing your OS, VSCode version, Symfony version, other installed extensions and the tool you'are working with (FPM, Apache PHP worker, Docker, Vagrant ...). 16 | * The extension lacks a feature that would improve productivity. Please create an issue with at least a minimum Symfony version. 17 | 18 | Note that if your Symfony app is not running on a conventionnal installation (Docker, Vagrant ...) and the extension is working with some settings tweak, you can contribute [this file](ENVIRONMENTS.md) to help other users to set up their IDE. 19 | 20 | ## Developpement 21 | 22 | ### Prerequisites 23 | 24 | To contribute to this extension, you must have the following tools : 25 | * Git (obviously) 26 | * NodeJS (>= 8.11) 27 | * npm (>= 5.6) 28 | 29 | If you want to have a better understanding of extension authoring, [the documentation is your first stop](https://code.visualstudio.com/api). 30 | 31 | ### Installation 32 | 33 | ``` 34 | git clone https://github.com/TheNouillet/symfony-vscode.git 35 | npm install --no-save 36 | npm run compile 37 | ``` 38 | 39 | ### Watching 40 | 41 | For developpement, it's easier to watch the files with : 42 | ``` 43 | npm run watch 44 | ``` 45 | 46 | ### Creating the VSIX file 47 | 48 | VSIX file allows you to install the extension on VSCode. For this, you have to install the `vsce` utility : 49 | ``` 50 | npm install -g vsce 51 | ``` 52 | 53 | To create a VSIX file, you can use this command : 54 | ``` 55 | vsce package 56 | ``` 57 | 58 | Make sure that your dependencies are up-to-date before packaging the extension. -------------------------------------------------------------------------------- /src/mvc/editing/codeaction/ServiceDocumentationCodeActionProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "../../../symfony/ServiceDefinition"; 3 | import { AbstractContainerStoreListener } from "../../../symfony/AbstractContainerStoreListener"; 4 | import { EditingUtils } from "../EditingUtils"; 5 | import { ServiceDocumentationCodeAction } from "./ServiceDocumentationCodeAction"; 6 | import { PHPClassStore } from "../../../php/PHPClassStore"; 7 | 8 | export class ServiceDocumentationCodeActionProvider extends AbstractContainerStoreListener implements vscode.CodeActionProvider { 9 | private _servicesDefinitionsList: ServiceDefinition[] = [] 10 | private _phpClassStore: PHPClassStore 11 | 12 | constructor(phpClassStore: PHPClassStore) { 13 | super() 14 | this._phpClassStore = phpClassStore 15 | } 16 | 17 | onServicesChanges(servicesDefinitionList: ServiceDefinition[]) { 18 | this._servicesDefinitionsList = servicesDefinitionList 19 | } 20 | 21 | provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, 22 | context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.ProviderResult<(vscode.Command | vscode.CodeAction)[]> { 23 | 24 | if(range instanceof vscode.Selection) { 25 | let potentialServiceRange = EditingUtils.getWordRange(document, range.active) 26 | let potentialServiceName = document.getText(potentialServiceRange) 27 | let use = this._phpClassStore.getUsesForUri(document.uri).find(use => { 28 | return potentialServiceName == use.shortName 29 | }) 30 | let serviceDefinition = this._servicesDefinitionsList.find(serviceDefinition => { 31 | if(potentialServiceName === serviceDefinition.id) { 32 | return true 33 | } else if (potentialServiceName === serviceDefinition.className && potentialServiceName !== "") { 34 | return true 35 | } else if (use !== undefined && use.className === serviceDefinition.className){ 36 | return true 37 | } else if (use !== undefined && use.className === serviceDefinition.id){ 38 | return true 39 | } 40 | return false 41 | }); 42 | if(serviceDefinition !== undefined) { 43 | return [new ServiceDocumentationCodeAction(document, potentialServiceRange, serviceDefinition)] 44 | } 45 | return null 46 | } 47 | return null 48 | } 49 | } -------------------------------------------------------------------------------- /src/symfony/ContainerCacheManager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "./ServiceDefinition"; 3 | import { RouteDefinition } from "./RouteDefinition"; 4 | import { Parameter } from "./Parameter"; 5 | 6 | export class ContainerCacheManager { 7 | 8 | protected _memento: vscode.Memento 9 | 10 | public static SERVICES_CACHE_KEY = "cached_container_store_services" 11 | public static ROUTES_CACHE_KEY = "cached_container_store_routes" 12 | public static PARAMETERS_CACHE_KEY = "cached_container_store_parameters" 13 | 14 | constructor(memento: vscode.Memento) { 15 | this._memento = memento 16 | } 17 | 18 | hasCachedServices() : boolean { 19 | return this._memento.get(ContainerCacheManager.SERVICES_CACHE_KEY) !== undefined 20 | } 21 | 22 | hasCachedRoutes() : boolean { 23 | return this._memento.get(ContainerCacheManager.ROUTES_CACHE_KEY) !== undefined 24 | } 25 | 26 | hasCachedParameters() : boolean { 27 | return this._memento.get(ContainerCacheManager.PARAMETERS_CACHE_KEY) !== undefined 28 | } 29 | 30 | getServices(): ServiceDefinition[] { 31 | return this._memento.get(ContainerCacheManager.SERVICES_CACHE_KEY).map(jsonServiceDefinition => { 32 | return ServiceDefinition.fromJSON(jsonServiceDefinition) 33 | }) 34 | } 35 | 36 | getRoutes(): RouteDefinition[] { 37 | return this._memento.get(ContainerCacheManager.ROUTES_CACHE_KEY).map(jsonRouteDefinition => { 38 | return RouteDefinition.fromJSON(jsonRouteDefinition) 39 | }) 40 | } 41 | 42 | getParameters(): Parameter[] { 43 | return this._memento.get(ContainerCacheManager.PARAMETERS_CACHE_KEY).map(jsonParameter => { 44 | return Parameter.fromJSON(jsonParameter) 45 | }) 46 | } 47 | 48 | setServices(servicesDefinitions: ServiceDefinition[]): Thenable { 49 | return this._memento.update(ContainerCacheManager.SERVICES_CACHE_KEY, servicesDefinitions) 50 | } 51 | 52 | setRoutes(routesDefinitions: RouteDefinition[]): Thenable { 53 | return this._memento.update(ContainerCacheManager.ROUTES_CACHE_KEY, routesDefinitions) 54 | } 55 | 56 | setParameters(parameters: Parameter[]): Thenable { 57 | return this._memento.update(ContainerCacheManager.PARAMETERS_CACHE_KEY, parameters) 58 | } 59 | 60 | clearServices(): Thenable { 61 | return this._memento.update(ContainerCacheManager.SERVICES_CACHE_KEY, undefined) 62 | } 63 | 64 | clearRoutes(): Thenable { 65 | return this._memento.update(ContainerCacheManager.ROUTES_CACHE_KEY, undefined) 66 | } 67 | 68 | clearParameters(): Thenable { 69 | return this._memento.update(ContainerCacheManager.PARAMETERS_CACHE_KEY, undefined) 70 | } 71 | } -------------------------------------------------------------------------------- /media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 1.0.2 [02-27-2019] 4 | 5 | * Fixed the extension not starting at all 6 | 7 | ## 1.0.1 [02-26-2019] 8 | 9 | * [#31](https://github.com/TheNouillet/symfony-vscode/pull/31) Fix parsing of files not working on Windows (thank you [smertelny](https://github.com/smertelny) !) 10 | * Fix of command console failure when the console output has comments in it 11 | * Fix PHP parsing not working 12 | 13 | ## 1.0.0 [02-25-2019] 14 | 15 | * Added a "Include PHPDoc tag for Symfony service" code action 16 | * This code action allows you to include a `@var` PHPDoc tag on the line above a recognized service name 17 | * This acts as a way to provide autocompletion of a service obtained via a ContainerInterface object (such as `$this->get('logger')` in a controller for example) 18 | * Added a "Go to definition" on services in YAML, XML and PHP files 19 | * PHP files are now parsed 20 | * Container elements and PHP files are now cached 21 | * Startup is now way faster on existing projects 22 | * Commands and file modification invalidates caches. 23 | * Console command calls are now asynchronous 24 | * The extension usage with Docker or others shell-based environments has been changed, via the addition of `shellExecutable` and `shellCommand` parameters. 25 | * Added a search functionnality on services, routes and parameters views. 26 | * Added the `parametersFilters` setting to filter out parameters, such as classes. 27 | * Added the `routesFilters` setting to filter out routes, such as Assetic routes. 28 | * Let know in the repository issues if default filters aren't pertinent enough ! I made them according to my work habbits, but each project is different. 29 | * Errors messages now display only once when refreshing services, routes and parameters (i.e. at extension startup or configuration file modification) 30 | 31 | ## 0.0.3 [08-06-2018] 32 | 33 | * Added aucompletion of public services in PHP files 34 | * Added the parameter view to display parameters of the Symfony container. 35 | * Added aucompletion of parameters in YAML files 36 | * Added class name on hover on a known service id in YAML and PHP files. 37 | * Added the `enableFileWatching` setting to enable or disable file watching. 38 | * Added the `servicesFilters` to improve autocompletion pertinence. 39 | * Added the "Toggle class/id display for services" command to switch between Id and class name display on the services view. 40 | * Added the "Toggle path/id display for routes" command to switch between Id and paths display on the routes view. 41 | * These two commands are available via buttons on the side of the two views. 42 | 43 | ## 0.0.2 [08-04-2018] 44 | 45 | * Added autocompletion of services in YAML files 46 | * Added the `detectCwd` setting to help with Symfony projects on Docker 47 | * Added more logging of errors 48 | * Added the `showConsoleErrors` setting to hide errors from the Symfony console 49 | * Added progress indicator on the status bar 50 | * Added buttons to the side of TreeViews to re-sync the extension and Symfony. 51 | * Added class name for services aliases 52 | 53 | ## 0.0.1 54 | 55 | Initial preview release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symfony for VSCode 2 | 3 | This extension aims to help developing Symfony2+ projects, by providing basic autocompletion and visualization of the Symfony container. 4 | 5 | ![Autocomplete](media/autocomplete.gif) 6 | 7 | ## Features 8 | 9 | This extension provides the following features : 10 | * Autocompletion in YML and XML files of services and parameters 11 | * Hover details on services and parameters name 12 | * Go to implementation of a service 13 | * A custom view to visualize the current project container, with services, routes and parameters 14 | 15 | ![Debug view](media/view.gif) 16 | 17 | ## How does it works ? 18 | 19 | To detect Symfony projects, this extension rely on `composer.json` files with `symfony/symfony` as one of its dependencies. 20 | 21 | The `composer.json` file is supposed to be at the root of your Symfony project. 22 | 23 | When the project is detected, it simply uses the `debug:container` and `debug:router` console commands to hydrate the views and autocompletions. 24 | 25 | ## Extension settings 26 | 27 | Here are the settings that can be overridden for convenience : 28 | * `phpExecutablePath`: Path to the PHP executable. This path is ignored if the `shellExecutable` parameter is different than false (default value : `/usr/bin/php`). 29 | * `shellExecutable`: The shell executable path. If differant that false, console commands will be called via shell instead of just calling the PHP executable. Useful for particular setup, such as Dockerized projects (default value : `false`). 30 | * `shellCommand`: The shell command. Only used when calling the shell to do console commands. Useful for particular setup, such as Dockerized projects (default value : `false`). 31 | * `consolePath`: Path to the Symfony console, relative to the root directeory. If null, the extension try to guess the path with the Symfony version from the composer.json file (default value : `null`). 32 | * `showConsoleErrors`: If false, the extension doesn't show error messages caused by compilation errors (default value : `true`). 33 | * `enableFileWatching`: If false, the extension refresh automatically when a YAML file is modified (default value : `true`). 34 | * `fileWatchingPatterns`: Files with one of these extensions will trigger a container refresh on save. By default, watches only `*.yml` and `*.xml` files. 35 | * `servicesFilters`, `routesFilters` and `parametersFilters` : Filters out container elements. Filtered elements doesn't show in the Symfony view, nor does they appear in autocompletion. 36 | 37 | ## Various environments 38 | 39 | If your Symfony app is not running on a conventional installation (for example, you are running a Symfony app on a Docker container), you can find different configuration recipes [here](ENVIRONMENTS.md). 40 | 41 | ## Contribution 42 | 43 | If you want to contribute to this extension, everything you want to know is [here](CONTRIBUTING.md). 44 | 45 | ## Release Notes 46 | 47 | See [the changelog](CHANGELOG.md) for releases notes. 48 | 49 | ## Acknowledgments 50 | 51 | Icons from www.flaticon.com, by : 52 | * [Chanut](https://www.flaticon.com/authors/chanut) 53 | * [SimpleIcon](https://www.flaticon.com/authors/simpleicon) 54 | -------------------------------------------------------------------------------- /src/mvc/containerview/AbstractContainerViewProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { AbstractContainerStoreListener } from "../../symfony/AbstractContainerStoreListener"; 3 | import { Searchable } from "../../symfony/Searchable"; 4 | import { AbstractContainerTreeItem } from "./AbstractContainerTreeItem"; 5 | 6 | export abstract class AbstractContainerViewProvider extends AbstractContainerStoreListener implements vscode.TreeDataProvider { 7 | 8 | protected _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 9 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 10 | protected _searchCriteria: string | boolean = false 11 | protected _previousSearchCriteria: string = null 12 | 13 | setCriteria(criteria: string | boolean): void { 14 | this._searchCriteria = criteria 15 | if(criteria) { 16 | this._previousSearchCriteria = criteria 17 | } 18 | this._onDidChangeTreeData.fire() 19 | } 20 | 21 | clearCriteria(): void { 22 | this.setCriteria(false) 23 | } 24 | 25 | acceptSearchable(searchable: Searchable): boolean { 26 | return (false === this._searchCriteria || searchable.acceptSearchCriteria(this._searchCriteria.toString()) > 0) 27 | } 28 | 29 | getTreeItem(element: vscode.TreeItem): vscode.TreeItem | Thenable { 30 | return element 31 | } 32 | 33 | protected _getSearchItemContext(): string { 34 | return null 35 | } 36 | 37 | getChildren(element?: vscode.TreeItem): vscode.ProviderResult { 38 | return new Promise(resolve => { 39 | if (!element) { 40 | let result: vscode.TreeItem[] = [] 41 | let containerTreeItems: AbstractContainerTreeItem[] = this.getTreeItems() 42 | containerTreeItems.sort((a, b) => { 43 | if (a.label < b.label) { 44 | return -1 45 | } 46 | if (a.label > b.label) { 47 | return 1 48 | } 49 | return 0 50 | }) 51 | 52 | if (false !== this._searchCriteria) { 53 | let searchTreeItem : vscode.TreeItem = new vscode.TreeItem("Searching for : " + this._searchCriteria) 54 | if(this._getSearchItemContext()) { 55 | searchTreeItem.contextValue = this._getSearchItemContext() 56 | } 57 | result.push(searchTreeItem) 58 | } 59 | resolve(result.concat(containerTreeItems)) 60 | } else { 61 | if (element instanceof AbstractContainerTreeItem) { 62 | resolve(element.childrenItems) 63 | } else { 64 | resolve([]) 65 | } 66 | } 67 | }) 68 | } 69 | 70 | abstract getTreeItems(): AbstractContainerTreeItem[] 71 | 72 | get previousSearchCriteria(): string { 73 | return this._previousSearchCriteria 74 | } 75 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // The module 'vscode' contains the VS Code extensibility API 3 | // Import the module and reference it with the alias vscode in your code below 4 | import * as vscode from 'vscode'; 5 | import { ServiceDefintionViewProvider } from './mvc/containerview/ServiceDefintionViewProvider'; 6 | import { ContainerStore } from './symfony/ContainerStore'; 7 | import { RouteDefinitionViewProvider } from './mvc/containerview/RouteDefinitionViewProvider'; 8 | import { FileWatchController } from './mvc/FileWatchController'; 9 | import { AutocompleteController } from './mvc/AutocompleteController'; 10 | import { ParameterViewProvider } from './mvc/containerview/ParameterViewProvider'; 11 | import { ServiceDocumentationCodeActionProvider } from './mvc/editing/codeaction/ServiceDocumentationCodeActionProvider'; 12 | import { ServicesCommandController } from './mvc/ServicesCommandController'; 13 | import { RoutesCommandController } from './mvc/RoutesCommandController'; 14 | import { ParametersCommandController } from './mvc/ParametersCommandController'; 15 | import { PHPClassStore } from './php/PHPClassStore'; 16 | import { PHPClassesController } from './mvc/PHPClassesController'; 17 | import { PHPClassCacheManager } from './php/PHPClassCacheManager'; 18 | import { ContainerCacheManager } from './symfony/ContainerCacheManager'; 19 | 20 | // this method is called when your extension is activated 21 | // your extension is activated the very first time the command is executed 22 | export function activate(context: vscode.ExtensionContext) { 23 | 24 | let phpClassCacheManager = new PHPClassCacheManager(context.workspaceState) 25 | let containerCacheManager = new ContainerCacheManager(context.workspaceState) 26 | let containerStore = new ContainerStore(containerCacheManager) 27 | let phpClassStore = new PHPClassStore(phpClassCacheManager) 28 | const serviceDefinitionViewProvider = new ServiceDefintionViewProvider() 29 | const routeDefinitionViewProvider = new RouteDefinitionViewProvider() 30 | const parameterViewProvider = new ParameterViewProvider() 31 | containerStore.subscribeListerner(serviceDefinitionViewProvider) 32 | containerStore.subscribeListerner(routeDefinitionViewProvider) 33 | containerStore.subscribeListerner(parameterViewProvider) 34 | 35 | vscode.commands.registerCommand('symfony-vscode.refreshContainer', () => { 36 | containerStore.clearCacheAndRefreshAll() 37 | }) 38 | 39 | vscode.window.registerTreeDataProvider("serviceDefinitionsView", serviceDefinitionViewProvider) 40 | let servicesCommandController = new ServicesCommandController(containerStore, serviceDefinitionViewProvider) 41 | 42 | vscode.window.registerTreeDataProvider("routeDefinitionsView", routeDefinitionViewProvider) 43 | let routesCommandController = new RoutesCommandController(containerStore, routeDefinitionViewProvider) 44 | 45 | vscode.window.registerTreeDataProvider("parametersView", parameterViewProvider) 46 | let parametersCommandController = new ParametersCommandController(containerStore, parameterViewProvider) 47 | 48 | if(vscode.workspace.getConfiguration("symfony-vscode").get("enableFileWatching")) { 49 | let fileWatchController = new FileWatchController(containerStore, phpClassStore) 50 | context.subscriptions.push(fileWatchController) 51 | } 52 | 53 | let autocompleteController = new AutocompleteController(containerStore, phpClassStore) 54 | context.subscriptions.push(autocompleteController) 55 | 56 | let serviceDocCodeActionProvider = new ServiceDocumentationCodeActionProvider(phpClassStore) 57 | containerStore.subscribeListerner(serviceDocCodeActionProvider) 58 | vscode.languages.registerCodeActionsProvider({scheme: "file", language: "php"}, serviceDocCodeActionProvider) 59 | 60 | let phpClassesController = new PHPClassesController(phpClassStore) 61 | 62 | containerStore.refreshAll().then(() => { 63 | phpClassStore.refreshAll() 64 | }) 65 | } 66 | 67 | // this method is called when your extension is deactivated 68 | export function deactivate() { 69 | } -------------------------------------------------------------------------------- /src/php/PHPClassStore.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClass } from "./PHPClass"; 3 | import { PHPClassProviderInterface } from "./provider/PHPClassProviderInterface"; 4 | import { ParserPHPClassProvider } from "./provider/ParserPHPClassProvider"; 5 | import { CachePHPClassProvider } from "./provider/CachePHPClassProvider"; 6 | import { PHPClassCacheManager } from "./PHPClassCacheManager"; 7 | import { PHPUse } from "./PHPUse"; 8 | 9 | export class PHPClassStore { 10 | protected _cacheManager: PHPClassCacheManager 11 | protected _phpClassProviders: PHPClassProviderInterface[] = [] 12 | protected _phpClassesIndex: Map = new Map() 13 | protected _phpUsesIndex: Map = new Map() 14 | 15 | private static PHP_CLASS_FETCH_MESSAGE = "Fetching PHP classes..." 16 | private static PHP_CLASS_NO_PROVIDER = "Cannot retrieve PHP classes at the moment" 17 | 18 | constructor(cacheManager: PHPClassCacheManager) { 19 | this._cacheManager = cacheManager 20 | this._phpClassProviders.push(new CachePHPClassProvider(cacheManager)) 21 | this._phpClassProviders.push(new ParserPHPClassProvider()) 22 | } 23 | 24 | refreshAll(): void { 25 | this._phpClassesIndex.clear() 26 | let hasValidProvider = this._phpClassProviders.some(provider => { 27 | if(provider.canUpdateAllUris()) { 28 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: PHPClassStore.PHP_CLASS_FETCH_MESSAGE }, (progress, token) => { 29 | return provider.updateAllUris().then(phpClasses => { 30 | phpClasses.forEach(phpClass => { 31 | this._phpClassesIndex.set(phpClass.className, phpClass) 32 | if(phpClass.uses.length > 0) { 33 | this._phpUsesIndex.set(phpClass.documentUri.fsPath, phpClass.uses) 34 | } 35 | }) 36 | this._cacheManager.set(phpClasses) 37 | }).catch(reason => { 38 | vscode.window.showErrorMessage(reason) 39 | }) 40 | }) 41 | return true 42 | } else { 43 | return false 44 | } 45 | }) 46 | if(!hasValidProvider) { 47 | vscode.window.showErrorMessage(PHPClassStore.PHP_CLASS_NO_PROVIDER) 48 | } 49 | } 50 | 51 | clearCacheAndRefreshAll(): void { 52 | this._cacheManager.clear().then(() => { 53 | this.refreshAll() 54 | }) 55 | } 56 | 57 | refresh(uri: vscode.Uri): void { 58 | let hasValidProvider = this._phpClassProviders.some(provider => { 59 | if(provider.canUpdateUri(uri)) { 60 | provider.updateUri(uri).then(phpClasses => { 61 | phpClasses.forEach(phpClass => { 62 | this._phpClassesIndex.set(phpClass.className, phpClass) 63 | if(phpClass.uses.length > 0) { 64 | this._phpUsesIndex.set(phpClass.documentUri.fsPath, phpClass.uses) 65 | } 66 | }) 67 | }) 68 | let phpClasses = Array.from(this._phpClassesIndex.values()) 69 | this._cacheManager.set(phpClasses) 70 | return true 71 | } else { 72 | return false 73 | } 74 | }) 75 | if(!hasValidProvider) { 76 | vscode.window.showErrorMessage(PHPClassStore.PHP_CLASS_NO_PROVIDER) 77 | } 78 | } 79 | 80 | clearCacheAndRefresh(uri: vscode.Uri): void { 81 | this._cacheManager.clearClassByUri(uri).then(() => { 82 | this.refresh(uri) 83 | }) 84 | } 85 | 86 | getPhpClass(className: string): PHPClass { 87 | return this._phpClassesIndex.get(className) 88 | } 89 | 90 | getUsesForUri(uri: vscode.Uri): PHPUse[] { 91 | return this._phpUsesIndex.get(uri.fsPath) 92 | } 93 | } -------------------------------------------------------------------------------- /src/mvc/AutocompleteController.ts: -------------------------------------------------------------------------------- 1 | import { ContainerStore } from "../symfony/ContainerStore"; 2 | import * as vscode from "vscode" 3 | import { ConfigurationFileProvider } from "./editing/autocomplete/ConfigurationFileProvider"; 4 | import { PHPServiceProvider } from "./editing/autocomplete/PHPServiceProvider"; 5 | import { ContainerHoverProvider } from "./editing/hover/ContainerHoverProvider"; 6 | import { PHPClassStore } from "../php/PHPClassStore"; 7 | import { ServiceDefinitionTreeItem } from "./containerview/ServiceDefinitionTreeItem"; 8 | import { ConfigurationFileServiceDefinitionProvider } from "./editing/definition/ConfigurationFileServiceDefinitionProvider"; 9 | import { PHPServiceDefinitionProvider } from "./editing/definition/PHPServiceDefinitionProvider"; 10 | import { ServiceQuickPickItem } from "./editing/quickpick/ServiceQuickPickItem"; 11 | import { ServiceDefinition } from "../symfony/ServiceDefinition"; 12 | import { AbstractServiceDefinitionProvider } from "./editing/definition/AbstractServiceDefinitionProvider"; 13 | 14 | export class AutocompleteController { 15 | private _disposable: vscode.Disposable 16 | 17 | constructor(containerStore: ContainerStore, phpClassStore: PHPClassStore) { 18 | let configurationFileProvider = new ConfigurationFileProvider(containerStore) 19 | let phpServiceProvider = new PHPServiceProvider(containerStore) 20 | let hoverProvider = new ContainerHoverProvider(containerStore) 21 | let confFileServiveDefinitionProvider = new ConfigurationFileServiceDefinitionProvider(containerStore, phpClassStore) 22 | let phpServiceDefinitionProvider = new PHPServiceDefinitionProvider(containerStore, phpClassStore) 23 | 24 | let disposables: vscode.Disposable[] = [] 25 | disposables.push(vscode.languages.registerCompletionItemProvider({ scheme: 'file', language: 'yaml' }, configurationFileProvider, "@")) 26 | disposables.push(vscode.languages.registerCompletionItemProvider({ scheme: 'file', language: 'xml' }, configurationFileProvider, "id=\"")) 27 | disposables.push(vscode.languages.registerCompletionItemProvider({ scheme: 'file', language: 'php' }, phpServiceProvider)) 28 | disposables.push(vscode.languages.registerHoverProvider({ scheme: 'file', language: 'yaml' }, hoverProvider)) 29 | disposables.push(vscode.languages.registerHoverProvider({ scheme: 'file', language: 'xml' }, hoverProvider)) 30 | disposables.push(vscode.languages.registerHoverProvider({ scheme: 'file', language: 'php' }, hoverProvider)) 31 | disposables.push(vscode.languages.registerDefinitionProvider({ scheme: 'file', language: 'yaml' }, confFileServiveDefinitionProvider)) 32 | disposables.push(vscode.languages.registerDefinitionProvider({ scheme: 'file', language: 'xml' }, confFileServiveDefinitionProvider)) 33 | disposables.push(vscode.languages.registerDefinitionProvider({ scheme: 'file', language: 'php' }, phpServiceDefinitionProvider)) 34 | 35 | this._disposable = vscode.Disposable.from(...disposables) 36 | 37 | vscode.commands.registerCommand('symfony-vscode.goToServiceDefinition', (args) => { 38 | if(args && args instanceof ServiceDefinitionTreeItem) { 39 | this._goToServiceDefinition(args.serviceDefinition, confFileServiveDefinitionProvider) 40 | } else { 41 | vscode.window.showQuickPick(containerStore.serviceDefinitionList.map(serviceDefinition => { 42 | return new ServiceQuickPickItem(serviceDefinition) 43 | })).then(item => { 44 | if(item instanceof ServiceQuickPickItem) { 45 | this._goToServiceDefinition(item.serviceDefinition, confFileServiveDefinitionProvider) 46 | } 47 | }) 48 | } 49 | }) 50 | } 51 | 52 | protected _goToServiceDefinition(serviceDefinition: ServiceDefinition, serviceDefinitionProvider: AbstractServiceDefinitionProvider) { 53 | let location = serviceDefinitionProvider.getLocationOfService(serviceDefinition) 54 | if(location) { 55 | vscode.window.showTextDocument(location.uri, { 56 | selection: location.range 57 | }) 58 | } else { 59 | vscode.window.showErrorMessage("Class \"" + serviceDefinition.className + "\" not found") 60 | } 61 | } 62 | 63 | dispose() { 64 | this._disposable.dispose() 65 | } 66 | } -------------------------------------------------------------------------------- /src/php/provider/ParserPHPClassProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { PHPClassProviderInterface } from "./PHPClassProviderInterface" 3 | import { PHPClass } from "../PHPClass" 4 | import engine from 'php-parser' 5 | import { readFile } from "graceful-fs"; 6 | import { PromiseUtils } from "../PromiseUtils"; 7 | import { PHPUse } from "../PHPUse"; 8 | 9 | interface PHPParser { 10 | parseEval(code: String|Buffer): PHPParser_Item 11 | parseCode(code: String|Buffer, filename?: String): PHPParser_Item 12 | tokenGetAll(code: String|Buffer): PHPParser_Item 13 | } 14 | 15 | interface PHPParser_Item { 16 | kind: string 17 | loc: PHPParser_Location 18 | name?: string | PHPParser_Item 19 | children?: Array 20 | items?: Array 21 | body?: Array 22 | } 23 | 24 | interface PHPParser_UseItem { 25 | kind: string 26 | name: string 27 | alias?: string 28 | } 29 | 30 | interface PHPParser_Location { 31 | start: PHPParser_Position 32 | end: PHPParser_Position 33 | } 34 | 35 | interface PHPParser_Position { 36 | line: number 37 | column: number 38 | offset: number 39 | } 40 | 41 | export class ParserPHPClassProvider implements PHPClassProviderInterface { 42 | 43 | protected _engine: PHPParser 44 | protected _configuration = vscode.workspace.getConfiguration("symfony-vscode") 45 | 46 | constructor() { 47 | this._engine = new engine({ 48 | parser: { 49 | php7: true 50 | }, 51 | ast: { 52 | withPositions: true 53 | } 54 | }) 55 | } 56 | 57 | canUpdateAllUris(): boolean { 58 | return true 59 | } 60 | 61 | canUpdateUri(uri: vscode.Uri): boolean { 62 | return true 63 | } 64 | 65 | updateAllUris(): Promise { 66 | return new Promise((resolve, reject) => { 67 | vscode.workspace.findFiles("**/*.php").then(uris => { 68 | let ps = [] 69 | uris.forEach(uri => { 70 | ps.push(() => this.updateUri(uri)) 71 | }) 72 | PromiseUtils.throttleActions(ps, this._getParserThrottle()).then(phpClassesArray => { 73 | let resultArray: PHPClass[] = [] 74 | phpClassesArray.map(phpClasses => { 75 | let filteredArray: PHPClass[] = phpClasses.filter(phpClass => { 76 | return phpClass !== null 77 | }) 78 | resultArray = resultArray.concat(filteredArray) 79 | }) 80 | resolve(resultArray) 81 | }).catch(reason => { 82 | reject(reason) 83 | }) 84 | }) 85 | }) 86 | } 87 | 88 | updateUri(uri: vscode.Uri): Promise { 89 | return new Promise((resolve) => { 90 | readFile(uri.fsPath, (err, data) => { 91 | if(err) { 92 | resolve([]) 93 | } else { 94 | try { 95 | let ast = this._engine.parseCode(data.toString()) 96 | resolve(this._hydratePHPClass(ast, uri)) 97 | } catch(e) { 98 | resolve([]) 99 | } 100 | } 101 | }) 102 | }) 103 | } 104 | 105 | protected _hydratePHPClass(ast: PHPParser_Item, uri: vscode.Uri): PHPClass[] { 106 | try { 107 | let result: PHPClass[] = [] 108 | let children: Array = ast.children 109 | let nextElementsToProcess: Array = children 110 | let currentElement: PHPParser_Item = null 111 | let currentNamespace: String = null 112 | let uses: PHPUse[] = [] 113 | while(nextElementsToProcess.length > 0) { 114 | currentElement = nextElementsToProcess.shift() 115 | if(currentElement.kind === "namespace") { 116 | currentNamespace = currentElement.name 117 | nextElementsToProcess = currentElement.children 118 | } 119 | if(currentElement.kind === "usegroup") { 120 | uses = uses.concat(this._processUseGroup(currentElement)) 121 | } 122 | if(currentElement.kind === "class" || currentElement.kind === "interface") { 123 | result.push(this._processClass(currentElement, uri, currentNamespace)) 124 | } 125 | } 126 | 127 | result.forEach(phpClass => { 128 | phpClass.uses = uses 129 | }) 130 | 131 | return result 132 | } catch (e) { 133 | return [] 134 | } 135 | } 136 | 137 | protected _processClass(element: PHPParser_Item, uri: vscode.Uri, namespace?: String): PHPClass { 138 | let fullName = null 139 | if(typeof element.name === "object") { 140 | fullName = element.name.name 141 | } else if(typeof element.name === "string") { 142 | fullName = element.name 143 | } 144 | if(namespace) { 145 | fullName = namespace + '\\' + fullName 146 | } 147 | let phpClass = new PHPClass(fullName, uri) 148 | element.body.forEach(classElement => { 149 | if(classElement.kind === "method") { 150 | phpClass.addMethod((classElement.name).name) 151 | } 152 | }) 153 | phpClass.classPosition = new vscode.Position( 154 | element.loc.start.line, element.loc.start.column 155 | ) 156 | return phpClass 157 | } 158 | 159 | protected _processUseGroup(element: PHPParser_Item): PHPUse[] { 160 | let result: PHPUse[] = [] 161 | 162 | element.items.forEach(item => { 163 | result.push(new PHPUse(item.name, item.alias)) 164 | }) 165 | 166 | return result 167 | } 168 | 169 | private _getParserThrottle(): number { 170 | return this._configuration.get("phpParserThrottle") 171 | } 172 | } -------------------------------------------------------------------------------- /src/symfony/provider/ConsoleContainerProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import * as path from "path" 3 | import * as jsonStripComments from "strip-json-comments" 4 | 5 | import { ContainerProviderInterface } from "./ContainerProviderInterface"; 6 | import { ServiceDefinition } from "../ServiceDefinition"; 7 | import { spawn, SpawnOptions } from "child_process"; 8 | import { ComposerJSON } from "../ComposerJSON"; 9 | import { RouteDefinition } from "../RouteDefinition"; 10 | import { Parameter } from "../Parameter"; 11 | 12 | export class ConsoleContainerProvider implements ContainerProviderInterface { 13 | 14 | private _configuration = vscode.workspace.getConfiguration("symfony-vscode") 15 | private _composerJson: ComposerJSON = new ComposerJSON() 16 | 17 | canProvideServiceDefinitions(): boolean { 18 | return true 19 | } 20 | 21 | canProvideRouteDefinitions(): boolean { 22 | return true 23 | } 24 | 25 | canProvideParameters(): boolean { 26 | return true 27 | } 28 | 29 | provideServiceDefinitions(): Promise { 30 | return this._executeCommand(["debug:container", "--show-private"], (obj) => { 31 | let result: ServiceDefinition[] = [] 32 | let collection: Object = {} 33 | 34 | if (obj.definitions !== undefined) { 35 | Object.keys(obj.definitions).forEach(key => { 36 | collection[key] = (new ServiceDefinition(key, obj.definitions[key].class, obj.definitions[key].public, null)) 37 | }) 38 | } 39 | if (obj.aliases !== undefined) { 40 | Object.keys(obj.aliases).forEach(key => { 41 | let alias = obj.aliases[key].service 42 | let className = collection[alias] ? collection[alias].className : null 43 | collection[key] = (new ServiceDefinition(key, className, obj.aliases[key].public, alias)) 44 | }) 45 | } 46 | Object.keys(collection).forEach(key => { 47 | if (!this._matchServicesFilters(collection[key].id, collection[key].className)) { 48 | result.push(collection[key]) 49 | } 50 | }); 51 | 52 | return result 53 | }) 54 | } 55 | 56 | provideRouteDefinitions(): Promise { 57 | return this._executeCommand(["debug:router"], (obj) => { 58 | let result: RouteDefinition[] = [] 59 | 60 | Object.keys(obj).forEach(key => { 61 | if (!this._matchRoutesFilters(key, obj[key].path)) { 62 | result.push(new RouteDefinition(key, obj[key].path, obj[key].method, obj[key].defaults._controller)) 63 | } 64 | }) 65 | 66 | return result 67 | }) 68 | } 69 | 70 | provideParameters(): Promise { 71 | return this._executeCommand(["debug:container", "--parameters"], (obj) => { 72 | let result: Parameter[] = [] 73 | 74 | Object.keys(obj).forEach(key => { 75 | if (!this._matchParametersFilters(key)) { 76 | result.push(new Parameter(key, obj[key])) 77 | } 78 | }) 79 | 80 | return result 81 | }) 82 | } 83 | 84 | private _executeCommand(parameters: string[], cb: (obj: any) => T[]): Promise { 85 | return new Promise((resolve, reject) => { 86 | this._getConsolePath().then(infos => { 87 | let args: string[] = [] 88 | args.push(infos.consolePath) 89 | args = args.concat(parameters) 90 | args.push("--format=json") 91 | 92 | let buffer: string = "" 93 | let errorBuffer: string = "" 94 | try { 95 | let executable: string = this._getPHPExecutablePath() 96 | let options: SpawnOptions = { cwd: infos.cwd } 97 | 98 | let shellExecutable: string | boolean = false 99 | if (shellExecutable = this._getShellExecutable()) { 100 | executable = this._getShellCommand() 101 | options = { shell: shellExecutable } 102 | } 103 | 104 | let process = spawn(executable, args, options) 105 | process.stdout.on('data', (data) => { 106 | buffer += data 107 | }) 108 | process.stderr.on('data', (data) => { 109 | errorBuffer += data 110 | }) 111 | process.on('error', (err) => { 112 | if (this._showErrors) { 113 | reject(err.message) 114 | } else { 115 | resolve([]) 116 | } 117 | }) 118 | process.on('close', (code) => { 119 | if (code !== 0) { 120 | if (this._showErrors) { 121 | reject(errorBuffer) 122 | } else { 123 | resolve([]) 124 | } 125 | } else { 126 | try { 127 | let obj = JSON.parse(jsonStripComments(buffer)) 128 | resolve(cb(obj)) 129 | } catch (e) { 130 | if (this._showErrors) { 131 | reject(e) 132 | } else { 133 | resolve([]) 134 | } 135 | } 136 | } 137 | }) 138 | } catch (e) { 139 | if (this._showErrors) { 140 | reject(e) 141 | } else { 142 | resolve([]) 143 | } 144 | } 145 | }).catch(reason => { 146 | reject(reason) 147 | }) 148 | }) 149 | } 150 | 151 | private _getConsolePath(): Promise<{ consolePath: string, cwd: string }> { 152 | return new Promise((resolve, reject) => { 153 | this._composerJson.initialize().then(infos => { 154 | let customConsolePath = this._configuration.get("consolePath") 155 | let consolePath: string = "" 156 | if (customConsolePath) { 157 | consolePath = customConsolePath + " " 158 | } else { 159 | switch (infos.symfonyVersion) { 160 | case 2: 161 | consolePath = "app/console" 162 | break; 163 | case 3: 164 | default: 165 | consolePath = "bin/console" 166 | break; 167 | } 168 | } 169 | resolve({ 170 | consolePath: consolePath, 171 | cwd: path.dirname(infos.uri.fsPath) 172 | }) 173 | }).catch(reason => reject(reason)) 174 | }) 175 | } 176 | 177 | private _getPHPExecutablePath(): string { 178 | return this._configuration.get("phpExecutablePath") 179 | } 180 | 181 | private _getShellExecutable(): string { 182 | return this._configuration.get("shellExecutable") 183 | } 184 | 185 | private _getShellCommand(): string { 186 | return this._configuration.get("shellCommand") 187 | } 188 | 189 | private _showErrors(): boolean { 190 | return this._configuration.get("showConsoleErrors") 191 | } 192 | 193 | private _matchServicesFilters(serviceId: string, serviceClassName: string): boolean { 194 | let filters: object = this._configuration.get("servicesFilters") 195 | return Object.keys(filters).some(filter => { 196 | if (filters[filter] === "id" && serviceId != null && serviceId.match(new RegExp(filter))) { 197 | return true 198 | } else if (filters[filter] === "class" && serviceClassName != null && serviceClassName.match(new RegExp(filter))) { 199 | return true 200 | } 201 | return false 202 | }) 203 | } 204 | 205 | private _matchRoutesFilters(routeId: string, routePath: string): boolean { 206 | let filters: object = this._configuration.get("routesFilters") 207 | return Object.keys(filters).some(filter => { 208 | if (filters[filter] === "id" && routeId != null && routeId.match(new RegExp(filter))) { 209 | return true 210 | } else if (filters[filter] === "path" && routePath != null && routePath.match(new RegExp(filter))) { 211 | return true 212 | } 213 | return false 214 | }) 215 | } 216 | 217 | private _matchParametersFilters(parameterId: string): boolean { 218 | let filters: Array = this._configuration.get("parametersFilters") 219 | return filters.some(filter => { 220 | return parameterId != null && (parameterId.match(new RegExp(filter)) !== null) 221 | }) 222 | } 223 | } -------------------------------------------------------------------------------- /src/symfony/ContainerStore.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode" 2 | import { ServiceDefinition } from "./ServiceDefinition"; 3 | import { ContainerProviderInterface } from "./provider/ContainerProviderInterface"; 4 | import { ConsoleContainerProvider } from "./provider/ConsoleContainerProvider"; 5 | import { RouteDefinition } from "./RouteDefinition"; 6 | import { Parameter } from "./Parameter"; 7 | import { AbstractContainerStoreListener } from "./AbstractContainerStoreListener"; 8 | import { ContainerCacheManager } from "./ContainerCacheManager"; 9 | import { CacheContainerProvider } from "./provider/CacheContainerProvider"; 10 | 11 | export class ContainerStore { 12 | private _cacheManager: ContainerCacheManager 13 | private _containerProviders: ContainerProviderInterface[] = [] 14 | private _serviceDefinitionStore: ServiceDefinition[] = [] 15 | private _routeDefinitionStore: RouteDefinition[] = [] 16 | private _parameterStore: Parameter[] = [] 17 | private _listeners: AbstractContainerStoreListener[] = [] 18 | 19 | private static SERVICES_FETCH_MESSAGE = "Fetching Symfony services definitions..." 20 | private static ROUTES_FETCH_MESSAGE = "Fetching Symfony routes definitions..." 21 | private static PARAMETERS_FETCH_MESSAGE = "Fetching Symfony parameters..." 22 | private static CONTAINER_NO_PROVIDER = "Cannot retrieve container elements at the moment" 23 | 24 | constructor(cacheManager: ContainerCacheManager) { 25 | this._cacheManager = cacheManager 26 | this._containerProviders.push(new CacheContainerProvider(cacheManager)) 27 | this._containerProviders.push(new ConsoleContainerProvider()) 28 | } 29 | 30 | refreshAll(): Promise { 31 | return new Promise((resolve, reject) => { 32 | let hasValidProvider = this._containerProviders.some((provider) => { 33 | if(provider.canProvideServiceDefinitions() && provider.canProvideRouteDefinitions() && provider.canProvideParameters()) { 34 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.SERVICES_FETCH_MESSAGE }, (progress, token) => { 35 | return provider.provideServiceDefinitions().then(servicesDefinitions => { 36 | this._serviceDefinitionStore = servicesDefinitions 37 | this._cacheManager.setServices(servicesDefinitions) 38 | this._listeners.forEach(listerner => { 39 | listerner.onServicesChanges(servicesDefinitions) 40 | }); 41 | 42 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.ROUTES_FETCH_MESSAGE }, (progress, token) => { 43 | return provider.provideRouteDefinitions().then(routeDefinitions => { 44 | this._routeDefinitionStore = routeDefinitions 45 | this._cacheManager.setRoutes(routeDefinitions) 46 | this._listeners.forEach(listerner => { 47 | listerner.onRoutesChanges(routeDefinitions) 48 | }); 49 | 50 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.PARAMETERS_FETCH_MESSAGE }, (progress, token) => { 51 | return provider.provideParameters().then(parameters => { 52 | this._parameterStore = parameters 53 | this._cacheManager.setParameters(parameters) 54 | this._listeners.forEach(listerner => { 55 | listerner.onParametersChanges(parameters) 56 | }); 57 | resolve() 58 | }).catch(reason => { 59 | vscode.window.showErrorMessage(reason) 60 | reject() 61 | }) 62 | }) 63 | }).catch(reason => { 64 | vscode.window.showErrorMessage(reason) 65 | reject() 66 | }) 67 | }) 68 | }).catch(reason => { 69 | vscode.window.showErrorMessage(reason) 70 | reject() 71 | }) 72 | }) 73 | return true 74 | } else { 75 | return false 76 | } 77 | }) 78 | if(!hasValidProvider) { 79 | vscode.window.showErrorMessage(ContainerStore.CONTAINER_NO_PROVIDER) 80 | } 81 | }) 82 | } 83 | 84 | clearCacheAndRefreshAll(): void { 85 | this._cacheManager.clearServices().then(() => { 86 | this._cacheManager.clearRoutes().then(() => { 87 | this._cacheManager.clearParameters().then(() => { 88 | this.refreshAll() 89 | }) 90 | }) 91 | }) 92 | } 93 | 94 | refreshServiceDefinitions(): void { 95 | let hasValidProvider = this._containerProviders.some(provider => { 96 | if(provider.canProvideServiceDefinitions()) { 97 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.SERVICES_FETCH_MESSAGE }, (progress, token) => { 98 | return provider.provideServiceDefinitions().then(servicesDefinitions => { 99 | this._serviceDefinitionStore = servicesDefinitions 100 | this._cacheManager.setServices(servicesDefinitions) 101 | this._listeners.forEach(listener => { 102 | listener.onServicesChanges(servicesDefinitions) 103 | }); 104 | }).catch(reason => { 105 | vscode.window.showErrorMessage(reason) 106 | }) 107 | }) 108 | return true 109 | } else { 110 | return false 111 | } 112 | }) 113 | if(!hasValidProvider) { 114 | vscode.window.showErrorMessage(ContainerStore.CONTAINER_NO_PROVIDER) 115 | } 116 | } 117 | 118 | clearCacheAndRefreshServices(): void { 119 | this._cacheManager.clearServices().then(() => { 120 | this.refreshServiceDefinitions() 121 | }) 122 | } 123 | 124 | refreshRouteDefinitions(): void { 125 | let hasValidProvider = this._containerProviders.some(provider => { 126 | if(provider.canProvideRouteDefinitions()) { 127 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.ROUTES_FETCH_MESSAGE }, (progress, token) => { 128 | return provider.provideRouteDefinitions().then(routeDefinitions => { 129 | this._routeDefinitionStore = routeDefinitions 130 | this._cacheManager.setRoutes(routeDefinitions) 131 | this._listeners.forEach(listener => { 132 | listener.onRoutesChanges(routeDefinitions) 133 | }); 134 | }).catch(reason => { 135 | vscode.window.showErrorMessage(reason) 136 | }) 137 | }) 138 | return true 139 | } else { 140 | return false 141 | } 142 | }) 143 | if(!hasValidProvider) { 144 | vscode.window.showErrorMessage(ContainerStore.CONTAINER_NO_PROVIDER) 145 | } 146 | } 147 | 148 | clearCacheAndRefreshRoutes(): void { 149 | this._cacheManager.clearRoutes().then(() => { 150 | this.refreshRouteDefinitions() 151 | }) 152 | } 153 | 154 | refreshParameters(): void { 155 | let hasValidProvider = this._containerProviders.some(provider => { 156 | if(provider.canProvideParameters()) { 157 | vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: ContainerStore.PARAMETERS_FETCH_MESSAGE }, (progress, token) => { 158 | return provider.provideParameters().then(parameters => { 159 | this._parameterStore = parameters 160 | this._cacheManager.setParameters(parameters) 161 | this._listeners.forEach(listener => { 162 | listener.onParametersChanges(parameters) 163 | }); 164 | }).catch(reason => { 165 | vscode.window.showErrorMessage(reason) 166 | }) 167 | }) 168 | return true 169 | } else { 170 | return false 171 | } 172 | }) 173 | if(!hasValidProvider) { 174 | vscode.window.showErrorMessage(ContainerStore.CONTAINER_NO_PROVIDER) 175 | } 176 | } 177 | 178 | clearCacheAndRefreshParameters(): void { 179 | this._cacheManager.clearParameters().then(() => { 180 | this.refreshParameters() 181 | }) 182 | } 183 | 184 | subscribeListerner(listener: AbstractContainerStoreListener) { 185 | this._listeners.push(listener) 186 | } 187 | 188 | get serviceDefinitionList(): ServiceDefinition[] { 189 | return this._serviceDefinitionStore 190 | } 191 | 192 | get routeDefinitionList(): RouteDefinition[] { 193 | return this._routeDefinitionStore 194 | } 195 | 196 | get parameterList(): Parameter[] { 197 | return this._parameterStore 198 | } 199 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony-vscode", 3 | "displayName": "Symfony for VSCode", 4 | "description": "Debug and autocomplete of Symfony container", 5 | "version": "1.0.2", 6 | "publisher": "TheNouillet", 7 | "repository": { 8 | "url": "https://github.com/TheNouillet/symfony-vscode" 9 | }, 10 | "engines": { 11 | "vscode": "^1.25.0" 12 | }, 13 | "icon": "media/symfony.png", 14 | "categories": [ 15 | "Other" 16 | ], 17 | "activationEvents": [ 18 | "workspaceContains:**/composer.json" 19 | ], 20 | "main": "./out/extension", 21 | "contributes": { 22 | "viewsContainers": { 23 | "activitybar": [ 24 | { 25 | "id": "symfonyViewsContainer", 26 | "title": "Symfony container view", 27 | "icon": "media/logo.svg" 28 | } 29 | ] 30 | }, 31 | "views": { 32 | "symfonyViewsContainer": [ 33 | { 34 | "id": "parametersView", 35 | "name": "Parameters view" 36 | }, 37 | { 38 | "id": "routeDefinitionsView", 39 | "name": "Routes definitions view" 40 | }, 41 | { 42 | "id": "serviceDefinitionsView", 43 | "name": "Services definitions view" 44 | } 45 | ] 46 | }, 47 | "commands": [ 48 | { 49 | "command": "symfony-vscode.refreshServiceDefinitions", 50 | "title": "Refresh container services definitions", 51 | "category": "Symfony" 52 | }, 53 | { 54 | "command": "symfony-vscode.searchForServices", 55 | "title": "Search for Symfony services in the services view", 56 | "category": "Symfony", 57 | "icon": { 58 | "light": "media/light/search.svg", 59 | "dark": "media/dark/search.svg" 60 | } 61 | }, 62 | { 63 | "command": "symfony-vscode.clearServicesSearch", 64 | "title": "Clear the services search criteria", 65 | "category": "Symfony", 66 | "icon": { 67 | "light": "media/light/cancel.svg", 68 | "dark": "media/dark/cancel.svg" 69 | } 70 | }, 71 | { 72 | "command": "symfony-vscode.goToServiceDefinition", 73 | "title": "Go to service definition", 74 | "category": "Symfony", 75 | "icon": { 76 | "light": "media/light/goto.svg", 77 | "dark": "media/dark/goto.svg" 78 | } 79 | }, 80 | { 81 | "command": "symfony-vscode.refreshRouteDefinitions", 82 | "title": "Refresh container routes definitions", 83 | "category": "Symfony" 84 | }, 85 | { 86 | "command": "symfony-vscode.searchForRoutes", 87 | "title": "Search for Symfony routes in the routes view", 88 | "category": "Symfony", 89 | "icon": { 90 | "light": "media/light/search.svg", 91 | "dark": "media/dark/search.svg" 92 | } 93 | }, 94 | { 95 | "command": "symfony-vscode.clearRoutesSearch", 96 | "title": "Clear the routes search criteria", 97 | "category": "Symfony", 98 | "icon": { 99 | "light": "media/light/cancel.svg", 100 | "dark": "media/dark/cancel.svg" 101 | } 102 | }, 103 | { 104 | "command": "symfony-vscode.refreshParameters", 105 | "title": "Refresh container parameters", 106 | "category": "Symfony" 107 | }, 108 | { 109 | "command": "symfony-vscode.searchForParameters", 110 | "title": "Search for Symfony parameters in the parameters view", 111 | "category": "Symfony", 112 | "icon": { 113 | "light": "media/light/search.svg", 114 | "dark": "media/dark/search.svg" 115 | } 116 | }, 117 | { 118 | "command": "symfony-vscode.clearParametersSearch", 119 | "title": "Clear the parameters search criteria", 120 | "category": "Symfony", 121 | "icon": { 122 | "light": "media/light/cancel.svg", 123 | "dark": "media/dark/cancel.svg" 124 | } 125 | }, 126 | { 127 | "command": "symfony-vscode.refreshContainer", 128 | "title": "Refresh the entire container", 129 | "category": "Symfony" 130 | }, 131 | { 132 | "command": "symfony-vscode.toggleClassDisplay", 133 | "title": "Toggle class/id display for services", 134 | "category": "Symfony" 135 | }, 136 | { 137 | "command": "symfony-vscode.togglePathDisplay", 138 | "title": "Toggle path/id display for routes", 139 | "category": "Symfony" 140 | }, 141 | { 142 | "command": "symfony-vscode.refreshPHPClasses", 143 | "title": "Reindex PHP classes", 144 | "category": "Symfony" 145 | } 146 | ], 147 | "menus": { 148 | "view/title": [ 149 | { 150 | "command": "symfony-vscode.refreshServiceDefinitions", 151 | "when": "view == serviceDefinitionsView", 152 | "group": "2_workspace@1" 153 | }, 154 | { 155 | "command": "symfony-vscode.toggleClassDisplay", 156 | "when": "view == serviceDefinitionsView", 157 | "group": "2_workspace@2" 158 | }, 159 | { 160 | "command": "symfony-vscode.searchForServices", 161 | "when": "view == serviceDefinitionsView", 162 | "group": "navigation" 163 | }, 164 | { 165 | "command": "symfony-vscode.refreshRouteDefinitions", 166 | "when": "view == routeDefinitionsView", 167 | "group": "2_workspace@1" 168 | }, 169 | { 170 | "command": "symfony-vscode.togglePathDisplay", 171 | "when": "view == routeDefinitionsView", 172 | "group": "2_workspace@2" 173 | }, 174 | { 175 | "command": "symfony-vscode.searchForRoutes", 176 | "when": "view == routeDefinitionsView", 177 | "group": "navigation" 178 | }, 179 | { 180 | "command": "symfony-vscode.refreshParameters", 181 | "when": "view == parametersView", 182 | "group": "2_workspace@1" 183 | }, 184 | { 185 | "command": "symfony-vscode.searchForParameters", 186 | "when": "view == parametersView", 187 | "group": "navigation" 188 | } 189 | ], 190 | "view/item/context": [ 191 | { 192 | "command": "symfony-vscode.clearServicesSearch", 193 | "when": "viewItem == symfony-vscode.searchItem.service", 194 | "group": "inline" 195 | }, 196 | { 197 | "command": "symfony-vscode.clearRoutesSearch", 198 | "when": "viewItem == symfony-vscode.searchItem.route", 199 | "group": "inline" 200 | }, 201 | { 202 | "command": "symfony-vscode.clearParametersSearch", 203 | "when": "viewItem == symfony-vscode.searchItem.parameter", 204 | "group": "inline" 205 | }, 206 | { 207 | "command": "symfony-vscode.goToServiceDefinition", 208 | "when": "viewItem == symfony-vscode.service", 209 | "group": "inline" 210 | } 211 | ] 212 | }, 213 | "configuration": { 214 | "title": "Symfony for VSCode", 215 | "properties": { 216 | "symfony-vscode.phpExecutablePath": { 217 | "type": "string", 218 | "default": "/usr/bin/php", 219 | "description": "Path to the PHP executable. This path is ignored if the symfony-vscode.shellExecutable parameter is different than false" 220 | }, 221 | "symfony-vscode.shellExecutable": { 222 | "type": "string", 223 | "default": false, 224 | "description": "The shell executable path. If differant that false, console commands will be called via shell instead of just calling the PHP executable." 225 | }, 226 | "symfony-vscode.shellCommand": { 227 | "type": "string", 228 | "default": false, 229 | "description": "The shell command. Only used when calling the shell to do console commands." 230 | }, 231 | "symfony-vscode.consolePath": { 232 | "type": [ 233 | "string", 234 | "null" 235 | ], 236 | "default": null, 237 | "description": "Path to the Symfony console, relative to the root directeory. If null, the extension try to guess the path with the Symfony version from the composer.json file" 238 | }, 239 | "symfony-vscode.showConsoleErrors": { 240 | "type": "boolean", 241 | "default": true, 242 | "description": "If false, the extension doesn't show error messages caused by compilation errors." 243 | }, 244 | "symfony-vscode.enableFileWatching": { 245 | "type": "boolean", 246 | "default": true, 247 | "description": "If false, the extension refresh automatically when a YAML file is modified" 248 | }, 249 | "symfony-vscode.fileWatchingPatterns": { 250 | "type": "array", 251 | "default": [ 252 | "yml", 253 | "yaml", 254 | "xml" 255 | ], 256 | "description": "Files with one of these extensions will trigger a container refresh on save" 257 | }, 258 | "symfony-vscode.servicesFilters": { 259 | "type": "object", 260 | "default": { 261 | "[a-f0-9]{64}_[0-9]+": "id", 262 | "~": "id", 263 | "instanceof\\.": "id" 264 | }, 265 | "description": "Filter out services entirely when they match one of the given regexes. Useful for auto-generated services. Use \"id\" to filter out services by id, or \"class\" by extended class name" 266 | }, 267 | "symfony-vscode.routesFilters": { 268 | "type": "object", 269 | "default": { 270 | "^_assetic_": "id" 271 | }, 272 | "description": "Filter out routes entirely when they match one of the given regexes. Useful for auto-generated routes. Use \"id\" to filter out routes by id, or \"path\" by route path" 273 | }, 274 | "symfony-vscode.parametersFilters": { 275 | "type": "array", 276 | "default": [ 277 | "\\.class$", 278 | "_class$" 279 | ], 280 | "description": "Filter out parameters entirely when their ids match one of the given regexes." 281 | }, 282 | "symfony-vscode.phpParserThrottle": { 283 | "type": "number", 284 | "default": 256, 285 | "description": "Maximum number of process capable of reading PHP files. Too much processes can block file reading of other extensions and programs" 286 | } 287 | } 288 | } 289 | }, 290 | "scripts": { 291 | "vscode:prepublish": "npm run compile", 292 | "compile": "tsc -p ./", 293 | "watch": "tsc -watch -p ./", 294 | "postinstall": "node ./node_modules/vscode/bin/install", 295 | "test": "npm run compile && node ./node_modules/vscode/bin/test" 296 | }, 297 | "devDependencies": { 298 | "@types/mocha": "^2.2.42", 299 | "@types/node": "^7.0.43", 300 | "typescript": "^2.6.1", 301 | "vscode": "^1.1.6" 302 | }, 303 | "dependencies": { 304 | "graceful-fs": "^4.1.15", 305 | "strip-json-comments": "^2.0.1", 306 | "php-parser": "^3.0.0-prerelease.7" 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/mocha@^2.2.42": 6 | version "2.2.48" 7 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.48.tgz#3523b126a0b049482e1c3c11877460f76622ffab" 8 | 9 | "@types/node@^7.0.43": 10 | version "7.10.2" 11 | resolved "https://registry.yarnpkg.com/@types/node/-/node-7.10.2.tgz#a98845168012d7a63a84d50e738829da43bdb0de" 12 | 13 | ajv@^6.5.5: 14 | version "6.5.5" 15 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1" 16 | dependencies: 17 | fast-deep-equal "^2.0.1" 18 | fast-json-stable-stringify "^2.0.0" 19 | json-schema-traverse "^0.4.1" 20 | uri-js "^4.2.2" 21 | 22 | ansi-cyan@^0.1.1: 23 | version "0.1.1" 24 | resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" 25 | dependencies: 26 | ansi-wrap "0.1.0" 27 | 28 | ansi-red@^0.1.1: 29 | version "0.1.1" 30 | resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" 31 | dependencies: 32 | ansi-wrap "0.1.0" 33 | 34 | ansi-wrap@0.1.0: 35 | version "0.1.0" 36 | resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" 37 | 38 | append-buffer@^1.0.2: 39 | version "1.0.2" 40 | resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" 41 | dependencies: 42 | buffer-equal "^1.0.0" 43 | 44 | arr-diff@^1.0.1: 45 | version "1.1.0" 46 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" 47 | dependencies: 48 | arr-flatten "^1.0.1" 49 | array-slice "^0.2.3" 50 | 51 | arr-diff@^2.0.0: 52 | version "2.0.0" 53 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 54 | dependencies: 55 | arr-flatten "^1.0.1" 56 | 57 | arr-flatten@^1.0.1: 58 | version "1.1.0" 59 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 60 | 61 | arr-union@^2.0.1: 62 | version "2.1.0" 63 | resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" 64 | 65 | array-differ@^1.0.0: 66 | version "1.0.0" 67 | resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" 68 | 69 | array-slice@^0.2.3: 70 | version "0.2.3" 71 | resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" 72 | 73 | array-union@^1.0.1: 74 | version "1.0.2" 75 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 76 | dependencies: 77 | array-uniq "^1.0.1" 78 | 79 | array-uniq@^1.0.1: 80 | version "1.0.3" 81 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 82 | 83 | array-unique@^0.2.1: 84 | version "0.2.1" 85 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 86 | 87 | arrify@^1.0.0: 88 | version "1.0.1" 89 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 90 | 91 | asn1@~0.2.3: 92 | version "0.2.4" 93 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 94 | dependencies: 95 | safer-buffer "~2.1.0" 96 | 97 | assert-plus@1.0.0, assert-plus@^1.0.0: 98 | version "1.0.0" 99 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 100 | 101 | asynckit@^0.4.0: 102 | version "0.4.0" 103 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 104 | 105 | aws-sign2@~0.7.0: 106 | version "0.7.0" 107 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 108 | 109 | aws4@^1.8.0: 110 | version "1.8.0" 111 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" 112 | 113 | balanced-match@^1.0.0: 114 | version "1.0.0" 115 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 116 | 117 | bcrypt-pbkdf@^1.0.0: 118 | version "1.0.2" 119 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 120 | dependencies: 121 | tweetnacl "^0.14.3" 122 | 123 | block-stream@*: 124 | version "0.0.9" 125 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" 126 | dependencies: 127 | inherits "~2.0.0" 128 | 129 | brace-expansion@^1.1.7: 130 | version "1.1.11" 131 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 132 | dependencies: 133 | balanced-match "^1.0.0" 134 | concat-map "0.0.1" 135 | 136 | braces@^1.8.2: 137 | version "1.8.5" 138 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 139 | dependencies: 140 | expand-range "^1.8.1" 141 | preserve "^0.2.0" 142 | repeat-element "^1.1.2" 143 | 144 | browser-stdout@1.3.0: 145 | version "1.3.0" 146 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 147 | 148 | buffer-crc32@~0.2.3: 149 | version "0.2.13" 150 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" 151 | 152 | buffer-equal@^1.0.0: 153 | version "1.0.0" 154 | resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" 155 | 156 | buffer-from@^1.0.0: 157 | version "1.1.1" 158 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 159 | 160 | caseless@~0.12.0: 161 | version "0.12.0" 162 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 163 | 164 | clone-buffer@^1.0.0: 165 | version "1.0.0" 166 | resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" 167 | 168 | clone-stats@^0.0.1: 169 | version "0.0.1" 170 | resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" 171 | 172 | clone-stats@^1.0.0: 173 | version "1.0.0" 174 | resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" 175 | 176 | clone@^0.2.0: 177 | version "0.2.0" 178 | resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" 179 | 180 | clone@^1.0.0: 181 | version "1.0.4" 182 | resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" 183 | 184 | clone@^2.1.1: 185 | version "2.1.2" 186 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" 187 | 188 | cloneable-readable@^1.0.0: 189 | version "1.1.2" 190 | resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" 191 | dependencies: 192 | inherits "^2.0.1" 193 | process-nextick-args "^2.0.0" 194 | readable-stream "^2.3.5" 195 | 196 | combined-stream@^1.0.6, combined-stream@~1.0.6: 197 | version "1.0.7" 198 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" 199 | dependencies: 200 | delayed-stream "~1.0.0" 201 | 202 | commander@2.11.0: 203 | version "2.11.0" 204 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" 205 | 206 | concat-map@0.0.1: 207 | version "0.0.1" 208 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 209 | 210 | convert-source-map@^1.1.1, convert-source-map@^1.5.0: 211 | version "1.6.0" 212 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" 213 | dependencies: 214 | safe-buffer "~5.1.1" 215 | 216 | core-util-is@1.0.2, core-util-is@~1.0.0: 217 | version "1.0.2" 218 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 219 | 220 | dashdash@^1.12.0: 221 | version "1.14.1" 222 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 223 | dependencies: 224 | assert-plus "^1.0.0" 225 | 226 | debug@3.1.0: 227 | version "3.1.0" 228 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 229 | dependencies: 230 | ms "2.0.0" 231 | 232 | deep-assign@^1.0.0: 233 | version "1.0.0" 234 | resolved "http://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b" 235 | dependencies: 236 | is-obj "^1.0.0" 237 | 238 | define-properties@^1.1.2: 239 | version "1.1.3" 240 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 241 | dependencies: 242 | object-keys "^1.0.12" 243 | 244 | delayed-stream@~1.0.0: 245 | version "1.0.0" 246 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 247 | 248 | diff@3.3.1: 249 | version "3.3.1" 250 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" 251 | 252 | duplexer@^0.1.1, duplexer@~0.1.1: 253 | version "0.1.1" 254 | resolved "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" 255 | 256 | duplexify@^3.2.0, duplexify@^3.6.0: 257 | version "3.6.1" 258 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.1.tgz#b1a7a29c4abfd639585efaecce80d666b1e34125" 259 | dependencies: 260 | end-of-stream "^1.0.0" 261 | inherits "^2.0.1" 262 | readable-stream "^2.0.0" 263 | stream-shift "^1.0.0" 264 | 265 | ecc-jsbn@~0.1.1: 266 | version "0.1.2" 267 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 268 | dependencies: 269 | jsbn "~0.1.0" 270 | safer-buffer "^2.1.0" 271 | 272 | end-of-stream@^1.0.0, end-of-stream@^1.1.0: 273 | version "1.4.1" 274 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" 275 | dependencies: 276 | once "^1.4.0" 277 | 278 | escape-string-regexp@1.0.5: 279 | version "1.0.5" 280 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 281 | 282 | event-stream@^3.3.1, event-stream@^3.3.4, event-stream@~3.3.4: 283 | version "3.3.6" 284 | resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.6.tgz#cac1230890e07e73ec9cacd038f60a5b66173eef" 285 | dependencies: 286 | duplexer "^0.1.1" 287 | flatmap-stream "^0.1.0" 288 | from "^0.1.7" 289 | map-stream "0.0.7" 290 | pause-stream "^0.0.11" 291 | split "^1.0.1" 292 | stream-combiner "^0.2.2" 293 | through "^2.3.8" 294 | 295 | expand-brackets@^0.1.4: 296 | version "0.1.5" 297 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 298 | dependencies: 299 | is-posix-bracket "^0.1.0" 300 | 301 | expand-range@^1.8.1: 302 | version "1.8.2" 303 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 304 | dependencies: 305 | fill-range "^2.1.0" 306 | 307 | extend-shallow@^1.1.2: 308 | version "1.1.4" 309 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" 310 | dependencies: 311 | kind-of "^1.1.0" 312 | 313 | extend-shallow@^2.0.1: 314 | version "2.0.1" 315 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 316 | dependencies: 317 | is-extendable "^0.1.0" 318 | 319 | extend@^3.0.0, extend@~3.0.2: 320 | version "3.0.2" 321 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 322 | 323 | extglob@^0.3.1: 324 | version "0.3.2" 325 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 326 | dependencies: 327 | is-extglob "^1.0.0" 328 | 329 | extsprintf@1.3.0: 330 | version "1.3.0" 331 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 332 | 333 | extsprintf@^1.2.0: 334 | version "1.4.0" 335 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 336 | 337 | fast-deep-equal@^2.0.1: 338 | version "2.0.1" 339 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 340 | 341 | fast-json-stable-stringify@^2.0.0: 342 | version "2.0.0" 343 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 344 | 345 | fd-slicer@~1.1.0: 346 | version "1.1.0" 347 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" 348 | dependencies: 349 | pend "~1.2.0" 350 | 351 | filename-regex@^2.0.0: 352 | version "2.0.1" 353 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 354 | 355 | fill-range@^2.1.0: 356 | version "2.2.4" 357 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" 358 | dependencies: 359 | is-number "^2.1.0" 360 | isobject "^2.0.0" 361 | randomatic "^3.0.0" 362 | repeat-element "^1.1.2" 363 | repeat-string "^1.5.2" 364 | 365 | first-chunk-stream@^1.0.0: 366 | version "1.0.0" 367 | resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" 368 | 369 | flatmap-stream@^0.1.0: 370 | version "0.1.2" 371 | resolved "https://registry.yarnpkg.com/flatmap-stream/-/flatmap-stream-0.1.2.tgz#b1da359a93f24f6d96e46f948552d997e3c2863d" 372 | 373 | flush-write-stream@^1.0.2: 374 | version "1.0.3" 375 | resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" 376 | dependencies: 377 | inherits "^2.0.1" 378 | readable-stream "^2.0.4" 379 | 380 | for-in@^1.0.1: 381 | version "1.0.2" 382 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 383 | 384 | for-own@^0.1.4: 385 | version "0.1.5" 386 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 387 | dependencies: 388 | for-in "^1.0.1" 389 | 390 | forever-agent@~0.6.1: 391 | version "0.6.1" 392 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 393 | 394 | form-data@~2.3.2: 395 | version "2.3.3" 396 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" 397 | dependencies: 398 | asynckit "^0.4.0" 399 | combined-stream "^1.0.6" 400 | mime-types "^2.1.12" 401 | 402 | from@^0.1.7: 403 | version "0.1.7" 404 | resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" 405 | 406 | fs-mkdirp-stream@^1.0.0: 407 | version "1.0.0" 408 | resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" 409 | dependencies: 410 | graceful-fs "^4.1.11" 411 | through2 "^2.0.3" 412 | 413 | fs.realpath@^1.0.0: 414 | version "1.0.0" 415 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 416 | 417 | fstream@^1.0.2: 418 | version "1.0.11" 419 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" 420 | dependencies: 421 | graceful-fs "^4.1.2" 422 | inherits "~2.0.0" 423 | mkdirp ">=0.5 0" 424 | rimraf "2" 425 | 426 | function-bind@^1.1.1: 427 | version "1.1.1" 428 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 429 | 430 | getpass@^0.1.1: 431 | version "0.1.7" 432 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 433 | dependencies: 434 | assert-plus "^1.0.0" 435 | 436 | glob-base@^0.3.0: 437 | version "0.3.0" 438 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 439 | dependencies: 440 | glob-parent "^2.0.0" 441 | is-glob "^2.0.0" 442 | 443 | glob-parent@^2.0.0: 444 | version "2.0.0" 445 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 446 | dependencies: 447 | is-glob "^2.0.0" 448 | 449 | glob-parent@^3.0.0, glob-parent@^3.1.0: 450 | version "3.1.0" 451 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" 452 | dependencies: 453 | is-glob "^3.1.0" 454 | path-dirname "^1.0.0" 455 | 456 | glob-stream@^5.3.2: 457 | version "5.3.5" 458 | resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" 459 | dependencies: 460 | extend "^3.0.0" 461 | glob "^5.0.3" 462 | glob-parent "^3.0.0" 463 | micromatch "^2.3.7" 464 | ordered-read-streams "^0.3.0" 465 | through2 "^0.6.0" 466 | to-absolute-glob "^0.1.1" 467 | unique-stream "^2.0.2" 468 | 469 | glob-stream@^6.1.0: 470 | version "6.1.0" 471 | resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" 472 | dependencies: 473 | extend "^3.0.0" 474 | glob "^7.1.1" 475 | glob-parent "^3.1.0" 476 | is-negated-glob "^1.0.0" 477 | ordered-read-streams "^1.0.0" 478 | pumpify "^1.3.5" 479 | readable-stream "^2.1.5" 480 | remove-trailing-separator "^1.0.1" 481 | to-absolute-glob "^2.0.0" 482 | unique-stream "^2.0.2" 483 | 484 | glob@7.1.2: 485 | version "7.1.2" 486 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 487 | dependencies: 488 | fs.realpath "^1.0.0" 489 | inflight "^1.0.4" 490 | inherits "2" 491 | minimatch "^3.0.4" 492 | once "^1.3.0" 493 | path-is-absolute "^1.0.0" 494 | 495 | glob@^5.0.3: 496 | version "5.0.15" 497 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 498 | dependencies: 499 | inflight "^1.0.4" 500 | inherits "2" 501 | minimatch "2 || 3" 502 | once "^1.3.0" 503 | path-is-absolute "^1.0.0" 504 | 505 | glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: 506 | version "7.1.3" 507 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 508 | dependencies: 509 | fs.realpath "^1.0.0" 510 | inflight "^1.0.4" 511 | inherits "2" 512 | minimatch "^3.0.4" 513 | once "^1.3.0" 514 | path-is-absolute "^1.0.0" 515 | 516 | graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: 517 | version "4.1.15" 518 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" 519 | 520 | growl@1.10.3: 521 | version "1.10.3" 522 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" 523 | 524 | gulp-chmod@^2.0.0: 525 | version "2.0.0" 526 | resolved "https://registry.yarnpkg.com/gulp-chmod/-/gulp-chmod-2.0.0.tgz#00c390b928a0799b251accf631aa09e01cc6299c" 527 | dependencies: 528 | deep-assign "^1.0.0" 529 | stat-mode "^0.2.0" 530 | through2 "^2.0.0" 531 | 532 | gulp-filter@^5.0.1: 533 | version "5.1.0" 534 | resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.1.0.tgz#a05e11affb07cf7dcf41a7de1cb7b63ac3783e73" 535 | dependencies: 536 | multimatch "^2.0.0" 537 | plugin-error "^0.1.2" 538 | streamfilter "^1.0.5" 539 | 540 | gulp-gunzip@1.0.0: 541 | version "1.0.0" 542 | resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz#15b741145e83a9c6f50886241b57cc5871f151a9" 543 | dependencies: 544 | through2 "~0.6.5" 545 | vinyl "~0.4.6" 546 | 547 | gulp-remote-src-vscode@^0.5.0: 548 | version "0.5.0" 549 | resolved "https://registry.yarnpkg.com/gulp-remote-src-vscode/-/gulp-remote-src-vscode-0.5.0.tgz#71785553bc491880088ad971f90910c4b2d80a99" 550 | dependencies: 551 | event-stream "^3.3.4" 552 | node.extend "^1.1.2" 553 | request "^2.79.0" 554 | through2 "^2.0.3" 555 | vinyl "^2.0.1" 556 | 557 | gulp-sourcemaps@1.6.0: 558 | version "1.6.0" 559 | resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c" 560 | dependencies: 561 | convert-source-map "^1.1.1" 562 | graceful-fs "^4.1.2" 563 | strip-bom "^2.0.0" 564 | through2 "^2.0.0" 565 | vinyl "^1.0.0" 566 | 567 | gulp-symdest@^1.1.0: 568 | version "1.1.0" 569 | resolved "https://registry.yarnpkg.com/gulp-symdest/-/gulp-symdest-1.1.0.tgz#c165320732d192ce56fd94271ffa123234bf2ae0" 570 | dependencies: 571 | event-stream "^3.3.1" 572 | mkdirp "^0.5.1" 573 | queue "^3.1.0" 574 | vinyl-fs "^2.4.3" 575 | 576 | gulp-untar@^0.0.7: 577 | version "0.0.7" 578 | resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.7.tgz#92067d79e0fa1e92d60562a100233a44a5aa08b4" 579 | dependencies: 580 | event-stream "~3.3.4" 581 | streamifier "~0.1.1" 582 | tar "^2.2.1" 583 | through2 "~2.0.3" 584 | vinyl "^1.2.0" 585 | 586 | gulp-vinyl-zip@^2.1.0: 587 | version "2.1.1" 588 | resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.1.tgz#211aebdc5e4f702ddaf17b4e8b1ef6e3612a8b04" 589 | dependencies: 590 | event-stream "^3.3.1" 591 | queue "^4.2.1" 592 | through2 "^2.0.3" 593 | vinyl "^2.0.2" 594 | vinyl-fs "^3.0.3" 595 | yauzl "^2.2.1" 596 | yazl "^2.2.1" 597 | 598 | har-schema@^2.0.0: 599 | version "2.0.0" 600 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 601 | 602 | har-validator@~5.1.0: 603 | version "5.1.3" 604 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" 605 | dependencies: 606 | ajv "^6.5.5" 607 | har-schema "^2.0.0" 608 | 609 | has-flag@^2.0.0: 610 | version "2.0.0" 611 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 612 | 613 | has-symbols@^1.0.0: 614 | version "1.0.0" 615 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 616 | 617 | has@^1.0.3: 618 | version "1.0.3" 619 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 620 | dependencies: 621 | function-bind "^1.1.1" 622 | 623 | he@1.1.1: 624 | version "1.1.1" 625 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 626 | 627 | http-signature@~1.2.0: 628 | version "1.2.0" 629 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 630 | dependencies: 631 | assert-plus "^1.0.0" 632 | jsprim "^1.2.2" 633 | sshpk "^1.7.0" 634 | 635 | inflight@^1.0.4: 636 | version "1.0.6" 637 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 638 | dependencies: 639 | once "^1.3.0" 640 | wrappy "1" 641 | 642 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: 643 | version "2.0.3" 644 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 645 | 646 | is-absolute@^1.0.0: 647 | version "1.0.0" 648 | resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" 649 | dependencies: 650 | is-relative "^1.0.0" 651 | is-windows "^1.0.1" 652 | 653 | is-buffer@^1.1.5: 654 | version "1.1.6" 655 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 656 | 657 | is-dotfile@^1.0.0: 658 | version "1.0.3" 659 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 660 | 661 | is-equal-shallow@^0.1.3: 662 | version "0.1.3" 663 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 664 | dependencies: 665 | is-primitive "^2.0.0" 666 | 667 | is-extendable@^0.1.0, is-extendable@^0.1.1: 668 | version "0.1.1" 669 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 670 | 671 | is-extglob@^1.0.0: 672 | version "1.0.0" 673 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 674 | 675 | is-extglob@^2.1.0: 676 | version "2.1.1" 677 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 678 | 679 | is-glob@^2.0.0, is-glob@^2.0.1: 680 | version "2.0.1" 681 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 682 | dependencies: 683 | is-extglob "^1.0.0" 684 | 685 | is-glob@^3.1.0: 686 | version "3.1.0" 687 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" 688 | dependencies: 689 | is-extglob "^2.1.0" 690 | 691 | is-negated-glob@^1.0.0: 692 | version "1.0.0" 693 | resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" 694 | 695 | is-number@^2.1.0: 696 | version "2.1.0" 697 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 698 | dependencies: 699 | kind-of "^3.0.2" 700 | 701 | is-number@^4.0.0: 702 | version "4.0.0" 703 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" 704 | 705 | is-obj@^1.0.0: 706 | version "1.0.1" 707 | resolved "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" 708 | 709 | is-posix-bracket@^0.1.0: 710 | version "0.1.1" 711 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 712 | 713 | is-primitive@^2.0.0: 714 | version "2.0.0" 715 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 716 | 717 | is-relative@^1.0.0: 718 | version "1.0.0" 719 | resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" 720 | dependencies: 721 | is-unc-path "^1.0.0" 722 | 723 | is-stream@^1.0.1: 724 | version "1.1.0" 725 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 726 | 727 | is-typedarray@~1.0.0: 728 | version "1.0.0" 729 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 730 | 731 | is-unc-path@^1.0.0: 732 | version "1.0.0" 733 | resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" 734 | dependencies: 735 | unc-path-regex "^0.1.2" 736 | 737 | is-utf8@^0.2.0, is-utf8@^0.2.1: 738 | version "0.2.1" 739 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 740 | 741 | is-valid-glob@^0.3.0: 742 | version "0.3.0" 743 | resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" 744 | 745 | is-valid-glob@^1.0.0: 746 | version "1.0.0" 747 | resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" 748 | 749 | is-windows@^1.0.1: 750 | version "1.0.2" 751 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 752 | 753 | is@^3.2.1: 754 | version "3.2.1" 755 | resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" 756 | 757 | isarray@0.0.1: 758 | version "0.0.1" 759 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 760 | 761 | isarray@1.0.0, isarray@~1.0.0: 762 | version "1.0.0" 763 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 764 | 765 | isobject@^2.0.0: 766 | version "2.1.0" 767 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 768 | dependencies: 769 | isarray "1.0.0" 770 | 771 | isstream@~0.1.2: 772 | version "0.1.2" 773 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 774 | 775 | jsbn@~0.1.0: 776 | version "0.1.1" 777 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 778 | 779 | json-schema-traverse@^0.4.1: 780 | version "0.4.1" 781 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 782 | 783 | json-schema@0.2.3: 784 | version "0.2.3" 785 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 786 | 787 | json-stable-stringify@^1.0.0: 788 | version "1.0.1" 789 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 790 | dependencies: 791 | jsonify "~0.0.0" 792 | 793 | json-stringify-safe@~5.0.1: 794 | version "5.0.1" 795 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 796 | 797 | jsonify@~0.0.0: 798 | version "0.0.0" 799 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 800 | 801 | jsprim@^1.2.2: 802 | version "1.4.1" 803 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 804 | dependencies: 805 | assert-plus "1.0.0" 806 | extsprintf "1.3.0" 807 | json-schema "0.2.3" 808 | verror "1.10.0" 809 | 810 | kind-of@^1.1.0: 811 | version "1.1.0" 812 | resolved "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" 813 | 814 | kind-of@^3.0.2: 815 | version "3.2.2" 816 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 817 | dependencies: 818 | is-buffer "^1.1.5" 819 | 820 | kind-of@^6.0.0: 821 | version "6.0.2" 822 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" 823 | 824 | lazystream@^1.0.0: 825 | version "1.0.0" 826 | resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" 827 | dependencies: 828 | readable-stream "^2.0.5" 829 | 830 | lead@^1.0.0: 831 | version "1.0.0" 832 | resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42" 833 | dependencies: 834 | flush-write-stream "^1.0.2" 835 | 836 | lodash.isequal@^4.0.0: 837 | version "4.5.0" 838 | resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" 839 | 840 | map-stream@0.0.7: 841 | version "0.0.7" 842 | resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" 843 | 844 | math-random@^1.0.1: 845 | version "1.0.1" 846 | resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" 847 | 848 | merge-stream@^1.0.0: 849 | version "1.0.1" 850 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" 851 | dependencies: 852 | readable-stream "^2.0.1" 853 | 854 | micromatch@^2.3.7: 855 | version "2.3.11" 856 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 857 | dependencies: 858 | arr-diff "^2.0.0" 859 | array-unique "^0.2.1" 860 | braces "^1.8.2" 861 | expand-brackets "^0.1.4" 862 | extglob "^0.3.1" 863 | filename-regex "^2.0.0" 864 | is-extglob "^1.0.0" 865 | is-glob "^2.0.1" 866 | kind-of "^3.0.2" 867 | normalize-path "^2.0.1" 868 | object.omit "^2.0.0" 869 | parse-glob "^3.0.4" 870 | regex-cache "^0.4.2" 871 | 872 | mime-db@~1.37.0: 873 | version "1.37.0" 874 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" 875 | 876 | mime-types@^2.1.12, mime-types@~2.1.19: 877 | version "2.1.21" 878 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" 879 | dependencies: 880 | mime-db "~1.37.0" 881 | 882 | "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.4: 883 | version "3.0.4" 884 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 885 | dependencies: 886 | brace-expansion "^1.1.7" 887 | 888 | minimist@0.0.8: 889 | version "0.0.8" 890 | resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 891 | 892 | mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: 893 | version "0.5.1" 894 | resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 895 | dependencies: 896 | minimist "0.0.8" 897 | 898 | mocha@^4.0.1: 899 | version "4.1.0" 900 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" 901 | dependencies: 902 | browser-stdout "1.3.0" 903 | commander "2.11.0" 904 | debug "3.1.0" 905 | diff "3.3.1" 906 | escape-string-regexp "1.0.5" 907 | glob "7.1.2" 908 | growl "1.10.3" 909 | he "1.1.1" 910 | mkdirp "0.5.1" 911 | supports-color "4.4.0" 912 | 913 | ms@2.0.0: 914 | version "2.0.0" 915 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 916 | 917 | multimatch@^2.0.0: 918 | version "2.1.0" 919 | resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" 920 | dependencies: 921 | array-differ "^1.0.0" 922 | array-union "^1.0.1" 923 | arrify "^1.0.0" 924 | minimatch "^3.0.0" 925 | 926 | node.extend@^1.1.2: 927 | version "1.1.7" 928 | resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.7.tgz#e140a5a54d587465085a99d78ce92c856331a131" 929 | dependencies: 930 | has "^1.0.3" 931 | is "^3.2.1" 932 | 933 | normalize-path@^2.0.1, normalize-path@^2.1.1: 934 | version "2.1.1" 935 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 936 | dependencies: 937 | remove-trailing-separator "^1.0.1" 938 | 939 | now-and-later@^2.0.0: 940 | version "2.0.0" 941 | resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.0.tgz#bc61cbb456d79cb32207ce47ca05136ff2e7d6ee" 942 | dependencies: 943 | once "^1.3.2" 944 | 945 | oauth-sign@~0.9.0: 946 | version "0.9.0" 947 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" 948 | 949 | object-assign@^4.0.0: 950 | version "4.1.1" 951 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 952 | 953 | object-keys@^1.0.11, object-keys@^1.0.12: 954 | version "1.0.12" 955 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" 956 | 957 | object.assign@^4.0.4: 958 | version "4.1.0" 959 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 960 | dependencies: 961 | define-properties "^1.1.2" 962 | function-bind "^1.1.1" 963 | has-symbols "^1.0.0" 964 | object-keys "^1.0.11" 965 | 966 | object.omit@^2.0.0: 967 | version "2.0.1" 968 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 969 | dependencies: 970 | for-own "^0.1.4" 971 | is-extendable "^0.1.1" 972 | 973 | once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: 974 | version "1.4.0" 975 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 976 | dependencies: 977 | wrappy "1" 978 | 979 | ordered-read-streams@^0.3.0: 980 | version "0.3.0" 981 | resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" 982 | dependencies: 983 | is-stream "^1.0.1" 984 | readable-stream "^2.0.1" 985 | 986 | ordered-read-streams@^1.0.0: 987 | version "1.0.1" 988 | resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" 989 | dependencies: 990 | readable-stream "^2.0.1" 991 | 992 | parse-glob@^3.0.4: 993 | version "3.0.4" 994 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 995 | dependencies: 996 | glob-base "^0.3.0" 997 | is-dotfile "^1.0.0" 998 | is-extglob "^1.0.0" 999 | is-glob "^2.0.0" 1000 | 1001 | path-dirname@^1.0.0: 1002 | version "1.0.2" 1003 | resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" 1004 | 1005 | path-is-absolute@^1.0.0: 1006 | version "1.0.1" 1007 | resolved "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1008 | 1009 | pause-stream@^0.0.11: 1010 | version "0.0.11" 1011 | resolved "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" 1012 | dependencies: 1013 | through "~2.3" 1014 | 1015 | pend@~1.2.0: 1016 | version "1.2.0" 1017 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" 1018 | 1019 | performance-now@^2.1.0: 1020 | version "2.1.0" 1021 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 1022 | 1023 | php-parser@^3.0.0-prerelease.7: 1024 | version "3.0.0-prerelease.7" 1025 | resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.0.0-prerelease.7.tgz#1a90d55e43af69588042f6d5169d5d335af739e1" 1026 | 1027 | plugin-error@^0.1.2: 1028 | version "0.1.2" 1029 | resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" 1030 | dependencies: 1031 | ansi-cyan "^0.1.1" 1032 | ansi-red "^0.1.1" 1033 | arr-diff "^1.0.1" 1034 | arr-union "^2.0.1" 1035 | extend-shallow "^1.1.2" 1036 | 1037 | preserve@^0.2.0: 1038 | version "0.2.0" 1039 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 1040 | 1041 | process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: 1042 | version "2.0.0" 1043 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" 1044 | 1045 | psl@^1.1.24: 1046 | version "1.1.29" 1047 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" 1048 | 1049 | pump@^2.0.0: 1050 | version "2.0.1" 1051 | resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" 1052 | dependencies: 1053 | end-of-stream "^1.1.0" 1054 | once "^1.3.1" 1055 | 1056 | pumpify@^1.3.5: 1057 | version "1.5.1" 1058 | resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" 1059 | dependencies: 1060 | duplexify "^3.6.0" 1061 | inherits "^2.0.3" 1062 | pump "^2.0.0" 1063 | 1064 | punycode@^1.4.1: 1065 | version "1.4.1" 1066 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 1067 | 1068 | punycode@^2.1.0: 1069 | version "2.1.1" 1070 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1071 | 1072 | qs@~6.5.2: 1073 | version "6.5.2" 1074 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 1075 | 1076 | querystringify@^2.0.0: 1077 | version "2.1.0" 1078 | resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" 1079 | 1080 | queue@^3.1.0: 1081 | version "3.1.0" 1082 | resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" 1083 | dependencies: 1084 | inherits "~2.0.0" 1085 | 1086 | queue@^4.2.1: 1087 | version "4.5.0" 1088 | resolved "https://registry.yarnpkg.com/queue/-/queue-4.5.0.tgz#0f125191a983e3c38fcc0c0c75087d358d0857f4" 1089 | dependencies: 1090 | inherits "~2.0.0" 1091 | 1092 | randomatic@^3.0.0: 1093 | version "3.1.1" 1094 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" 1095 | dependencies: 1096 | is-number "^4.0.0" 1097 | kind-of "^6.0.0" 1098 | math-random "^1.0.1" 1099 | 1100 | "readable-stream@>=1.0.33-1 <1.1.0-0": 1101 | version "1.0.34" 1102 | resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" 1103 | dependencies: 1104 | core-util-is "~1.0.0" 1105 | inherits "~2.0.1" 1106 | isarray "0.0.1" 1107 | string_decoder "~0.10.x" 1108 | 1109 | readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@~2.3.6: 1110 | version "2.3.6" 1111 | resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 1112 | dependencies: 1113 | core-util-is "~1.0.0" 1114 | inherits "~2.0.3" 1115 | isarray "~1.0.0" 1116 | process-nextick-args "~2.0.0" 1117 | safe-buffer "~5.1.1" 1118 | string_decoder "~1.1.1" 1119 | util-deprecate "~1.0.1" 1120 | 1121 | regex-cache@^0.4.2: 1122 | version "0.4.4" 1123 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" 1124 | dependencies: 1125 | is-equal-shallow "^0.1.3" 1126 | 1127 | remove-bom-buffer@^3.0.0: 1128 | version "3.0.0" 1129 | resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" 1130 | dependencies: 1131 | is-buffer "^1.1.5" 1132 | is-utf8 "^0.2.1" 1133 | 1134 | remove-bom-stream@^1.2.0: 1135 | version "1.2.0" 1136 | resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523" 1137 | dependencies: 1138 | remove-bom-buffer "^3.0.0" 1139 | safe-buffer "^5.1.0" 1140 | through2 "^2.0.3" 1141 | 1142 | remove-trailing-separator@^1.0.1: 1143 | version "1.1.0" 1144 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 1145 | 1146 | repeat-element@^1.1.2: 1147 | version "1.1.3" 1148 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" 1149 | 1150 | repeat-string@^1.5.2: 1151 | version "1.6.1" 1152 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1153 | 1154 | replace-ext@0.0.1: 1155 | version "0.0.1" 1156 | resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" 1157 | 1158 | replace-ext@^1.0.0: 1159 | version "1.0.0" 1160 | resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" 1161 | 1162 | request@^2.79.0, request@^2.83.0: 1163 | version "2.88.0" 1164 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" 1165 | dependencies: 1166 | aws-sign2 "~0.7.0" 1167 | aws4 "^1.8.0" 1168 | caseless "~0.12.0" 1169 | combined-stream "~1.0.6" 1170 | extend "~3.0.2" 1171 | forever-agent "~0.6.1" 1172 | form-data "~2.3.2" 1173 | har-validator "~5.1.0" 1174 | http-signature "~1.2.0" 1175 | is-typedarray "~1.0.0" 1176 | isstream "~0.1.2" 1177 | json-stringify-safe "~5.0.1" 1178 | mime-types "~2.1.19" 1179 | oauth-sign "~0.9.0" 1180 | performance-now "^2.1.0" 1181 | qs "~6.5.2" 1182 | safe-buffer "^5.1.2" 1183 | tough-cookie "~2.4.3" 1184 | tunnel-agent "^0.6.0" 1185 | uuid "^3.3.2" 1186 | 1187 | requires-port@^1.0.0: 1188 | version "1.0.0" 1189 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 1190 | 1191 | resolve-options@^1.1.0: 1192 | version "1.1.0" 1193 | resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" 1194 | dependencies: 1195 | value-or-function "^3.0.0" 1196 | 1197 | rimraf@2: 1198 | version "2.6.2" 1199 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 1200 | dependencies: 1201 | glob "^7.0.5" 1202 | 1203 | safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1204 | version "5.1.2" 1205 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1206 | 1207 | safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 1208 | version "2.1.2" 1209 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1210 | 1211 | semver@^5.4.1: 1212 | version "5.6.0" 1213 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" 1214 | 1215 | source-map-support@^0.5.0: 1216 | version "0.5.9" 1217 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" 1218 | dependencies: 1219 | buffer-from "^1.0.0" 1220 | source-map "^0.6.0" 1221 | 1222 | source-map@^0.6.0: 1223 | version "0.6.1" 1224 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1225 | 1226 | split@^1.0.1: 1227 | version "1.0.1" 1228 | resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" 1229 | dependencies: 1230 | through "2" 1231 | 1232 | sshpk@^1.7.0: 1233 | version "1.15.2" 1234 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629" 1235 | dependencies: 1236 | asn1 "~0.2.3" 1237 | assert-plus "^1.0.0" 1238 | bcrypt-pbkdf "^1.0.0" 1239 | dashdash "^1.12.0" 1240 | ecc-jsbn "~0.1.1" 1241 | getpass "^0.1.1" 1242 | jsbn "~0.1.0" 1243 | safer-buffer "^2.0.2" 1244 | tweetnacl "~0.14.0" 1245 | 1246 | stat-mode@^0.2.0: 1247 | version "0.2.2" 1248 | resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" 1249 | 1250 | stream-combiner@^0.2.2: 1251 | version "0.2.2" 1252 | resolved "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" 1253 | dependencies: 1254 | duplexer "~0.1.1" 1255 | through "~2.3.4" 1256 | 1257 | stream-shift@^1.0.0: 1258 | version "1.0.0" 1259 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" 1260 | 1261 | streamfilter@^1.0.5: 1262 | version "1.0.7" 1263 | resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" 1264 | dependencies: 1265 | readable-stream "^2.0.2" 1266 | 1267 | streamifier@~0.1.1: 1268 | version "0.1.1" 1269 | resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" 1270 | 1271 | string_decoder@~0.10.x: 1272 | version "0.10.31" 1273 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 1274 | 1275 | string_decoder@~1.1.1: 1276 | version "1.1.1" 1277 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1278 | dependencies: 1279 | safe-buffer "~5.1.0" 1280 | 1281 | strip-bom-stream@^1.0.0: 1282 | version "1.0.0" 1283 | resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" 1284 | dependencies: 1285 | first-chunk-stream "^1.0.0" 1286 | strip-bom "^2.0.0" 1287 | 1288 | strip-bom@^2.0.0: 1289 | version "2.0.0" 1290 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 1291 | dependencies: 1292 | is-utf8 "^0.2.0" 1293 | 1294 | supports-color@4.4.0: 1295 | version "4.4.0" 1296 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" 1297 | dependencies: 1298 | has-flag "^2.0.0" 1299 | 1300 | tar@^2.2.1: 1301 | version "2.2.1" 1302 | resolved "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" 1303 | dependencies: 1304 | block-stream "*" 1305 | fstream "^1.0.2" 1306 | inherits "2" 1307 | 1308 | through2-filter@^2.0.0: 1309 | version "2.0.0" 1310 | resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" 1311 | dependencies: 1312 | through2 "~2.0.0" 1313 | xtend "~4.0.0" 1314 | 1315 | through2@^0.6.0, through2@~0.6.5: 1316 | version "0.6.5" 1317 | resolved "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" 1318 | dependencies: 1319 | readable-stream ">=1.0.33-1 <1.1.0-0" 1320 | xtend ">=4.0.0 <4.1.0-0" 1321 | 1322 | through2@^2.0.0, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: 1323 | version "2.0.5" 1324 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" 1325 | dependencies: 1326 | readable-stream "~2.3.6" 1327 | xtend "~4.0.1" 1328 | 1329 | through@2, through@^2.3.8, through@~2.3, through@~2.3.4: 1330 | version "2.3.8" 1331 | resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1332 | 1333 | to-absolute-glob@^0.1.1: 1334 | version "0.1.1" 1335 | resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" 1336 | dependencies: 1337 | extend-shallow "^2.0.1" 1338 | 1339 | to-absolute-glob@^2.0.0: 1340 | version "2.0.2" 1341 | resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" 1342 | dependencies: 1343 | is-absolute "^1.0.0" 1344 | is-negated-glob "^1.0.0" 1345 | 1346 | to-through@^2.0.0: 1347 | version "2.0.0" 1348 | resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6" 1349 | dependencies: 1350 | through2 "^2.0.3" 1351 | 1352 | tough-cookie@~2.4.3: 1353 | version "2.4.3" 1354 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" 1355 | dependencies: 1356 | psl "^1.1.24" 1357 | punycode "^1.4.1" 1358 | 1359 | tunnel-agent@^0.6.0: 1360 | version "0.6.0" 1361 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 1362 | dependencies: 1363 | safe-buffer "^5.0.1" 1364 | 1365 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 1366 | version "0.14.5" 1367 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 1368 | 1369 | typescript@^2.6.1: 1370 | version "2.9.2" 1371 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" 1372 | 1373 | unc-path-regex@^0.1.2: 1374 | version "0.1.2" 1375 | resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" 1376 | 1377 | unique-stream@^2.0.2: 1378 | version "2.2.1" 1379 | resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" 1380 | dependencies: 1381 | json-stable-stringify "^1.0.0" 1382 | through2-filter "^2.0.0" 1383 | 1384 | uri-js@^4.2.2: 1385 | version "4.2.2" 1386 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 1387 | dependencies: 1388 | punycode "^2.1.0" 1389 | 1390 | url-parse@^1.4.3: 1391 | version "1.4.4" 1392 | resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" 1393 | dependencies: 1394 | querystringify "^2.0.0" 1395 | requires-port "^1.0.0" 1396 | 1397 | util-deprecate@~1.0.1: 1398 | version "1.0.2" 1399 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1400 | 1401 | uuid@^3.3.2: 1402 | version "3.3.2" 1403 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 1404 | 1405 | vali-date@^1.0.0: 1406 | version "1.0.0" 1407 | resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" 1408 | 1409 | value-or-function@^3.0.0: 1410 | version "3.0.0" 1411 | resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" 1412 | 1413 | verror@1.10.0: 1414 | version "1.10.0" 1415 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 1416 | dependencies: 1417 | assert-plus "^1.0.0" 1418 | core-util-is "1.0.2" 1419 | extsprintf "^1.2.0" 1420 | 1421 | vinyl-fs@^2.4.3: 1422 | version "2.4.4" 1423 | resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" 1424 | dependencies: 1425 | duplexify "^3.2.0" 1426 | glob-stream "^5.3.2" 1427 | graceful-fs "^4.0.0" 1428 | gulp-sourcemaps "1.6.0" 1429 | is-valid-glob "^0.3.0" 1430 | lazystream "^1.0.0" 1431 | lodash.isequal "^4.0.0" 1432 | merge-stream "^1.0.0" 1433 | mkdirp "^0.5.0" 1434 | object-assign "^4.0.0" 1435 | readable-stream "^2.0.4" 1436 | strip-bom "^2.0.0" 1437 | strip-bom-stream "^1.0.0" 1438 | through2 "^2.0.0" 1439 | through2-filter "^2.0.0" 1440 | vali-date "^1.0.0" 1441 | vinyl "^1.0.0" 1442 | 1443 | vinyl-fs@^3.0.3: 1444 | version "3.0.3" 1445 | resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" 1446 | dependencies: 1447 | fs-mkdirp-stream "^1.0.0" 1448 | glob-stream "^6.1.0" 1449 | graceful-fs "^4.0.0" 1450 | is-valid-glob "^1.0.0" 1451 | lazystream "^1.0.0" 1452 | lead "^1.0.0" 1453 | object.assign "^4.0.4" 1454 | pumpify "^1.3.5" 1455 | readable-stream "^2.3.3" 1456 | remove-bom-buffer "^3.0.0" 1457 | remove-bom-stream "^1.2.0" 1458 | resolve-options "^1.1.0" 1459 | through2 "^2.0.0" 1460 | to-through "^2.0.0" 1461 | value-or-function "^3.0.0" 1462 | vinyl "^2.0.0" 1463 | vinyl-sourcemap "^1.1.0" 1464 | 1465 | vinyl-source-stream@^1.1.0: 1466 | version "1.1.2" 1467 | resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz#62b53a135610a896e98ca96bee3a87f008a8e780" 1468 | dependencies: 1469 | through2 "^2.0.3" 1470 | vinyl "^0.4.3" 1471 | 1472 | vinyl-sourcemap@^1.1.0: 1473 | version "1.1.0" 1474 | resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" 1475 | dependencies: 1476 | append-buffer "^1.0.2" 1477 | convert-source-map "^1.5.0" 1478 | graceful-fs "^4.1.6" 1479 | normalize-path "^2.1.1" 1480 | now-and-later "^2.0.0" 1481 | remove-bom-buffer "^3.0.0" 1482 | vinyl "^2.0.0" 1483 | 1484 | vinyl@^0.4.3, vinyl@~0.4.6: 1485 | version "0.4.6" 1486 | resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" 1487 | dependencies: 1488 | clone "^0.2.0" 1489 | clone-stats "^0.0.1" 1490 | 1491 | vinyl@^1.0.0, vinyl@^1.2.0: 1492 | version "1.2.0" 1493 | resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" 1494 | dependencies: 1495 | clone "^1.0.0" 1496 | clone-stats "^0.0.1" 1497 | replace-ext "0.0.1" 1498 | 1499 | vinyl@^2.0.0, vinyl@^2.0.1, vinyl@^2.0.2: 1500 | version "2.2.0" 1501 | resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86" 1502 | dependencies: 1503 | clone "^2.1.1" 1504 | clone-buffer "^1.0.0" 1505 | clone-stats "^1.0.0" 1506 | cloneable-readable "^1.0.0" 1507 | remove-trailing-separator "^1.0.1" 1508 | replace-ext "^1.0.0" 1509 | 1510 | vscode@^1.1.6: 1511 | version "1.1.21" 1512 | resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.21.tgz#1c8253d6238aefb4112d6e58cf975ad25313dafc" 1513 | dependencies: 1514 | glob "^7.1.2" 1515 | gulp-chmod "^2.0.0" 1516 | gulp-filter "^5.0.1" 1517 | gulp-gunzip "1.0.0" 1518 | gulp-remote-src-vscode "^0.5.0" 1519 | gulp-symdest "^1.1.0" 1520 | gulp-untar "^0.0.7" 1521 | gulp-vinyl-zip "^2.1.0" 1522 | mocha "^4.0.1" 1523 | request "^2.83.0" 1524 | semver "^5.4.1" 1525 | source-map-support "^0.5.0" 1526 | url-parse "^1.4.3" 1527 | vinyl-source-stream "^1.1.0" 1528 | 1529 | wrappy@1: 1530 | version "1.0.2" 1531 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1532 | 1533 | "xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.0, xtend@~4.0.1: 1534 | version "4.0.1" 1535 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1536 | 1537 | yauzl@^2.2.1: 1538 | version "2.10.0" 1539 | resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" 1540 | dependencies: 1541 | buffer-crc32 "~0.2.3" 1542 | fd-slicer "~1.1.0" 1543 | 1544 | yazl@^2.2.1: 1545 | version "2.5.0" 1546 | resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.0.tgz#1ab8de8cd3c3c252986c7fa2f6562784d7288e49" 1547 | dependencies: 1548 | buffer-crc32 "~0.2.3" 1549 | --------------------------------------------------------------------------------