├── .node-version ├── phpcs ├── phpcs_icon.png ├── .vscodeignore ├── tsconfig.json ├── src │ ├── resolvers │ │ ├── path-resolver-base.ts │ │ ├── global-path-resolver.ts │ │ ├── path-resolver.ts │ │ └── composer-path-resolver.ts │ ├── settings.ts │ ├── timer.ts │ ├── protocol.ts │ ├── status.ts │ ├── extension.ts │ └── configuration.ts ├── test │ ├── extension.test.ts │ └── index.ts ├── package.json ├── README.md └── phpcs_icon.svg ├── phpcs-server ├── README.md ├── tsconfig.json ├── src │ ├── message.ts │ ├── settings.ts │ ├── protocol.ts │ ├── base │ │ ├── common │ │ │ ├── strings.ts │ │ │ └── charcode.ts │ │ └── node │ │ │ └── extfs.ts │ ├── strings.ts │ ├── linter.ts │ └── server.ts ├── package.json ├── test │ └── base │ │ └── common │ │ └── strings.test.ts └── package-lock.json ├── tslint.json ├── .editorconfig ├── tsfmt.json ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── LICENSE.md ├── package.json ├── README.md └── .gitignore /.node-version: -------------------------------------------------------------------------------- 1 | 8.9.4 2 | -------------------------------------------------------------------------------- /phpcs/phpcs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikappas/vscode-phpcs/HEAD/phpcs/phpcs_icon.png -------------------------------------------------------------------------------- /phpcs-server/README.md: -------------------------------------------------------------------------------- 1 | # phpcs-server 2 | 3 | The VS Code server part of the [phpcs](https://github.com/squizlabs/PHP_CodeSniffer.git) integration. 4 | -------------------------------------------------------------------------------- /phpcs/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-unused-expression": true, 4 | "no-duplicate-variable": true, 5 | "no-unused-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": true, 9 | "triple-equals": true 10 | }, 11 | "defaultSeverity": "warning" 12 | } -------------------------------------------------------------------------------- /phpcs-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noUnusedLocals": true, 4 | "noUnusedParameters": true, 5 | "noImplicitAny": true, 6 | "noImplicitReturns": true, 7 | "target": "es6", 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "sourceMap": true, 11 | "lib": [ "es2016" ], 12 | "outDir": "../phpcs/server" 13 | }, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /phpcs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noUnusedLocals": true, 4 | "noUnusedParameters": true, 5 | "noImplicitAny": true, 6 | "noImplicitReturns": true, 7 | "target": "es6", 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "sourceMap": true, 11 | "lib": [ "es2016" ], 12 | "rootDir": ".", 13 | "outDir": "out" 14 | }, 15 | "exclude": [ 16 | "node_modules", 17 | "server" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Tab indentation 7 | [*] 8 | end_of_line = lf 9 | indent_style = tab 10 | indent_size = 4 11 | trim_trailing_whitespace = true 12 | 13 | # The indent size used in the `package.json` file cannot be changed 14 | # https://github.com/npm/npm/pull/3180#issuecomment-16336516 15 | [{*.yml,*.yaml,npm-shrinkwrap.json,package.json}] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /phpcs-server/src/message.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export interface PhpcsMessage { 8 | message: string; 9 | severity: number; 10 | type: string; 11 | line: number; 12 | column: number; 13 | fixable: boolean; 14 | source?: string; 15 | } 16 | -------------------------------------------------------------------------------- /phpcs/src/resolvers/path-resolver-base.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export abstract class PhpcsPathResolverBase { 8 | protected phpcsExecutableFile: string; 9 | 10 | constructor() { 11 | let extension = /^win/.test(process.platform) ? ".bat" : ""; 12 | this.phpcsExecutableFile = `phpcs${extension}`; 13 | } 14 | 15 | abstract async resolve(): Promise; 16 | } 17 | -------------------------------------------------------------------------------- /phpcs/src/settings.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export interface PhpcsSettings { 8 | enable: boolean; 9 | workspaceRoot: string | null; 10 | executablePath: string | null; 11 | composerJsonPath: string | null; 12 | standard: string | null; 13 | autoConfigSearch: boolean; 14 | showSources: boolean; 15 | showWarnings: boolean; 16 | ignorePatterns: string[]; 17 | warningSeverity: number; 18 | errorSeverity: number; 19 | } -------------------------------------------------------------------------------- /phpcs-server/src/settings.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export interface PhpcsSettings { 8 | enable: boolean; 9 | workspaceRoot: string | null; 10 | executablePath: string | null; 11 | composerJsonPath: string | null; 12 | standard: string | null; 13 | autoConfigSearch: boolean; 14 | showSources: boolean; 15 | showWarnings: boolean; 16 | ignorePatterns: string[]; 17 | warningSeverity: number; 18 | errorSeverity: number; 19 | } -------------------------------------------------------------------------------- /tsfmt.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabSize": 4, 3 | "indentSize": 4, 4 | "newLineCharacter": "\n", 5 | "convertTabsToSpaces": false, 6 | "insertSpaceAfterCommaDelimiter": true, 7 | "insertSpaceAfterSemicolonInForStatements": true, 8 | "insertSpaceBeforeAndAfterBinaryOperators": true, 9 | "insertSpaceAfterKeywordsInControlFlowStatements": true, 10 | "insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 11 | "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 12 | "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 13 | "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, 14 | "insertSpaceBeforeFunctionParenthesis": false, 15 | "placeOpenBraceOnNewLineForFunctions": false, 16 | "placeOpenBraceOnNewLineForControlBlocks": false 17 | } -------------------------------------------------------------------------------- /phpcs/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 extension from '../src/extension'; 13 | 14 | // Defines a Mocha test suite to group tests of similar kind together 15 | suite("Extension Tests", () => { 16 | 17 | // Defines a Mocha unit test 18 | test("Something 1", () => { 19 | assert.equal(-1, [1, 2, 3].indexOf(5)); 20 | assert.equal(-1, [1, 2, 3].indexOf(0)); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": false // set this to true to hide the "out" folder with the compiled JS files 4 | }, 5 | "search.exclude": { 6 | "out": true // set this to false to include "out" folder in search results 7 | }, 8 | "typescript.tsdk": "./node_modules/typescript/lib", 9 | "typescript.tsc.autoDetect": "off", 10 | "files.trimTrailingWhitespace": true, 11 | "editor.insertSpaces": false, 12 | "editor.tabSize": 4, 13 | "cSpell.words": [ 14 | "Composer", 15 | "Drupal", 16 | "Ioannis", 17 | "Kappas", 18 | "Squiz", 19 | "WordPress", 20 | "Zend", 21 | "charcode", 22 | "codesniffer", 23 | "comspec", 24 | "gitignore", 25 | "ikappas", 26 | "languageclient", 27 | "languageserver", 28 | "lockfile", 29 | "micromatch", 30 | "phpcs", 31 | "pkg", 32 | "pkgs", 33 | "preinstall", 34 | "quickstart", 35 | "rtrim", 36 | "ruleset", 37 | "squizlabs", 38 | "testrunner" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "compounds": [ 4 | { 5 | "name": "Client+Server", 6 | "configurations": ["Launch Extension", "Attach to Server"] 7 | } 8 | ], 9 | "configurations": [ 10 | { 11 | "name": "Launch Extension", 12 | "type": "extensionHost", 13 | "request": "launch", 14 | "runtimeExecutable": "${execPath}", 15 | "args": [ 16 | "--extensionDevelopmentPath=${workspaceRoot}/phpcs" 17 | ], 18 | "stopOnEntry": false, 19 | "sourceMaps": true, 20 | "outFiles": [ 21 | "${workspaceRoot}/phpcs/out/**/*.js" 22 | ], 23 | "preLaunchTask": "watch:client" 24 | }, 25 | { 26 | "name": "Attach to Server", 27 | "type": "node", 28 | "request": "attach", 29 | "port": 6199, 30 | "stopOnEntry": false, 31 | "sourceMaps": true, 32 | "outFiles": [ 33 | "${workspaceRoot}/phpcs/server/**/*.js" 34 | ], 35 | "protocol": "inspector", 36 | "preLaunchTask": "watch:server" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /phpcs/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 | var testRunner = require("vscode/lib/testrunner"); 14 | 15 | // You can directly control Mocha options by un-commenting 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; 23 | -------------------------------------------------------------------------------- /phpcs/src/resolvers/global-path-resolver.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import * as path from 'path'; 8 | import * as fs from 'fs'; 9 | 10 | import { PhpcsPathResolverBase } from './path-resolver-base'; 11 | 12 | export class GlobalPhpcsPathResolver extends PhpcsPathResolverBase { 13 | async resolve(): Promise { 14 | let resolvedPath = null; 15 | let pathSeparator = /^win/.test(process.platform) ? ";" : ":"; 16 | let globalPaths: string[] = process.env.PATH.split(pathSeparator); 17 | globalPaths.some((globalPath: string) => { 18 | let testPath = path.join(globalPath, this.phpcsExecutableFile); 19 | if (fs.existsSync(testPath)) { 20 | resolvedPath = testPath; 21 | return true; 22 | } 23 | return false; 24 | }); 25 | return resolvedPath; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ioannis Kappas 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /phpcs-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpcs-server", 3 | "description": "PHP Code Sniffer server.", 4 | "version": "1.0.5", 5 | "author": "Ioannis Kappas", 6 | "publisher": "ikappas", 7 | "license": "MIT", 8 | "engines": { 9 | "node": "*" 10 | }, 11 | "homepage": "https://github.com/ikappas/vscode-phpcs/blob/master/README.md", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/ikappas/vscode-phpcs.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/ikappas/vscode-phpcs/issues" 18 | }, 19 | "dependencies": { 20 | "vscode-languageserver": "^3.5.0", 21 | "cross-spawn": "^6.0.4", 22 | "micromatch": "^3.1.9", 23 | "semver": "^5.5.0" 24 | }, 25 | "scripts": { 26 | "preinstall": "rimraf node_modules", 27 | "installServer": "installServerIntoExtension ../phpcs ./package.json ./tsconfig.json", 28 | "compile": "installServerIntoExtension ../phpcs ./package.json ./tsconfig.json && tsc -p .", 29 | "watch": "installServerIntoExtension ../phpcs ./package.json ./tsconfig.json && tsc --watch -p .", 30 | "test": "mocha -r ts-node/register --ui tdd --timeout 10000 test/**/*.test.ts", 31 | "clean": "rimraf ../phpcs/server" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phpcs/src/timer.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export class Timer { 8 | 9 | /** 10 | * Frequency of elapse event of the timer in millisecond 11 | */ 12 | public interval = 1000; 13 | 14 | /** 15 | * The function to execute on set interval. 16 | */ 17 | private tick: (...args: any[]) => void; 18 | 19 | /** 20 | * A boolean flag indicating whether the timer is enabled. 21 | */ 22 | private enable: boolean = false; 23 | 24 | /** 25 | * A Number, representing the ID value of the timer that is set. 26 | * Use this value with the clearInterval() method to cancel the timer 27 | */ 28 | private handle: NodeJS.Timer; 29 | 30 | /** 31 | * Class constructor. 32 | * @param tick The function to execute on set interval. 33 | */ 34 | constructor(tick: (...args: any[]) => void) { 35 | this.tick = tick; 36 | } 37 | 38 | /** 39 | * Start the timer. 40 | */ 41 | public start(): void { 42 | this.enable = true; 43 | if (this.enable) { 44 | this.handle = setInterval(this.tick, this.interval); 45 | } 46 | } 47 | 48 | /** 49 | * Stop the timer. 50 | */ 51 | public stop(): void { 52 | this.enable = false; 53 | if (this.handle) { 54 | clearInterval(this.handle); 55 | } 56 | } 57 | 58 | /** 59 | * Dispose the timer. 60 | */ 61 | public dispose(): void { 62 | if (this.handle) { 63 | clearInterval(this.handle); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /phpcs/src/resolvers/path-resolver.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import { PhpcsPathResolverBase } from './path-resolver-base'; 8 | import { ComposerPhpcsPathResolver } from './composer-path-resolver'; 9 | import { GlobalPhpcsPathResolver } from './global-path-resolver'; 10 | 11 | export interface PhpcsPathResolverOptions { 12 | workspaceRoot: string | null; 13 | composerJsonPath: string; 14 | } 15 | 16 | export class PhpcsPathResolver extends PhpcsPathResolverBase { 17 | 18 | private resolvers: PhpcsPathResolverBase[] = []; 19 | 20 | constructor(options: PhpcsPathResolverOptions) { 21 | super(); 22 | if (options.workspaceRoot !== null) { 23 | this.resolvers.push(new ComposerPhpcsPathResolver(options.workspaceRoot, options.composerJsonPath)); 24 | } 25 | this.resolvers.push(new GlobalPhpcsPathResolver()); 26 | } 27 | 28 | async resolve(): Promise { 29 | let resolvedPath: string = null; 30 | for (var i = 0, len = this.resolvers.length; i < len; i++) { 31 | let resolverPath = await this.resolvers[i].resolve(); 32 | if (resolvedPath !== resolverPath) { 33 | resolvedPath = resolverPath; 34 | break; 35 | } 36 | } 37 | if (resolvedPath === null) { 38 | throw new Error('Unable to locate phpcs. Please add phpcs to your global path or use composer dependency manager to install it in your project locally.'); 39 | } 40 | return resolvedPath; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phpcs/src/protocol.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import { 8 | NotificationType, 9 | TextDocumentIdentifier 10 | } from "vscode-languageclient"; 11 | 12 | /** 13 | * The parameters send in a did start validate text document notification 14 | */ 15 | export interface DidStartValidateTextDocumentParams { 16 | /** 17 | * The document on which validation started. 18 | */ 19 | textDocument: TextDocumentIdentifier; 20 | } 21 | 22 | /** 23 | * The document start validation notification is sent from the server to the client to signal 24 | * the start of the validation on text documents. 25 | */ 26 | export namespace DidStartValidateTextDocumentNotification { 27 | export const type = new NotificationType("textDocument/didStartValidate"); 28 | } 29 | 30 | /** 31 | * The parameters send in a did end validate text document notification 32 | */ 33 | export interface DidEndValidateTextDocumentParams { 34 | /** 35 | * The document on which validation ended. 36 | */ 37 | textDocument: TextDocumentIdentifier; 38 | } 39 | 40 | /** 41 | * The document end validation notification is sent from the server to the client to signal 42 | * the end of the validation on text documents. 43 | */ 44 | export namespace DidEndValidateTextDocumentNotification { 45 | export const type = new NotificationType("textDocument/didEndValidate"); 46 | } 47 | -------------------------------------------------------------------------------- /phpcs-server/src/protocol.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import { 8 | NotificationType, 9 | TextDocumentIdentifier 10 | } from "vscode-languageserver"; 11 | 12 | /** 13 | * The parameters send in a did start validate text document notification 14 | */ 15 | export interface DidStartValidateTextDocumentParams { 16 | /** 17 | * The document on which validation started. 18 | */ 19 | textDocument: TextDocumentIdentifier; 20 | } 21 | 22 | /** 23 | * The document start validation notification is sent from the server to the client to signal 24 | * the start of the validation on text documents. 25 | */ 26 | export namespace DidStartValidateTextDocumentNotification { 27 | export const type = new NotificationType("textDocument/didStartValidate"); 28 | } 29 | 30 | /** 31 | * The parameters send in a did end validate text document notification 32 | */ 33 | export interface DidEndValidateTextDocumentParams { 34 | /** 35 | * The document on which validation ended. 36 | */ 37 | textDocument: TextDocumentIdentifier; 38 | } 39 | 40 | /** 41 | * The document end validation notification is sent from the server to the client to signal 42 | * the end of the validation on text documents. 43 | */ 44 | export namespace DidEndValidateTextDocumentNotification { 45 | export const type = new NotificationType("textDocument/didEndValidate"); 46 | } 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpcs", 3 | "description": "PHP CodeSniffer for Visual Studio Code", 4 | "version": "1.0.5", 5 | "author": "Ioannis Kappas", 6 | "publisher": "ikappas", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/ikappas/vscode-phpcs.git" 11 | }, 12 | "scripts": { 13 | "test": "npm-run-all --parallel test:*", 14 | "test:server": "cd phpcs-server && npm test", 15 | "test:client": "cd phpcs && npm test", 16 | "preinstall": "rimraf node_modules", 17 | "postinstall": "npm-run-all --parallel postinstall:*", 18 | "postinstall:server": "cd phpcs-server && npm install", 19 | "postinstall:client": "cd phpcs && npm install", 20 | "compile": "npm-run-all --serial clean:* compile:*", 21 | "compile:server": "cd phpcs-server && npm run installServer && cd .. && tsc -p phpcs-server/tsconfig.json", 22 | "compile:client": "tsc -p phpcs/tsconfig.json", 23 | "watch:server": "cd phpcs-server && npm run installServer && cd .. && tsc -w -p phpcs-server/tsconfig.json", 24 | "watch:client": "tsc -w -p phpcs/tsconfig.json", 25 | "clean": "npm-run-all --parallel clean:*", 26 | "clean:server": "cd phpcs-server && npm run clean", 27 | "clean:client": "cd phpcs && npm run clean" 28 | }, 29 | "devDependencies": { 30 | "@types/cross-spawn": "6.0.0", 31 | "@types/expect": "1.20.2", 32 | "@types/micromatch": "^3.1.0", 33 | "@types/mocha": "2.2.48", 34 | "@types/node": "^8.9.4", 35 | "@types/semver": "^5.5.0", 36 | "mocha": "^5.0.1", 37 | "npm-run-all": "^4.1.2", 38 | "rimraf": "^2.6.2", 39 | "ts-node": "^5.0.0", 40 | "tslint": "^5.9.1", 41 | "typescript": "^2.7.2", 42 | "typescript-formatter": "^7.1.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /phpcs-server/src/base/common/strings.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 'use strict'; 6 | 7 | const _formatRegexp = /{(\d+)}/g; 8 | 9 | /** 10 | * Helper to produce a string with a variable number of arguments. Insert variable segments 11 | * into the string using the {n} notation where N is the index of the argument following the string. 12 | * @param value string to which formatting is applied 13 | * @param args replacements for {n}-entries 14 | */ 15 | export function format(value: string, ...args: any[]): string { 16 | if (args.length === 0) { 17 | return value; 18 | } 19 | return value.replace(_formatRegexp, function (match, group) { 20 | let idx = parseInt(group, 10); 21 | return isNaN(idx) || idx < 0 || idx >= args.length ? 22 | match : 23 | args[idx]; 24 | }); 25 | } 26 | 27 | /** 28 | * Removes all occurrences of needle from the end of haystack. 29 | * @param haystack string to trim 30 | * @param needle the thing to trim 31 | */ 32 | export function rtrim(haystack?: string, needle?: string): string { 33 | if (!haystack || !needle) { 34 | return haystack; 35 | } 36 | 37 | let needleLen = needle.length, 38 | haystackLen = haystack.length; 39 | 40 | if (needleLen === 0 || haystackLen === 0) { 41 | return haystack; 42 | } 43 | 44 | let offset = haystackLen, 45 | idx = -1; 46 | 47 | while (true) { 48 | idx = haystack.lastIndexOf(needle, offset - 1); 49 | if (idx === -1 || idx + needleLen !== offset) { 50 | break; 51 | } 52 | if (idx === 0) { 53 | return ''; 54 | } 55 | offset = idx; 56 | } 57 | 58 | return haystack.substring(0, offset); 59 | } 60 | -------------------------------------------------------------------------------- /phpcs-server/test/base/common/strings.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 'use strict'; 6 | 7 | import * as assert from 'assert'; 8 | const strings = require('../../../src/base/common/strings'); 9 | 10 | suite('Strings', () => { 11 | 12 | test('format', function () { 13 | assert.strictEqual(strings.format('Foo Bar'), 'Foo Bar'); 14 | assert.strictEqual(strings.format('Foo {0} Bar'), 'Foo {0} Bar'); 15 | assert.strictEqual(strings.format('Foo {0} Bar', 'yes'), 'Foo yes Bar'); 16 | assert.strictEqual(strings.format('Foo {0} Bar {0}', 'yes'), 'Foo yes Bar yes'); 17 | assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes'), 'Foo yes Bar {1}{2}'); 18 | assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes', undefined), 'Foo yes Bar undefined{2}'); 19 | assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes', 5, false), 'Foo yes Bar 5false'); 20 | assert.strictEqual(strings.format('Foo {0} Bar. {1}', '(foo)', '.test'), 'Foo (foo) Bar. .test'); 21 | }); 22 | 23 | test('rtrim', function () { 24 | assert.strictEqual(strings.rtrim('foo', 'o'), 'f'); 25 | assert.strictEqual(strings.rtrim('foo', 'f'), 'foo'); 26 | assert.strictEqual(strings.rtrim('http://www.test.de', '.de'), 'http://www.test'); 27 | assert.strictEqual(strings.rtrim('/foo/', '/'), '/foo'); 28 | assert.strictEqual(strings.rtrim('/foo//', '/'), '/foo'); 29 | assert.strictEqual(strings.rtrim('/', ''), '/'); 30 | assert.strictEqual(strings.rtrim('/', '/'), ''); 31 | assert.strictEqual(strings.rtrim('///', '/'), ''); 32 | assert.strictEqual(strings.rtrim('', ''), ''); 33 | assert.strictEqual(strings.rtrim('', '/'), ''); 34 | }); 35 | 36 | }); -------------------------------------------------------------------------------- /phpcs-server/src/strings.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | export class StringResources { 8 | 9 | static readonly DidStartValidateTextDocument: string = 'Linting started on: {0}'; 10 | static readonly DidEndValidateTextDocument: string = 'Linting completed on: {0}'; 11 | 12 | static readonly ComposerDependencyNotFoundError: string = 'Composer phpcs dependency is configured but was not found under {0}. You may need to run "composer install" or set your phpcs.executablePath manually.'; 13 | static readonly UnableToLocatePhpcsError: string = 'Unable to locate phpcs. Please add phpcs to your global path or use composer dependency manager to install it in your project locally.'; 14 | static readonly InvalidVersionStringError: string = 'Invalid version string encountered!'; 15 | static readonly UnknownErrorWhileValidatingTextDocument: string = 'An unknown error occurred while validating: {0}'; 16 | 17 | static readonly CreateLinterErrorDefaultMessage: string = 'Please add phpcs to your global path or use composer dependency manager to install it in your project locally.'; 18 | static readonly CreateLinterError: string = 'Unable to locate phpcs. {0}'; 19 | 20 | static readonly UnknownExecutionError: string = 'Unknown error ocurred. Please verify that {0} returns a valid json object.'; 21 | static readonly CodingStandardNotInstalledError: string = 'The "{0}" coding standard is not installed. Please review your configuration an try again.'; 22 | static readonly InvalidJsonStringError: string = 'The phpcs report contains invalid json. Please review "Diagnosing Common Errors" in the plugin README'; 23 | 24 | static readonly Empty: string = ''; 25 | static readonly Space: string = ' '; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | // A task runner that calls a custom npm script that compiles the extension. 9 | { 10 | "version": "2.0.0", 11 | "tasks": [ 12 | { 13 | "label": "compile", 14 | "group": "build", 15 | "dependsOn": [ 16 | "compile:client", 17 | "compile:server" 18 | ], 19 | "problemMatcher": [] 20 | }, 21 | { 22 | "label": "compile:client", 23 | "type": "npm", 24 | "script": "compile:client", 25 | "group": "build", 26 | "presentation": { 27 | "panel": "dedicated", 28 | "reveal": "never" 29 | }, 30 | "problemMatcher": [ 31 | "$tsc" 32 | ] 33 | }, 34 | { 35 | "label": "compile:server", 36 | "type": "npm", 37 | "script": "compile:server", 38 | "group": "build", 39 | "presentation": { 40 | "panel": "dedicated", 41 | "reveal": "never" 42 | }, 43 | "problemMatcher": [ 44 | "$tsc" 45 | ] 46 | }, 47 | { 48 | "label": "watch", 49 | "group": { 50 | "kind": "build", 51 | "isDefault": true 52 | }, 53 | "dependsOn": [ 54 | "watch:client", 55 | "watch:server" 56 | ], 57 | "problemMatcher": [] 58 | }, 59 | { 60 | "label": "watch:client", 61 | "type": "npm", 62 | "script": "watch:client", 63 | "isBackground": true, 64 | "group": "build", 65 | "presentation": { 66 | "panel": "dedicated", 67 | "reveal": "never" 68 | }, 69 | "problemMatcher": [ 70 | "$tsc-watch" 71 | ] 72 | }, 73 | { 74 | "label": "watch:server", 75 | "type": "npm", 76 | "script": "watch:server", 77 | "isBackground": true, 78 | "group": "build", 79 | "presentation": { 80 | "panel": "dedicated", 81 | "reveal": "never" 82 | }, 83 | "problemMatcher": [ 84 | "$tsc-watch" 85 | ] 86 | } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-phpcs 2 | 3 | [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/pickhardt/maintainers-wanted) 4 | [![Current Version](https://vsmarketplacebadge.apphb.com/version/ikappas.phpcs.svg)](https://marketplace.visualstudio.com/items?itemName=ikappas.phpcs) 5 | [![Install Count](https://vsmarketplacebadge.apphb.com/installs/ikappas.phpcs.svg)](https://marketplace.visualstudio.com/items?itemName=ikappas.phpcs) 6 | [![Open Issues](https://vsmarketplacebadge.apphb.com/rating/ikappas.phpcs.svg)](https://marketplace.visualstudio.com/items?itemName=ikappas.phpcs) 7 | 8 | Integrates [phpcs](https://github.com/squizlabs/PHP_CodeSniffer.git) into [Visual Studio Code](https://code.visualstudio.com/). 9 | 10 | ## Looking for additional maintainers 11 | 12 | Due to current work obligations, I am unable to commit enough time to steadily maintain this project, so I am looking for co-maintainers that are familiar with node.js, typescript and vscode plugin authoring. 13 | 14 | If you want to help maintain this project, please contact me. 15 | 16 | ## Setup Development Version 17 | 18 | - install the [Visual Studio Code](https://code.visualstudio.com/) [npm extension](https://marketplace.visualstudio.com/items?itemName=eg2.vscode-npm-script) 19 | - clone this repository and checkout `develop` branch 20 | - open the cloned repository folder using [Visual Studio Code](https://code.visualstudio.com/) 21 | - run VS Code task `npm install` 22 | 23 | ## Run/Debug Development Version 24 | 25 | To run the development version of the `phpcs` extension: 26 | 27 | - open the cloned repository folder using [Visual Studio Code](https://code.visualstudio.com/) 28 | - select sidebar option `Debug` 29 | - select option `Client + Server` from the Debug drop-down menu 30 | - press `Start Debugging` button or hit F5 31 | 32 | This will launch a new VS Code window named `Extension Development Host`, automatically using the development version of the `phpcs` extension. 33 | 34 | > If you don't have an open php file on your `Extension Development Host` the server debug session will timeout and you will need to relaunch it from the debug panel. 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Extension specific 2 | */out/ 3 | *.vsix 4 | phpcs/server 5 | 6 | # General 7 | . 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | # Windows thumbnail cache files 35 | Thumbs.db 36 | ehthumbs.db 37 | ehthumbs_vista.db 38 | 39 | # Dump file 40 | *.stackdump 41 | 42 | # Folder config file 43 | [Dd]esktop.ini 44 | 45 | # Recycle Bin used on file shares 46 | $RECYCLE.BIN/ 47 | 48 | # Windows Installer files 49 | *.cab 50 | *.msi 51 | *.msm 52 | *.msp 53 | 54 | # Windows shortcuts 55 | *.lnk 56 | 57 | # Logs 58 | logs 59 | *.log 60 | npm-debug.log* 61 | yarn-debug.log* 62 | yarn-error.log* 63 | 64 | # Runtime data 65 | pids 66 | *.pid 67 | *.seed 68 | *.pid.lock 69 | 70 | # Directory for instrumented libs generated by jscoverage/JSCover 71 | lib-cov 72 | 73 | # Coverage directory used by tools like istanbul 74 | coverage 75 | 76 | # nyc test coverage 77 | .nyc_output 78 | 79 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 80 | .grunt 81 | 82 | # Bower dependency directory (https://bower.io/) 83 | bower_components 84 | 85 | # node-waf configuration 86 | .lock-wscript 87 | 88 | # Compiled binary addons (https://nodejs.org/api/addons.html) 89 | build/Release 90 | 91 | # Dependency directories 92 | node_modules/ 93 | jspm_packages/ 94 | 95 | # Typescript v1 declaration files 96 | typings/ 97 | 98 | # Optional npm cache directory 99 | .npm 100 | 101 | # Optional eslint cache 102 | .eslintcache 103 | 104 | # Optional REPL history 105 | .node_repl_history 106 | 107 | # Output of 'npm pack' 108 | *.tgz 109 | 110 | # Yarn Integrity file 111 | .yarn-integrity 112 | 113 | # dotenv environment variables file 114 | .env 115 | -------------------------------------------------------------------------------- /phpcs-server/src/base/node/extfs.ts: -------------------------------------------------------------------------------- 1 | 2 | /*--------------------------------------------------------------------------------------------- 3 | * Copyright (c) Microsoft Corporation. All rights reserved. 4 | * Licensed under the MIT License. See License.txt in the project root for license information. 5 | *--------------------------------------------------------------------------------------------*/ 6 | 'use strict'; 7 | 8 | import * as fs from "fs"; 9 | import * as paths from "path"; 10 | import * as strings from "../common/strings"; 11 | 12 | export function realpathSync(path: string): string { 13 | try { 14 | return fs.realpathSync(path); 15 | } catch (error) { 16 | 17 | // We hit an error calling fs.realpathSync(). Since fs.realpathSync() is doing some path normalization 18 | // we now do a similar normalization and then try again if we can access the path with read 19 | // permissions at least. If that succeeds, we return that path. 20 | // fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is 21 | // to not resolve links but to simply see if the path is read accessible or not. 22 | const normalizedPath = normalizePath(path); 23 | fs.accessSync(normalizedPath, fs.constants.R_OK); // throws in case of an error 24 | 25 | return normalizedPath; 26 | } 27 | } 28 | 29 | function normalizePath(path: string): string { 30 | return strings.rtrim(paths.normalize(path), paths.sep); 31 | } 32 | 33 | export async function findAsync(parent: string, directory: string, name: string | Array): Promise { 34 | 35 | if (typeof parent !== 'string') { 36 | throw new Error('Invalid or no `parent` provided'); 37 | } else if (typeof directory !== 'string') { 38 | throw new Error('Invalid or no `directory` provided'); 39 | } else if (typeof name !== 'string' && !(name instanceof Array)) { 40 | throw new Error('Invalid or no `name` provided'); 41 | } 42 | 43 | const names = [].concat(name); 44 | const chunks = paths.resolve(parent, directory).split(paths.sep); 45 | 46 | while (chunks.length) { 47 | let currentDir = chunks.join(paths.sep); 48 | for (const fileName of names) { 49 | const filePath = paths.join(currentDir, fileName); 50 | if (fs.existsSync(filePath)) { 51 | return filePath; 52 | } 53 | } 54 | if (parent === currentDir) { 55 | break; 56 | } 57 | chunks.pop(); 58 | } 59 | 60 | return null; 61 | } 62 | -------------------------------------------------------------------------------- /phpcs/src/status.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import { 8 | StatusBarAlignment, 9 | StatusBarItem, 10 | window 11 | } from "vscode"; 12 | 13 | import { Timer } from './timer'; 14 | 15 | export class PhpcsStatus { 16 | 17 | private statusBarItem: StatusBarItem; 18 | private documents: string[] = []; 19 | private processing: number = 0; 20 | private spinnerIndex = 0; 21 | private spinnerSequence: string[] = ["|", "/", "-", "\\"]; 22 | private timer: Timer; 23 | 24 | public startProcessing(uri: string) { 25 | this.documents.push(uri); 26 | this.processing += 1; 27 | this.getTimer().start(); 28 | this.getStatusBarItem().show(); 29 | } 30 | 31 | public endProcessing(uri: string) { 32 | this.processing -= 1; 33 | let index = this.documents.indexOf(uri); 34 | if (index !== undefined) { 35 | this.documents.slice(index, 1); 36 | } 37 | if (this.processing === 0) { 38 | this.getTimer().stop(); 39 | this.getStatusBarItem().hide(); 40 | this.updateStatusText(); 41 | } 42 | } 43 | 44 | private updateStatusText(): void { 45 | let statusBar = this.getStatusBarItem(); 46 | let count = this.processing; 47 | if (count > 0) { 48 | let spinner = this.getNextSpinnerChar(); 49 | statusBar.text = count === 1 ? `$(eye) phpcs is linting 1 document ... ${spinner}` : `$(eye) phpcs is linting ${count} documents ... ${spinner}`; 50 | } else { 51 | statusBar.text = ""; 52 | } 53 | } 54 | 55 | private getNextSpinnerChar(): string { 56 | let spinnerChar = this.spinnerSequence[this.spinnerIndex]; 57 | this.spinnerIndex += 1; 58 | if (this.spinnerIndex > this.spinnerSequence.length - 1) { 59 | this.spinnerIndex = 0; 60 | } 61 | return spinnerChar; 62 | } 63 | 64 | private getTimer(): Timer { 65 | if (!this.timer) { 66 | this.timer = new Timer(() => { 67 | this.updateStatusText(); 68 | }); 69 | this.timer.interval = 100; 70 | } 71 | return this.timer; 72 | } 73 | 74 | private getStatusBarItem(): StatusBarItem { 75 | // Create as needed 76 | if (!this.statusBarItem) { 77 | this.statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left); 78 | } 79 | return this.statusBarItem; 80 | } 81 | 82 | dispose() { 83 | if (this.statusBarItem) { 84 | this.statusBarItem.dispose(); 85 | } 86 | if (this.timer) { 87 | this.timer.dispose(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /phpcs/src/extension.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import * as path from "path"; 8 | import * as proto from "./protocol"; 9 | 10 | import { 11 | CancellationToken, 12 | ExtensionContext, 13 | workspace 14 | } from "vscode"; 15 | 16 | import { 17 | LanguageClient, 18 | LanguageClientOptions, 19 | Middleware, 20 | Proposed, 21 | ProposedFeatures, 22 | ServerOptions, 23 | TransportKind 24 | } from "vscode-languageclient"; 25 | 26 | import { PhpcsStatus } from "./status"; 27 | import { PhpcsConfiguration } from "./configuration"; 28 | 29 | export function activate(context: ExtensionContext) { 30 | 31 | let client: LanguageClient; 32 | let config: PhpcsConfiguration; 33 | 34 | // The server is implemented in node 35 | let serverModule = context.asAbsolutePath(path.join("server", "src", "server.js")); 36 | 37 | // The debug options for the server 38 | let debugOptions = { execArgv: ["--nolazy", "--inspect=6199"] }; 39 | 40 | // If the extension is launch in debug mode the debug server options are use 41 | // Otherwise the run options are used 42 | let serverOptions: ServerOptions = { 43 | run: { module: serverModule, transport: TransportKind.ipc }, 44 | debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions } 45 | }; 46 | 47 | let middleware: ProposedFeatures.ConfigurationMiddleware | Middleware = { 48 | workspace: { 49 | configuration: async (params: Proposed.ConfigurationParams, token: CancellationToken, next: Function) => { 50 | return config.compute(params, token, next); 51 | } 52 | } 53 | }; 54 | 55 | // Options to control the language client 56 | let clientOptions: LanguageClientOptions = { 57 | // Register the server for php documents 58 | documentSelector: ["php"], 59 | synchronize: { 60 | // Notify the server about file changes to 'ruleset.xml' files contain in the workspace 61 | fileEvents: workspace.createFileSystemWatcher("**/ruleset.xml") 62 | }, 63 | middleware: middleware as Middleware 64 | }; 65 | 66 | // Create the language client. 67 | client = new LanguageClient("phpcs", "PHP Code Sniffer", serverOptions, clientOptions); 68 | 69 | // Register new proposed protocol if available. 70 | client.registerProposedFeatures(); 71 | 72 | config = new PhpcsConfiguration(client); 73 | 74 | // Create the status monitor. 75 | let status = new PhpcsStatus(); 76 | client.onReady().then(() => { 77 | config.initialize(); 78 | client.onNotification(proto.DidStartValidateTextDocumentNotification.type, event => { 79 | status.startProcessing(event.textDocument.uri); 80 | }); 81 | client.onNotification(proto.DidEndValidateTextDocumentNotification.type, event => { 82 | status.endProcessing(event.textDocument.uri); 83 | }); 84 | }); 85 | 86 | client.start(); 87 | 88 | // Push the monitor to the context's subscriptions so that the 89 | // client can be deactivated on extension deactivation 90 | context.subscriptions.push(status); 91 | context.subscriptions.push(config); 92 | } 93 | -------------------------------------------------------------------------------- /phpcs/src/configuration.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import * as path from "path"; 8 | 9 | import { 10 | CancellationToken, 11 | Disposable, 12 | Uri, 13 | workspace, 14 | WorkspaceConfiguration, 15 | WorkspaceFolder 16 | } from "vscode"; 17 | 18 | import { 19 | DidChangeConfigurationNotification, 20 | LanguageClient, 21 | Proposed, 22 | } from "vscode-languageclient"; 23 | 24 | import { PhpcsSettings } from "./settings"; 25 | import { PhpcsPathResolver } from "./resolvers/path-resolver"; 26 | 27 | export class PhpcsConfiguration extends Disposable { 28 | 29 | private client: LanguageClient; 30 | private disposables: Array = []; 31 | private globalSettings: PhpcsSettings; 32 | private folderSettings: Map = new Map(); 33 | 34 | /** 35 | * Class constructor 36 | * @param client The client to use. 37 | */ 38 | public constructor(client: LanguageClient) { 39 | super(() => { 40 | this.disposables.map(o => { o.dispose(); }); 41 | this.client = null; 42 | }); 43 | 44 | this.client = client; 45 | } 46 | 47 | // Convert VS Code specific settings to a format acceptable by the server. Since 48 | // both client and server do use JSON the conversion is trivial. 49 | public async compute(params: Proposed.ConfigurationParams, _token: CancellationToken, _next: Function): Promise { 50 | if (!params.items) { 51 | return null; 52 | } 53 | let result: (PhpcsSettings | null)[] = []; 54 | for (let item of params.items) { 55 | // The server asks the client for configuration settings without a section 56 | // If a section is present we return null to indicate that the configuration 57 | // is not supported. 58 | if (item.section) { 59 | result.push(null); 60 | continue; 61 | } 62 | 63 | let config: WorkspaceConfiguration; 64 | let folder: WorkspaceFolder; 65 | if (item.scopeUri) { 66 | let resource = this.client.protocol2CodeConverter.asUri(item.scopeUri); 67 | folder = workspace.getWorkspaceFolder(resource); 68 | } 69 | 70 | if (folder) { 71 | if (this.folderSettings.has(folder.uri)) { 72 | result.push(this.folderSettings.get(folder.uri)); 73 | continue; 74 | } 75 | config = workspace.getConfiguration('phpcs', folder.uri); 76 | } else { 77 | if (this.globalSettings) { 78 | result.push(this.globalSettings); 79 | continue; 80 | } 81 | config = workspace.getConfiguration('phpcs'); 82 | } 83 | 84 | let settings: PhpcsSettings = { 85 | enable: config.get('enable'), 86 | workspaceRoot: folder ? folder.uri.fsPath : null, 87 | executablePath: config.get('executablePath'), 88 | composerJsonPath: config.get('composerJsonPath'), 89 | standard: config.get('standard'), 90 | autoConfigSearch: config.get('autoConfigSearch'), 91 | showSources: config.get('showSources'), 92 | showWarnings: config.get('showWarnings'), 93 | ignorePatterns: config.get('ignorePatterns'), 94 | warningSeverity: config.get('warningSeverity'), 95 | errorSeverity: config.get('errorSeverity'), 96 | }; 97 | 98 | settings = await this.resolveExecutablePath(settings); 99 | 100 | if (folder) { 101 | this.folderSettings.set(folder.uri, settings); 102 | } else { 103 | this.globalSettings = settings; 104 | } 105 | 106 | result.push(settings); 107 | } 108 | return result; 109 | } 110 | 111 | protected async resolveExecutablePath(settings: PhpcsSettings): Promise { 112 | if (settings.executablePath === null) { 113 | let executablePathResolver = new PhpcsPathResolver(settings); 114 | settings.executablePath = await executablePathResolver.resolve(); 115 | } else if (!path.isAbsolute(settings.executablePath) && settings.workspaceRoot !== null) { 116 | settings.executablePath = path.join(settings.workspaceRoot, settings.executablePath); 117 | } 118 | return settings; 119 | } 120 | 121 | public initialize(): void { 122 | // VS Code currently doesn't sent fine grained configuration changes. So we 123 | // listen to any change. However this will change in the near future. 124 | this.disposables.push(workspace.onDidChangeConfiguration(() => { 125 | this.folderSettings.clear(); 126 | this.globalSettings = null; 127 | this.client.sendNotification(DidChangeConfigurationNotification.type, { settings: null }); 128 | })); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /phpcs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpcs", 3 | "description": "PHP CodeSniffer for Visual Studio Code", 4 | "version": "1.0.5", 5 | "author": "Ioannis Kappas", 6 | "publisher": "ikappas", 7 | "license": "MIT", 8 | "galleryBanner": { 9 | "color": "#6082bb", 10 | "theme": "dark" 11 | }, 12 | "icon": "phpcs_icon.png", 13 | "homepage": "https://github.com/ikappas/vscode-phpcs/blob/master/README.md", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/ikappas/vscode-phpcs.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/ikappas/vscode-phpcs/issues" 20 | }, 21 | "categories": [ 22 | "Languages", 23 | "Linters" 24 | ], 25 | "engines": { 26 | "vscode": "^1.20.0" 27 | }, 28 | "activationEvents": [ 29 | "onLanguage:php" 30 | ], 31 | "main": "./out/src/extension", 32 | "contributes": { 33 | "configuration": { 34 | "type": "object", 35 | "title": "PHP CodeSniffer configuration", 36 | "properties": { 37 | "phpcs.enable": { 38 | "scope": "resource", 39 | "type": "boolean", 40 | "default": true, 41 | "description": "Control whether phpcs is enabled for PHP files or not." 42 | }, 43 | "phpcs.executablePath": { 44 | "scope": "resource", 45 | "type": "string", 46 | "default": null, 47 | "description": "Optional. The path to the phpcs executable." 48 | }, 49 | "phpcs.composerJsonPath": { 50 | "scope": "resource", 51 | "type": "string", 52 | "default": "composer.json", 53 | "description": "The path to composer.json" 54 | }, 55 | "phpcs.standard": { 56 | "scope": "resource", 57 | "type": [ 58 | "string", 59 | "null" 60 | ], 61 | "default": null, 62 | "description": "Optional. The name or path of the coding standard to use. Defaults to the one set in phpcs global config." 63 | }, 64 | "phpcs.autoConfigSearch": { 65 | "scope": "resource", 66 | "type": "boolean", 67 | "default": true, 68 | "description": "Automatically search for any `phpcs.xml`, `phpcs.xml.dist`, `phpcs.ruleset.xml` or `ruleset.xml` file to use as configuration. Overrides custom standards defined above." 69 | }, 70 | "phpcs.ignorePatterns": { 71 | "scope": "resource", 72 | "type": "array", 73 | "items": { 74 | "type": "string", 75 | "title": "A glob pattern to skip files and folders that match." 76 | }, 77 | "default": [], 78 | "description": "An array of glob patterns to skip files and folders that match when linting your documents." 79 | }, 80 | "phpcs.errorSeverity": { 81 | "scope": "resource", 82 | "type": "number", 83 | "default": 5, 84 | "minimum": 0, 85 | "description": "The minimum severity an error must have to be displayed." 86 | }, 87 | "phpcs.warningSeverity": { 88 | "scope": "resource", 89 | "type": "number", 90 | "default": 5, 91 | "minimum": 0, 92 | "description": "The minimum severity a warning must have to be displayed." 93 | }, 94 | "phpcs.showWarnings": { 95 | "scope": "resource", 96 | "type": "boolean", 97 | "default": true, 98 | "description": "Control whether warnings are displayed." 99 | }, 100 | "phpcs.showSources": { 101 | "scope": "resource", 102 | "type": "boolean", 103 | "default": false, 104 | "description": "Show sniff source codes in diagnostic messages." 105 | }, 106 | "phpcs.trace.server": { 107 | "scope": "window", 108 | "type": "string", 109 | "enum": [ 110 | "off", 111 | "messages", 112 | "verbose" 113 | ], 114 | "default": "off", 115 | "description": "Traces the communication between VSCode and the language server." 116 | } 117 | } 118 | } 119 | }, 120 | "scripts": { 121 | "vscode:prepublish": "tsc -p ./", 122 | "compile": "tsc -watch -p ./", 123 | "update-vscode": "node ./node_modules/vscode/bin/install", 124 | "preinstall": "rimraf node_modules", 125 | "postinstall": "node ./node_modules/vscode/bin/install", 126 | "test": "mocha -r ts-node/register --ui tdd --timeout 10000 test/**/*.test.ts", 127 | "clean": "rimraf out" 128 | }, 129 | "dependencies": { 130 | "vscode": "^1.1.10", 131 | "vscode-languageclient": "^3.5.0" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /phpcs/src/resolvers/composer-path-resolver.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import * as path from 'path'; 8 | import * as fs from 'fs'; 9 | 10 | import { PhpcsPathResolverBase } from './path-resolver-base'; 11 | 12 | export class ComposerPhpcsPathResolver extends PhpcsPathResolverBase { 13 | 14 | protected readonly _workspaceRoot: string; 15 | protected readonly _workingPath: string; 16 | 17 | protected _composerJsonPath: string; 18 | protected _composerLockPath: string; 19 | 20 | /** 21 | * Class constructor. 22 | * 23 | * @param workspaceRoot The workspace path. 24 | * @param composerJsonPath The path to composer.json. 25 | */ 26 | constructor(workspaceRoot: string, workingPath?: string) { 27 | super(); 28 | this._workspaceRoot = workspaceRoot; 29 | this._workingPath = path.isAbsolute(workingPath) 30 | ? workingPath 31 | : path.join(workspaceRoot, workingPath).replace(/composer.json$/, ''); 32 | } 33 | 34 | public get workspaceRoot(): string { 35 | return this._workspaceRoot; 36 | } 37 | 38 | public get workingPath(): string { 39 | return this._workingPath; 40 | } 41 | 42 | public get composerJsonPath(): string { 43 | if (!this._composerJsonPath) { 44 | this._composerJsonPath = fs.realpathSync(path.join(this.workingPath, 'composer.json')); 45 | } 46 | return this._composerJsonPath; 47 | } 48 | 49 | public get composerLockPath(): string { 50 | if (!this._composerLockPath) { 51 | this._composerLockPath = fs.realpathSync(path.join(this.workingPath, 'composer.lock')); 52 | } 53 | return this._composerLockPath; 54 | } 55 | 56 | /** 57 | * Determine whether composer.json exists at the root path. 58 | */ 59 | hasComposerJson(): boolean { 60 | try { 61 | return fs.existsSync(this.composerJsonPath); 62 | } catch (error) { 63 | return false; 64 | } 65 | } 66 | 67 | /** 68 | * Determine whether composer.lock exists at the root path. 69 | */ 70 | hasComposerLock(): boolean { 71 | try { 72 | return fs.existsSync(this.composerLockPath); 73 | } catch (error) { 74 | return false; 75 | } 76 | } 77 | 78 | /** 79 | * Determine whether phpcs is set as a composer dependency. 80 | */ 81 | hasComposerDependency(): boolean { 82 | // Safely load composer.lock 83 | let dependencies = null; 84 | try { 85 | dependencies = JSON.parse(fs.readFileSync(this.composerLockPath, "utf8")); 86 | } catch (error) { 87 | dependencies = {}; 88 | } 89 | 90 | // Determine phpcs dependency. 91 | let search = []; 92 | if (dependencies["packages-dev"]) { 93 | search.push(dependencies["packages-dev"]); 94 | } 95 | if (dependencies["packages"]) { 96 | search.push(dependencies["packages"]); 97 | } 98 | 99 | return search.some(pkgs => { 100 | let match = pkgs.filter((pkg: any) => { 101 | return pkg.name === "squizlabs/php_codesniffer"; 102 | }); 103 | return match.length !== 0; 104 | }); 105 | } 106 | 107 | /** 108 | * Get the composer vendor path. 109 | */ 110 | getVendorPath(): string { 111 | let basePath = path.dirname(this.composerJsonPath); 112 | let vendorPath = path.join(basePath, "vendor", "bin", this.phpcsExecutableFile); 113 | 114 | // Safely load composer.json 115 | let config = null; 116 | try { 117 | config = JSON.parse(fs.readFileSync(this.composerJsonPath, "utf8")); 118 | } 119 | catch (error) { 120 | config = {}; 121 | } 122 | 123 | // Check vendor-bin configuration 124 | if (config["config"] && config["config"]["vendor-dir"]) { 125 | vendorPath = path.join(basePath, config["config"]["vendor-dir"], "bin", this.phpcsExecutableFile); 126 | } 127 | 128 | // Check bin-bin configuration 129 | if (config["config"] && config["config"]["bin-dir"]) { 130 | vendorPath = path.join(basePath, config["config"]["bin-dir"], this.phpcsExecutableFile); 131 | } 132 | 133 | return vendorPath; 134 | } 135 | 136 | async resolve(): Promise { 137 | let resolvedPath = null; 138 | if (this.workspaceRoot) { 139 | // Determine whether composer.json and composer.lock exist and phpcs is defined as a dependency. 140 | if (this.hasComposerJson() && this.hasComposerLock() && this.hasComposerDependency()) { 141 | let vendorPath = this.getVendorPath(); 142 | if (fs.existsSync(vendorPath)) { 143 | resolvedPath = vendorPath; 144 | } else { 145 | let relativeVendorPath = path.relative(this.workspaceRoot, vendorPath); 146 | throw new Error(`Composer phpcs dependency is configured but was not found under ${relativeVendorPath}. You may need to run "composer install" or set your phpcs.executablePath manually.`); 147 | } 148 | } 149 | } 150 | return resolvedPath; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /phpcs/README.md: -------------------------------------------------------------------------------- 1 | # vscode-phpcs 2 | 3 | This linter plugin for [Visual Studio Code](https://code.visualstudio.com/) provides an interface to [phpcs](http://pear.php.net/package/PHP_CodeSniffer/). It will be used with files that have the “PHP” language mode. 4 | 5 | ## Installation 6 | 7 | Visual Studio Code must be installed in order to use this plugin. If Visual Studio Code is not installed, please follow the instructions [here](https://code.visualstudio.com/Docs/editor/setup). 8 | 9 | ## Linter Installation 10 | 11 | Before using this plugin, you must ensure that `phpcs` is installed on your system. The preferred method is using [composer](https://getcomposer.org/) for both system-wide and project-wide installations. 12 | 13 | Once phpcs is installed, you can proceed to install the vscode-phpcs plugin if it is not yet installed. 14 | 15 | > **NOTE:** This plugin can detect whether your project has been set up to use phpcs via composer and use the project specific `phpcs` over the system-wide installation of `phpcs` automatically. This feature requires that both composer.json and composer.lock file exist in your workspace root or the `phpcs.composerJsonPath` in order to check for the composer dependency. If you wish to bypass this feature you can set the `phpcs.executablePath` configuration setting. 16 | 17 | > **NOTE:** You can also install `phpcs` on your system using [pear](http://pear.php.net/) or even manually but is beyond the scope of this plugin. 18 | 19 | ### System-wide Installation 20 | 21 | The `phpcs` linter can be installed globally using the Composer Dependency Manager for PHP. 22 | 23 | 1. Install [composer](https://getcomposer.org/doc/00-intro.md). 24 | 1. Require `phpcs` package by typing the following in a terminal: 25 | 26 | ```bash 27 | composer global require squizlabs/php_codesniffer 28 | ``` 29 | 30 | ### Project-wide Installation 31 | 32 | The `phpcs` linter can be installed in your project using the Composer Dependency Manager for PHP. 33 | 34 | 1. Install [composer](https://getcomposer.org/doc/00-intro.md). 35 | 1. Require `phpcs` package by typing the following at the root of your project in a terminal: 36 | 37 | ```bash 38 | composer require --dev squizlabs/php_codesniffer 39 | ``` 40 | 41 | ### Plugin Installation 42 | 43 | 1. Open Visual Studio Code. 44 | 1. Press `Ctrl+P` on Windows or `Cmd+P` on Mac to open the Quick Open dialog. 45 | 1. Type ext install phpcs to find the extension. 46 | 1. Press Enter or click the cloud icon to install it. 47 | 1. Restart Visual Studio Code when prompted. 48 | 49 | ## Basic Configuration 50 | 51 | There are various options that can be configured to control how the plugin operates which can be set 52 | in your user, workspace or folder preferences. 53 | 54 | ### **phpcs.enable** 55 | 56 | [ *Scope:* All | Optional | *Type:* boolean | *Default:* true ] 57 | 58 | This setting controls whether `phpcs` linting is enabled. 59 | 60 | ### **phpcs.executablePath** 61 | 62 | [ *Scope:* All | Optional | *Type:* string | *Default:* null ] 63 | 64 | This setting controls the executable path for the `phpcs`. You may specify the absolute path or workspace relative path to the `phpcs` executable. 65 | If omitted, the plugin will try to locate the path parsing your composer configuration or the global path. 66 | 67 | ### **phpcs.standard** 68 | 69 | [ *Scope:* All | Optional | *Type:* string | *Default:* null ] 70 | 71 | This setting controls the coding standard used by `phpcs`. You may specify the name, absolute path or workspace relative path of the coding standard to use. 72 | 73 | > **NOTE:** While using composer dependency manager over global installation make sure you use the phpcs commands under your project scope ! 74 | 75 | The following values are applicable: 76 | 77 | 1. This setting can be set to `null`, which is the default behavior and uses the `default_standard` when set in the `phpcs` configuration or fallback to the `Pear` coding standard. 78 | 79 | ```json 80 | { 81 | "phpcs.standard": null 82 | } 83 | ``` 84 | 85 | You may set the `default_standard` used by phpcs using the following command: 86 | 87 | ```bash 88 | phpcs --config-set default_standard 89 | ``` 90 | 91 | or when using composer dependency manager from the root of your project issue the following command: 92 | 93 | ```bash 94 | ./vendor/bin/phpcs --config-set default_standard 95 | ``` 96 | 97 | 1. The setting can be set to the name of a built-in coding standard ( ie. `MySource`, `PEAR`, `PHPCS`, `PSR1`, `PSR2`, `Squiz`, `Zend` ) and you are good to go. 98 | 99 | ```json 100 | { 101 | "phpcs.standard": "PSR2" 102 | } 103 | ``` 104 | 105 | 1. The setting can me set to the name of a custom coding standard ( ie. `WordPress`, `Drupal`, etc. ). In this case you must ensure that the specified coding standard is installed and accessible by `phpcs`. 106 | 107 | ```json 108 | { 109 | "phpcs.standard": "WordPress" 110 | } 111 | ``` 112 | 113 | After you install the custom coding standard, you can make it available to phpcs by issuing the following command: 114 | 115 | ```bash 116 | phpcs --config-set installed_paths 117 | ``` 118 | 119 | or when using composer dependency manager from the root of your project issue the following command: 120 | 121 | ```bash 122 | ./vendor/bin/phpcs --config-set installed_paths 123 | ``` 124 | 125 | 1. The setting can be set to the absolute path to a custom coding standard: 126 | 127 | ```json 128 | { 129 | "phpcs.standard": "/path/to/coding/standard" 130 | } 131 | ``` 132 | 133 | or you can use the path to a custom ruleset: 134 | 135 | ```json 136 | { 137 | "phpcs.standard": "/path/to/project/phpcs.xml" 138 | } 139 | ``` 140 | 141 | 1. The setting can be set to your workspace relative path to a custom coding standard: 142 | 143 | ```json 144 | { 145 | "phpcs.standard": "./vendor/path/to/coding/standard" 146 | } 147 | ``` 148 | 149 | or you can use the path to your project's custom ruleset: 150 | 151 | ```json 152 | { 153 | "phpcs.standard": "./phpcs.xml" 154 | } 155 | ``` 156 | 157 | ### **phpcs.autoConfigSearch** 158 | 159 | [ *Scope:* All | Optional | *Type:* boolean | *Default:* true ] 160 | 161 | Automatically search for any `phpcs.xml`, `phpcs.xml.dist`, `phpcs.ruleset.xml` or `ruleset.xml` file to use as configuration. Overrides `phpcs.standard` configuration when a ruleset is found. 162 | 163 | > **NOTE:** This option does not apply for unsaved documents (in-memory). 164 | 165 | ### **phpcs.ignorePatterns** 166 | 167 | [ *Scope:* All | Optional | *Type:* array | *Default:* [] ] 168 | 169 | An array of glob patterns to skip files and folders that match when linting your documents. 170 | 171 | ```json 172 | { 173 | "phpcs.ignorePatterns": [ 174 | "*/ignored-file.php", 175 | "*/ignored-dir/*" 176 | ] 177 | } 178 | ``` 179 | 180 | ### **phpcs.errorSeverity** 181 | 182 | [ *Scope:* All | Optional | *Type:* number | *Default:* 5 ] 183 | 184 | The minimum severity an error must have to be displayed. You may specify an integer value. 185 | 186 | ### **phpcs.warningSeverity** 187 | 188 | [ *Scope:* All | Optional | *Type:* number | *Default:* 5 ] 189 | 190 | The minimum severity a warning must have to be displayed. You may specify an integer value. 191 | 192 | ### **phpcs.showWarnings** 193 | 194 | [ *Scope:* All | Optional | *Type:* boolean | *Default:* true ] 195 | 196 | Control whether warnings are displayed. 197 | 198 | ### **phpcs.showSources** 199 | 200 | [ *Scope:* All | Optional | *Type:* boolean | *Default:* false ] 201 | 202 | Show sniff source codes in diagnostic messages. 203 | 204 | ### **phpcs.trace.server** 205 | 206 | [ *Scope:* User | Optional | *Type:* string | *Default:* off ] 207 | 208 | This setting controls whether the trace server is activated. Possible values you can use is `off`, `messages` or `verbose`. 209 | 210 | ## Advanced Configuration 211 | 212 | ### **phpcs.composerJsonPath** 213 | 214 | [ *Scope:* All | Optional | *Type:* string | *Default:* composer.json ] 215 | 216 | This setting allows you to override the path to your composer.json file when it does not reside at the workspace root. You may specify the absolute path or workspace relative path to the `composer.json` file. 217 | 218 | ## Diagnosing common errors 219 | 220 | ### The phpcs report contains invalid json 221 | 222 | This error occurs when something goes wrong in phpcs execution such as PHP Notices, PHP Fatal Exceptions, Other Script Output, etc, most of which can be detected as follows: 223 | 224 | Execute the phpcs command in your terminal with --report=json and see whether the output contains anything other than valid json. 225 | 226 | > **NOTE:** The '-q' parameter is automatically passed on phpcs v.2.6.2 and above to suppress such errors. Please update `phpcs` to a version >=2.6.2. 227 | 228 | ## Acknowledgements 229 | 230 | The extension architecture is based off of the [Language Server Node Example](https://github.com/Microsoft/vscode-languageserver-node-example). 231 | 232 | Additional inspiration comes from [Atom Linter-phpcs](https://github.com/AtomLinter/linter-phpcs). 233 | 234 | ## Contributing and Licensing 235 | 236 | The project is hosted on [GitHub](https://github.com/ikappas/vscode-phpcs) where you can [report issues](https://github.com/ikappas/vscode-phpcs/issues), fork 237 | the project and submit pull requests. 238 | 239 | The project is available under [MIT license](https://github.com/ikappas/vscode-phpcs/blob/master/LICENSE.md), which allows modification and 240 | redistribution for both commercial and non-commercial purposes. 241 | -------------------------------------------------------------------------------- /phpcs-server/src/linter.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | import * as cp from "child_process"; 7 | import * as extfs from "./base/node/extfs"; 8 | import * as mm from "micromatch"; 9 | import * as os from "os"; 10 | import * as path from "path"; 11 | import * as semver from "semver"; 12 | import * as spawn from "cross-spawn"; 13 | import * as strings from "./base/common/strings"; 14 | import CharCode from "./base/common/charcode"; 15 | 16 | import { 17 | Diagnostic, 18 | DiagnosticSeverity, 19 | Files, 20 | Range, 21 | TextDocument 22 | } from "vscode-languageserver"; 23 | 24 | import { StringResources as SR } from "./strings"; 25 | import { PhpcsSettings } from "./settings"; 26 | import { PhpcsMessage } from "./message"; 27 | 28 | export class PhpcsLinter { 29 | 30 | private executablePath: string; 31 | private executableVersion: string; 32 | private ignorePatternReplacements: Map; 33 | 34 | private constructor(executablePath: string, executableVersion: string) { 35 | this.executablePath = executablePath; 36 | this.executableVersion = executableVersion; 37 | } 38 | 39 | /** 40 | * Create an instance of the PhpcsLinter. 41 | */ 42 | static async create(executablePath: string): Promise { 43 | try { 44 | 45 | let result: Buffer = cp.execSync(`"${executablePath}" --version`); 46 | 47 | const versionPattern: RegExp = /^PHP_CodeSniffer version (\d+\.\d+\.\d+)/i; 48 | const versionMatches = result.toString().match(versionPattern); 49 | 50 | if (versionMatches === null) { 51 | throw new Error(SR.InvalidVersionStringError); 52 | } 53 | 54 | const executableVersion = versionMatches[1]; 55 | return new PhpcsLinter(executablePath, executableVersion); 56 | 57 | } catch (error) { 58 | let message = error.message ? error.message : SR.CreateLinterErrorDefaultMessage; 59 | throw new Error(strings.format(SR.CreateLinterError, message)); 60 | } 61 | } 62 | 63 | public async lint(document: TextDocument, settings: PhpcsSettings): Promise { 64 | 65 | const { workspaceRoot } = settings; 66 | 67 | // Process linting paths. 68 | let filePath = Files.uriToFilePath(document.uri); 69 | 70 | // Make sure we capitalize the drive letter in paths on Windows. 71 | if (filePath !== undefined && /^win/.test(process.platform)) { 72 | let pathRoot: string = path.parse(filePath).root; 73 | let noDrivePath = filePath.slice(Math.max(pathRoot.length - 1, 0)); 74 | filePath = path.join(pathRoot.toUpperCase(), noDrivePath); 75 | } 76 | 77 | let fileText = document.getText(); 78 | 79 | // Return empty on empty text. 80 | if (fileText === '') { 81 | return []; 82 | } 83 | 84 | // Process linting arguments. 85 | let lintArgs = ['--report=json']; 86 | 87 | // -q (quiet) option is available since phpcs 2.6.2 88 | if (semver.gte(this.executableVersion, '2.6.2')) { 89 | lintArgs.push('-q'); 90 | } 91 | 92 | // Show sniff source codes in report output. 93 | if (settings.showSources === true) { 94 | lintArgs.push('-s'); 95 | } 96 | 97 | // --encoding option is available since 1.3.0 98 | if (semver.gte(this.executableVersion, '1.3.0')) { 99 | lintArgs.push('--encoding=UTF-8'); 100 | } 101 | 102 | // Check if a config file exists and handle it 103 | let standard: string; 104 | if (settings.autoConfigSearch && workspaceRoot !== null && filePath !== undefined) { 105 | const confFileNames = [ 106 | '.phpcs.xml', '.phpcs.xml.dist', 'phpcs.xml', 'phpcs.xml.dist', 107 | 'phpcs.ruleset.xml', 'ruleset.xml', 108 | ]; 109 | 110 | const fileDir = path.relative(workspaceRoot, path.dirname(filePath)); 111 | 112 | const confFile = !settings.ignorePatterns.some(pattern => this.isIgnorePatternMatch(filePath, pattern)) 113 | ? await extfs.findAsync(workspaceRoot, fileDir, confFileNames) 114 | : null; 115 | 116 | standard = confFile || settings.standard; 117 | } else { 118 | standard = settings.standard; 119 | } 120 | 121 | if (standard) { 122 | lintArgs.push(`--standard=${standard}`); 123 | } 124 | 125 | // Check if file should be ignored (Skip for in-memory documents) 126 | if (filePath !== undefined && settings.ignorePatterns.length) { 127 | if (semver.gte(this.executableVersion, '3.0.0')) { 128 | // PHPCS v3 and up support this with STDIN files 129 | lintArgs.push(`--ignore=${settings.ignorePatterns.join()}`); 130 | } else if (settings.ignorePatterns.some(pattern => this.isIgnorePatternMatch(filePath, pattern))) { 131 | // We must determine this ourself for lower versions 132 | return []; 133 | } 134 | } 135 | 136 | lintArgs.push(`--error-severity=${settings.errorSeverity}`); 137 | 138 | let warningSeverity = settings.warningSeverity; 139 | if (settings.showWarnings === false) { 140 | warningSeverity = 0; 141 | } 142 | lintArgs.push(`--warning-severity=${warningSeverity}`); 143 | 144 | let text = fileText; 145 | 146 | // Determine the method of setting the file name 147 | if (filePath !== undefined) { 148 | switch (true) { 149 | 150 | // PHPCS 2.6 and above support sending the filename in a flag 151 | case semver.gte(this.executableVersion, '2.6.0'): 152 | lintArgs.push(`--stdin-path=${filePath}`); 153 | break; 154 | 155 | // PHPCS 2.x.x before 2.6.0 supports putting the name in the start of the stream 156 | case semver.satisfies(this.executableVersion, '>=2.0.0 <2.6.0'): 157 | // TODO: This needs to be document specific. 158 | const eolChar = os.EOL; 159 | text = `phpcs_input_file: ${filePath}${eolChar}${fileText}`; 160 | break; 161 | 162 | // PHPCS v1 supports stdin, but ignores all filenames. 163 | default: 164 | // Nothing to do 165 | break; 166 | } 167 | } 168 | 169 | // Finish off the parameter list 170 | lintArgs.push('-'); 171 | 172 | const forcedKillTime = 1000 * 60 * 5; // ms * s * m: 5 minutes 173 | const options = { 174 | cwd: workspaceRoot !== null ? workspaceRoot : undefined, 175 | env: process.env, 176 | encoding: "utf8", 177 | timeout: forcedKillTime, 178 | tty: true, 179 | input: text, 180 | }; 181 | 182 | const phpcs = spawn.sync(this.executablePath, lintArgs, options); 183 | const stdout = phpcs.stdout.toString().trim(); 184 | const stderr = phpcs.stderr.toString().trim(); 185 | let match = null; 186 | 187 | // Determine whether we have an error in stderr. 188 | if (stderr !== '') { 189 | if (match = stderr.match(/^(?:PHP\s?)FATAL\s?ERROR:\s?(.*)/i)) { 190 | let error = match[1].trim(); 191 | if (match = error.match(/^Uncaught exception '.*' with message '(.*)'/)) { 192 | throw new Error(match[1]); 193 | } 194 | throw new Error(error); 195 | } 196 | throw new Error(strings.format(SR.UnknownExecutionError, `${this.executablePath} ${lintArgs.join(' ')}`)); 197 | } 198 | 199 | // Determine whether we have an error in stdout. 200 | if (match = stdout.match(/^ERROR:\s?(.*)/i)) { 201 | let error = match[1].trim(); 202 | if (match = error.match(/^the \"(.*)\" coding standard is not installed\./)) { 203 | throw new Error(strings.format(SR.CodingStandardNotInstalledError, match[1])); 204 | } 205 | throw new Error(error); 206 | } 207 | 208 | const data = this.parseData(stdout); 209 | 210 | let messages: Array; 211 | if (filePath !== undefined && semver.gte(this.executableVersion, '2.0.0')) { 212 | const fileRealPath = extfs.realpathSync(filePath); 213 | if (!data.files[fileRealPath]) { 214 | return []; 215 | } 216 | ({ messages } = data.files[fileRealPath]); 217 | } else { 218 | // PHPCS v1 can't associate a filename with STDIN input 219 | if (!data.files.STDIN) { 220 | return []; 221 | } 222 | ({ messages } = data.files.STDIN); 223 | } 224 | 225 | let diagnostics: Diagnostic[] = []; 226 | messages.map(message => diagnostics.push( 227 | this.createDiagnostic(document, message, settings.showSources) 228 | )); 229 | 230 | return diagnostics; 231 | } 232 | 233 | private parseData(text: string) { 234 | try { 235 | return JSON.parse(text) as { files: any }; 236 | } catch (error) { 237 | throw new Error(SR.InvalidJsonStringError); 238 | } 239 | } 240 | 241 | private createDiagnostic(document: TextDocument, entry: PhpcsMessage, showSources: boolean): Diagnostic { 242 | 243 | let lines = document.getText().split("\n"); 244 | let line = entry.line - 1; 245 | let lineString = lines[line]; 246 | 247 | // Process diagnostic start and end characters. 248 | let startCharacter = entry.column - 1; 249 | let endCharacter = entry.column; 250 | let charCode = lineString.charCodeAt(startCharacter); 251 | if (CharCode.isWhiteSpace(charCode)) { 252 | for (let i = startCharacter + 1, len = lineString.length; i < len; i++) { 253 | charCode = lineString.charCodeAt(i); 254 | if (!CharCode.isWhiteSpace(charCode)) { 255 | break; 256 | } 257 | endCharacter = i; 258 | } 259 | } else if (CharCode.isAlphaNumeric(charCode) || CharCode.isSymbol(charCode)) { 260 | // Get the whole word 261 | for (let i = startCharacter + 1, len = lineString.length; i < len; i++) { 262 | charCode = lineString.charCodeAt(i); 263 | if (!CharCode.isAlphaNumeric(charCode) && charCode !== 95) { 264 | break; 265 | } 266 | endCharacter++; 267 | } 268 | // Move backwards 269 | for (let i = startCharacter, len = 0; i > len; i--) { 270 | charCode = lineString.charCodeAt(i - 1); 271 | if (!CharCode.isAlphaNumeric(charCode) && !CharCode.isSymbol(charCode) && charCode !== 95) { 272 | break; 273 | } 274 | startCharacter--; 275 | } 276 | } 277 | 278 | // Process diagnostic range. 279 | const range: Range = Range.create(line, startCharacter, line, endCharacter); 280 | 281 | // Process diagnostic sources. 282 | let message: string = entry.message; 283 | if (showSources) { 284 | message += `\n(${entry.source})`; 285 | } 286 | 287 | // Process diagnostic severity. 288 | let severity: DiagnosticSeverity = DiagnosticSeverity.Error; 289 | if (entry.type === "WARNING") { 290 | severity = DiagnosticSeverity.Warning; 291 | } 292 | 293 | return Diagnostic.create(range, message, severity, null, 'phpcs'); 294 | } 295 | 296 | protected getIgnorePatternReplacements(): Map { 297 | if (!this.ignorePatternReplacements) { 298 | this.ignorePatternReplacements = new Map([ 299 | [/^\*\//, '**/'], // */some/path => **/some/path 300 | [/\/\*$/, '/**'], // some/path/* => some/path/** 301 | [/\/\*\//g, '/**/'], // some/*/path => some/**/path 302 | ]); 303 | } 304 | return this.ignorePatternReplacements; 305 | } 306 | 307 | protected isIgnorePatternMatch(path: string, pattern: string): boolean { 308 | for (let [searchValue, replaceValue] of this.getIgnorePatternReplacements()) { 309 | pattern = pattern.replace(searchValue, replaceValue); 310 | } 311 | return mm.isMatch(path, pattern); 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /phpcs-server/src/server.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Ioannis Kappas. All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | "use strict"; 6 | 7 | import * as proto from "./protocol"; 8 | import * as strings from "./base/common/strings"; 9 | 10 | import { 11 | ClientCapabilities, 12 | createConnection, 13 | Diagnostic, 14 | DidChangeConfigurationParams, 15 | DidChangeWatchedFilesParams, 16 | Files, 17 | IConnection, 18 | InitializeParams, 19 | InitializeResult, 20 | IPCMessageReader, 21 | IPCMessageWriter, 22 | Proposed, 23 | ProposedFeatures, 24 | PublishDiagnosticsParams, 25 | TextDocument, 26 | TextDocumentChangeEvent, 27 | TextDocumentIdentifier, 28 | TextDocuments 29 | } from 'vscode-languageserver'; 30 | 31 | import { PhpcsLinter } from "./linter"; 32 | import { PhpcsSettings } from "./settings"; 33 | import { StringResources as SR } from "./strings"; 34 | 35 | class PhpcsServer { 36 | 37 | private connection: IConnection; 38 | private documents: TextDocuments; 39 | private validating: Map; 40 | 41 | // Cache the settings of all open documents 42 | private hasConfigurationCapability: boolean = false; 43 | private hasWorkspaceFolderCapability: boolean = false; 44 | 45 | private globalSettings: PhpcsSettings; 46 | private defaultSettings: PhpcsSettings = { 47 | enable: true, 48 | workspaceRoot: null, 49 | executablePath: null, 50 | composerJsonPath: null, 51 | standard: null, 52 | autoConfigSearch: true, 53 | showSources: false, 54 | showWarnings: true, 55 | ignorePatterns: [], 56 | warningSeverity: 5, 57 | errorSeverity: 5, 58 | }; 59 | private documentSettings: Map> = new Map(); 60 | 61 | /** 62 | * Class constructor. 63 | * 64 | * @return A new instance of the server. 65 | */ 66 | constructor() { 67 | this.validating = new Map(); 68 | this.connection = createConnection(ProposedFeatures.all, new IPCMessageReader(process), new IPCMessageWriter(process)); 69 | this.documents = new TextDocuments(); 70 | this.documents.listen(this.connection); 71 | this.connection.onInitialize(this.safeEventHandler(this.onInitialize)); 72 | this.connection.onInitialized(this.safeEventHandler(this.onDidInitialize)); 73 | this.connection.onDidChangeConfiguration(this.safeEventHandler(this.onDidChangeConfiguration)); 74 | this.connection.onDidChangeWatchedFiles(this.safeEventHandler(this.onDidChangeWatchedFiles)); 75 | this.documents.onDidChangeContent(this.safeEventHandler(this.onDidChangeDocument)); 76 | this.documents.onDidOpen(this.safeEventHandler(this.onDidOpenDocument)); 77 | this.documents.onDidSave(this.safeEventHandler(this.onDidSaveDocument)); 78 | this.documents.onDidClose(this.safeEventHandler(this.onDidCloseDocument)); 79 | } 80 | 81 | /** 82 | * Safely handle event notifications. 83 | * @param callback An event handler. 84 | */ 85 | private safeEventHandler(callback: (...args: any[]) => Promise): (...args: any[]) => Promise { 86 | return (...args: any[]): Promise => { 87 | return callback.apply(this, args).catch((error: Error) => { 88 | this.connection.window.showErrorMessage(`phpcs: ${error.message}`); 89 | }); 90 | }; 91 | } 92 | 93 | /** 94 | * Handles server initialization. 95 | * 96 | * @param params The initialization parameters. 97 | * @return A promise of initialization result or initialization error. 98 | */ 99 | private async onInitialize(params: InitializeParams & Proposed.WorkspaceFoldersInitializeParams): Promise { 100 | let capabilities = params.capabilities as ClientCapabilities & Proposed.WorkspaceFoldersClientCapabilities & Proposed.ConfigurationClientCapabilities; 101 | this.hasWorkspaceFolderCapability = capabilities.workspace && !!capabilities.workspace.workspaceFolders; 102 | this.hasConfigurationCapability = capabilities.workspace && !!capabilities.workspace.configuration; 103 | return Promise.resolve({ 104 | capabilities: { 105 | textDocumentSync: this.documents.syncKind 106 | } 107 | }); 108 | } 109 | 110 | /** 111 | * Handles connection initialization completion. 112 | */ 113 | private async onDidInitialize(): Promise { 114 | if (this.hasWorkspaceFolderCapability) { 115 | (this.connection.workspace as any).onDidChangeWorkspaceFolders((_event: Proposed.WorkspaceFoldersChangeEvent) => { 116 | this.connection.tracer.log('Workspace folder change event received'); 117 | }); 118 | } 119 | } 120 | 121 | /** 122 | * Handles configuration changes. 123 | * 124 | * @param params The changed configuration parameters. 125 | * @return void 126 | */ 127 | private async onDidChangeConfiguration(params: DidChangeConfigurationParams): Promise { 128 | if (this.hasConfigurationCapability) { 129 | this.documentSettings.clear(); 130 | } else { 131 | this.globalSettings = { 132 | ...this.defaultSettings, 133 | ...params.settings.phpcs 134 | }; 135 | } 136 | await this.validateMany(this.documents.all()); 137 | } 138 | 139 | /** 140 | * Handles watched files changes. 141 | * 142 | * @param params The changed watched files parameters. 143 | * @return void 144 | */ 145 | private async onDidChangeWatchedFiles(_params: DidChangeWatchedFilesParams): Promise { 146 | await this.validateMany(this.documents.all()); 147 | } 148 | 149 | /** 150 | * Handles opening of text documents. 151 | * 152 | * @param event The text document change event. 153 | * @return void 154 | */ 155 | private async onDidOpenDocument({ document }: TextDocumentChangeEvent): Promise { 156 | await this.validateSingle(document); 157 | } 158 | 159 | /** 160 | * Handles saving of text documents. 161 | * 162 | * @param event The text document change event. 163 | * @return void 164 | */ 165 | private async onDidSaveDocument({ document }: TextDocumentChangeEvent): Promise { 166 | await this.validateSingle(document); 167 | } 168 | 169 | /** 170 | * Handles closing of text documents. 171 | * 172 | * @param event The text document change event. 173 | * @return void 174 | */ 175 | private async onDidCloseDocument({ document }: TextDocumentChangeEvent): Promise { 176 | const uri = document.uri; 177 | 178 | // Clear cached document settings. 179 | if (this.documentSettings.has(uri)) { 180 | this.documentSettings.delete(uri); 181 | } 182 | 183 | // Clear validating status. 184 | if (this.validating.has(uri)) { 185 | this.validating.delete(uri); 186 | } 187 | 188 | this.clearDiagnostics(uri); 189 | } 190 | 191 | /** 192 | * Handles changes of text documents. 193 | * 194 | * @param event The text document change event. 195 | * @return void 196 | */ 197 | private async onDidChangeDocument({ document }: TextDocumentChangeEvent): Promise { 198 | await this.validateSingle(document); 199 | } 200 | 201 | /** 202 | * Start listening to requests. 203 | * 204 | * @return void 205 | */ 206 | public listen(): void { 207 | this.connection.listen(); 208 | } 209 | 210 | /** 211 | * Sends diagnostics computed for a given document to VSCode to render them in the 212 | * user interface. 213 | * 214 | * @param params The diagnostic parameters. 215 | */ 216 | private sendDiagnostics(params: PublishDiagnosticsParams): void { 217 | this.connection.sendDiagnostics(params); 218 | } 219 | 220 | /** 221 | * Clears the diagnostics computed for a given document. 222 | * 223 | * @param uri The document uri for which to clear the diagnostics. 224 | */ 225 | private clearDiagnostics(uri: string): void { 226 | this.connection.sendDiagnostics({ uri, diagnostics: [] }); 227 | } 228 | 229 | /** 230 | * Sends a notification for starting validation of a document. 231 | * 232 | * @param document The text document on which validation started. 233 | */ 234 | private sendStartValidationNotification(document: TextDocument): void { 235 | this.validating.set(document.uri, document); 236 | this.connection.sendNotification( 237 | proto.DidStartValidateTextDocumentNotification.type, 238 | { textDocument: TextDocumentIdentifier.create(document.uri) } 239 | ); 240 | this.connection.tracer.log(strings.format(SR.DidStartValidateTextDocument, document.uri)); 241 | } 242 | 243 | /** 244 | * Sends a notification for ending validation of a document. 245 | * 246 | * @param document The text document on which validation ended. 247 | */ 248 | private sendEndValidationNotification(document: TextDocument): void { 249 | this.validating.delete(document.uri); 250 | this.connection.sendNotification( 251 | proto.DidEndValidateTextDocumentNotification.type, 252 | { textDocument: TextDocumentIdentifier.create(document.uri) } 253 | ); 254 | this.connection.tracer.log(strings.format(SR.DidEndValidateTextDocument, document.uri)); 255 | } 256 | 257 | /** 258 | * Validate a single text document. 259 | * 260 | * @param document The text document to validate. 261 | * @return void 262 | */ 263 | public async validateSingle(document: TextDocument): Promise { 264 | const { uri } = document; 265 | if (this.validating.has(uri) === false) { 266 | let settings = await this.getDocumentSettings(document); 267 | if (settings.enable) { 268 | let diagnostics: Diagnostic[] = []; 269 | this.sendStartValidationNotification(document); 270 | try { 271 | const phpcs = await PhpcsLinter.create(settings.executablePath); 272 | diagnostics = await phpcs.lint(document, settings); 273 | } catch(error) { 274 | throw new Error(this.getExceptionMessage(error, document)); 275 | } finally { 276 | this.sendEndValidationNotification(document); 277 | this.sendDiagnostics({ uri, diagnostics }); 278 | } 279 | } 280 | } 281 | } 282 | 283 | /** 284 | * Validate a list of text documents. 285 | * 286 | * @param documents The list of text documents to validate. 287 | * @return void 288 | */ 289 | public async validateMany(documents: TextDocument[]): Promise { 290 | for (var i = 0, len = documents.length; i < len; i++) { 291 | await this.validateSingle(documents[i]); 292 | } 293 | } 294 | 295 | /** 296 | * Get the settings for the specified document. 297 | * 298 | * @param document The text document for which to get the settings. 299 | * @return A promise of PhpcsSettings. 300 | */ 301 | private async getDocumentSettings(document: TextDocument): Promise { 302 | const { uri } = document; 303 | let settings: Promise; 304 | if (this.hasConfigurationCapability) { 305 | if (this.documentSettings.has(uri)) { 306 | settings = this.documentSettings.get(uri); 307 | } else { 308 | const configurationItem: Proposed.ConfigurationItem = uri.match(/^untitled:/) ? {} : { scopeUri: uri }; 309 | settings = (this.connection.workspace as any).getConfiguration(configurationItem); 310 | this.documentSettings.set(uri, settings); 311 | } 312 | } else { 313 | settings = Promise.resolve(this.globalSettings); 314 | } 315 | return settings; 316 | } 317 | 318 | /** 319 | * Get the exception message from an exception object. 320 | * 321 | * @param exception The exception to parse. 322 | * @param document The document where the exception occurred. 323 | * @return string The exception message. 324 | */ 325 | private getExceptionMessage(exception: any, document: TextDocument): string { 326 | let message: string = null; 327 | if (typeof exception.message === 'string' || exception.message instanceof String) { 328 | message = exception.message; 329 | message = message.replace(/\r?\n/g, ' '); 330 | if (/^ERROR: /.test(message)) { 331 | message = message.substr(5); 332 | } 333 | } else { 334 | message = strings.format(SR.UnknownErrorWhileValidatingTextDocument, Files.uriToFilePath(document.uri)); 335 | } 336 | return message; 337 | } 338 | } 339 | 340 | let server = new PhpcsServer(); 341 | server.listen(); 342 | -------------------------------------------------------------------------------- /phpcs/phpcs_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xmlCodeSn -------------------------------------------------------------------------------- /phpcs-server/src/base/common/charcode.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 'use strict'; 6 | 7 | // Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/ 8 | 9 | /** 10 | * An inlined enum containing useful character codes (to be used with String.charCodeAt). 11 | * Please leave the const keyword such that it gets inlined when compiled to JavaScript! 12 | */ 13 | enum CharCode { 14 | Null = 0, 15 | /** 16 | * The `\t` character. 17 | */ 18 | Tab = 9, 19 | /** 20 | * The `\n` character. 21 | */ 22 | LineFeed = 10, 23 | /** 24 | * The `\r` character. 25 | */ 26 | CarriageReturn = 13, 27 | Space = 32, 28 | /** 29 | * The `!` character. 30 | */ 31 | ExclamationMark = 33, 32 | /** 33 | * The `"` character. 34 | */ 35 | DoubleQuote = 34, 36 | /** 37 | * The `#` character. 38 | */ 39 | Hash = 35, 40 | /** 41 | * The `$` character. 42 | */ 43 | DollarSign = 36, 44 | /** 45 | * The `%` character. 46 | */ 47 | PercentSign = 37, 48 | /** 49 | * The `&` character. 50 | */ 51 | Ampersand = 38, 52 | /** 53 | * The `'` character. 54 | */ 55 | SingleQuote = 39, 56 | /** 57 | * The `(` character. 58 | */ 59 | OpenParen = 40, 60 | /** 61 | * The `)` character. 62 | */ 63 | CloseParen = 41, 64 | /** 65 | * The `*` character. 66 | */ 67 | Asterisk = 42, 68 | /** 69 | * The `+` character. 70 | */ 71 | Plus = 43, 72 | /** 73 | * The `,` character. 74 | */ 75 | Comma = 44, 76 | /** 77 | * The `-` character. 78 | */ 79 | Dash = 45, 80 | /** 81 | * The `.` character. 82 | */ 83 | Period = 46, 84 | /** 85 | * The `/` character. 86 | */ 87 | Slash = 47, 88 | 89 | Digit0 = 48, 90 | Digit1 = 49, 91 | Digit2 = 50, 92 | Digit3 = 51, 93 | Digit4 = 52, 94 | Digit5 = 53, 95 | Digit6 = 54, 96 | Digit7 = 55, 97 | Digit8 = 56, 98 | Digit9 = 57, 99 | 100 | /** 101 | * The `:` character. 102 | */ 103 | Colon = 58, 104 | /** 105 | * The `;` character. 106 | */ 107 | Semicolon = 59, 108 | /** 109 | * The `<` character. 110 | */ 111 | LessThan = 60, 112 | /** 113 | * The `=` character. 114 | */ 115 | Equals = 61, 116 | /** 117 | * The `>` character. 118 | */ 119 | GreaterThan = 62, 120 | /** 121 | * The `?` character. 122 | */ 123 | QuestionMark = 63, 124 | /** 125 | * The `@` character. 126 | */ 127 | AtSign = 64, 128 | 129 | A = 65, 130 | B = 66, 131 | C = 67, 132 | D = 68, 133 | E = 69, 134 | F = 70, 135 | G = 71, 136 | H = 72, 137 | I = 73, 138 | J = 74, 139 | K = 75, 140 | L = 76, 141 | M = 77, 142 | N = 78, 143 | O = 79, 144 | P = 80, 145 | Q = 81, 146 | R = 82, 147 | S = 83, 148 | T = 84, 149 | U = 85, 150 | V = 86, 151 | W = 87, 152 | X = 88, 153 | Y = 89, 154 | Z = 90, 155 | 156 | /** 157 | * The `[` character. 158 | */ 159 | OpenSquareBracket = 91, 160 | /** 161 | * The `\` character. 162 | */ 163 | Backslash = 92, 164 | /** 165 | * The `]` character. 166 | */ 167 | CloseSquareBracket = 93, 168 | /** 169 | * The `^` character. 170 | */ 171 | Caret = 94, 172 | /** 173 | * The `_` character. 174 | */ 175 | Underline = 95, 176 | /** 177 | * The ``(`)`` character. 178 | */ 179 | BackTick = 96, 180 | 181 | a = 97, 182 | b = 98, 183 | c = 99, 184 | d = 100, 185 | e = 101, 186 | f = 102, 187 | g = 103, 188 | h = 104, 189 | i = 105, 190 | j = 106, 191 | k = 107, 192 | l = 108, 193 | m = 109, 194 | n = 110, 195 | o = 111, 196 | p = 112, 197 | q = 113, 198 | r = 114, 199 | s = 115, 200 | t = 116, 201 | u = 117, 202 | v = 118, 203 | w = 119, 204 | x = 120, 205 | y = 121, 206 | z = 122, 207 | 208 | /** 209 | * The `{` character. 210 | */ 211 | OpenCurlyBrace = 123, 212 | /** 213 | * The `|` character. 214 | */ 215 | Pipe = 124, 216 | /** 217 | * The `}` character. 218 | */ 219 | CloseCurlyBrace = 125, 220 | /** 221 | * The `~` character. 222 | */ 223 | Tilde = 126, 224 | 225 | U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent 226 | U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent 227 | U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent 228 | U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde 229 | U_Combining_Macron = 0x0304, // U+0304 Combining Macron 230 | U_Combining_Overline = 0x0305, // U+0305 Combining Overline 231 | U_Combining_Breve = 0x0306, // U+0306 Combining Breve 232 | U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above 233 | U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis 234 | U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above 235 | U_Combining_Ring_Above = 0x030A, // U+030A Combining Ring Above 236 | U_Combining_Double_Acute_Accent = 0x030B, // U+030B Combining Double Acute Accent 237 | U_Combining_Caron = 0x030C, // U+030C Combining Caron 238 | U_Combining_Vertical_Line_Above = 0x030D, // U+030D Combining Vertical Line Above 239 | U_Combining_Double_Vertical_Line_Above = 0x030E, // U+030E Combining Double Vertical Line Above 240 | U_Combining_Double_Grave_Accent = 0x030F, // U+030F Combining Double Grave Accent 241 | U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu 242 | U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve 243 | U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above 244 | U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above 245 | U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above 246 | U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right 247 | U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below 248 | U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below 249 | U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below 250 | U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below 251 | U_Combining_Left_Angle_Above = 0x031A, // U+031A Combining Left Angle Above 252 | U_Combining_Horn = 0x031B, // U+031B Combining Horn 253 | U_Combining_Left_Half_Ring_Below = 0x031C, // U+031C Combining Left Half Ring Below 254 | U_Combining_Up_Tack_Below = 0x031D, // U+031D Combining Up Tack Below 255 | U_Combining_Down_Tack_Below = 0x031E, // U+031E Combining Down Tack Below 256 | U_Combining_Plus_Sign_Below = 0x031F, // U+031F Combining Plus Sign Below 257 | U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below 258 | U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below 259 | U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below 260 | U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below 261 | U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below 262 | U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below 263 | U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below 264 | U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla 265 | U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek 266 | U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below 267 | U_Combining_Bridge_Below = 0x032A, // U+032A Combining Bridge Below 268 | U_Combining_Inverted_Double_Arch_Below = 0x032B, // U+032B Combining Inverted Double Arch Below 269 | U_Combining_Caron_Below = 0x032C, // U+032C Combining Caron Below 270 | U_Combining_Circumflex_Accent_Below = 0x032D, // U+032D Combining Circumflex Accent Below 271 | U_Combining_Breve_Below = 0x032E, // U+032E Combining Breve Below 272 | U_Combining_Inverted_Breve_Below = 0x032F, // U+032F Combining Inverted Breve Below 273 | U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below 274 | U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below 275 | U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line 276 | U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line 277 | U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay 278 | U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay 279 | U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay 280 | U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay 281 | U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay 282 | U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below 283 | U_Combining_Inverted_Bridge_Below = 0x033A, // U+033A Combining Inverted Bridge Below 284 | U_Combining_Square_Below = 0x033B, // U+033B Combining Square Below 285 | U_Combining_Seagull_Below = 0x033C, // U+033C Combining Seagull Below 286 | U_Combining_X_Above = 0x033D, // U+033D Combining X Above 287 | U_Combining_Vertical_Tilde = 0x033E, // U+033E Combining Vertical Tilde 288 | U_Combining_Double_Overline = 0x033F, // U+033F Combining Double Overline 289 | U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark 290 | U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark 291 | U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni 292 | U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis 293 | U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos 294 | U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni 295 | U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above 296 | U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below 297 | U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below 298 | U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below 299 | U_Combining_Not_Tilde_Above = 0x034A, // U+034A Combining Not Tilde Above 300 | U_Combining_Homothetic_Above = 0x034B, // U+034B Combining Homothetic Above 301 | U_Combining_Almost_Equal_To_Above = 0x034C, // U+034C Combining Almost Equal To Above 302 | U_Combining_Left_Right_Arrow_Below = 0x034D, // U+034D Combining Left Right Arrow Below 303 | U_Combining_Upwards_Arrow_Below = 0x034E, // U+034E Combining Upwards Arrow Below 304 | U_Combining_Grapheme_Joiner = 0x034F, // U+034F Combining Grapheme Joiner 305 | U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above 306 | U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above 307 | U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata 308 | U_Combining_X_Below = 0x0353, // U+0353 Combining X Below 309 | U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below 310 | U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below 311 | U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below 312 | U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above 313 | U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right 314 | U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below 315 | U_Combining_Double_Ring_Below = 0x035A, // U+035A Combining Double Ring Below 316 | U_Combining_Zigzag_Above = 0x035B, // U+035B Combining Zigzag Above 317 | U_Combining_Double_Breve_Below = 0x035C, // U+035C Combining Double Breve Below 318 | U_Combining_Double_Breve = 0x035D, // U+035D Combining Double Breve 319 | U_Combining_Double_Macron = 0x035E, // U+035E Combining Double Macron 320 | U_Combining_Double_Macron_Below = 0x035F, // U+035F Combining Double Macron Below 321 | U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde 322 | U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve 323 | U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below 324 | U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A 325 | U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E 326 | U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I 327 | U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O 328 | U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U 329 | U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C 330 | U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D 331 | U_Combining_Latin_Small_Letter_H = 0x036A, // U+036A Combining Latin Small Letter H 332 | U_Combining_Latin_Small_Letter_M = 0x036B, // U+036B Combining Latin Small Letter M 333 | U_Combining_Latin_Small_Letter_R = 0x036C, // U+036C Combining Latin Small Letter R 334 | U_Combining_Latin_Small_Letter_T = 0x036D, // U+036D Combining Latin Small Letter T 335 | U_Combining_Latin_Small_Letter_V = 0x036E, // U+036E Combining Latin Small Letter V 336 | U_Combining_Latin_Small_Letter_X = 0x036F, // U+036F Combining Latin Small Letter X 337 | 338 | /** 339 | * Unicode Character 'LINE SEPARATOR' (U+2028) 340 | * http://www.fileformat.info/info/unicode/char/2028/index.htm 341 | */ 342 | LINE_SEPARATOR_2028 = 8232, 343 | 344 | // http://www.fileformat.info/info/unicode/category/Sk/list.htm 345 | U_CIRCUMFLEX = 0x005E, // U+005E CIRCUMFLEX 346 | U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT 347 | U_DIAERESIS = 0x00A8, // U+00A8 DIAERESIS 348 | U_MACRON = 0x00AF, // U+00AF MACRON 349 | U_ACUTE_ACCENT = 0x00B4, // U+00B4 ACUTE ACCENT 350 | U_CEDILLA = 0x00B8, // U+00B8 CEDILLA 351 | U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02C2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD 352 | U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02C3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD 353 | U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02C4, // U+02C4 MODIFIER LETTER UP ARROWHEAD 354 | U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02C5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD 355 | U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02D2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING 356 | U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02D3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING 357 | U_MODIFIER_LETTER_UP_TACK = 0x02D4, // U+02D4 MODIFIER LETTER UP TACK 358 | U_MODIFIER_LETTER_DOWN_TACK = 0x02D5, // U+02D5 MODIFIER LETTER DOWN TACK 359 | U_MODIFIER_LETTER_PLUS_SIGN = 0x02D6, // U+02D6 MODIFIER LETTER PLUS SIGN 360 | U_MODIFIER_LETTER_MINUS_SIGN = 0x02D7, // U+02D7 MODIFIER LETTER MINUS SIGN 361 | U_BREVE = 0x02D8, // U+02D8 BREVE 362 | U_DOT_ABOVE = 0x02D9, // U+02D9 DOT ABOVE 363 | U_RING_ABOVE = 0x02DA, // U+02DA RING ABOVE 364 | U_OGONEK = 0x02DB, // U+02DB OGONEK 365 | U_SMALL_TILDE = 0x02DC, // U+02DC SMALL TILDE 366 | U_DOUBLE_ACUTE_ACCENT = 0x02DD, // U+02DD DOUBLE ACUTE ACCENT 367 | U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02DE, // U+02DE MODIFIER LETTER RHOTIC HOOK 368 | U_MODIFIER_LETTER_CROSS_ACCENT = 0x02DF, // U+02DF MODIFIER LETTER CROSS ACCENT 369 | U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02E5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR 370 | U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02E6, // U+02E6 MODIFIER LETTER HIGH TONE BAR 371 | U_MODIFIER_LETTER_MID_TONE_BAR = 0x02E7, // U+02E7 MODIFIER LETTER MID TONE BAR 372 | U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02E8, // U+02E8 MODIFIER LETTER LOW TONE BAR 373 | U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02E9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR 374 | U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02EA, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK 375 | U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02EB, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK 376 | U_MODIFIER_LETTER_UNASPIRATED = 0x02ED, // U+02ED MODIFIER LETTER UNASPIRATED 377 | U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02EF, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD 378 | U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02F0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD 379 | U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02F1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD 380 | U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02F2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD 381 | U_MODIFIER_LETTER_LOW_RING = 0x02F3, // U+02F3 MODIFIER LETTER LOW RING 382 | U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02F4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT 383 | U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02F5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT 384 | U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02F6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT 385 | U_MODIFIER_LETTER_LOW_TILDE = 0x02F7, // U+02F7 MODIFIER LETTER LOW TILDE 386 | U_MODIFIER_LETTER_RAISED_COLON = 0x02F8, // U+02F8 MODIFIER LETTER RAISED COLON 387 | U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02F9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE 388 | U_MODIFIER_LETTER_END_HIGH_TONE = 0x02FA, // U+02FA MODIFIER LETTER END HIGH TONE 389 | U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02FB, // U+02FB MODIFIER LETTER BEGIN LOW TONE 390 | U_MODIFIER_LETTER_END_LOW_TONE = 0x02FC, // U+02FC MODIFIER LETTER END LOW TONE 391 | U_MODIFIER_LETTER_SHELF = 0x02FD, // U+02FD MODIFIER LETTER SHELF 392 | U_MODIFIER_LETTER_OPEN_SHELF = 0x02FE, // U+02FE MODIFIER LETTER OPEN SHELF 393 | U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02FF, // U+02FF MODIFIER LETTER LOW LEFT ARROW 394 | U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN 395 | U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS 396 | U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS 397 | U_GREEK_KORONIS = 0x1FBD, // U+1FBD GREEK KORONIS 398 | U_GREEK_PSILI = 0x1FBF, // U+1FBF GREEK PSILI 399 | U_GREEK_PERISPOMENI = 0x1FC0, // U+1FC0 GREEK PERISPOMENI 400 | U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1FC1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI 401 | U_GREEK_PSILI_AND_VARIA = 0x1FCD, // U+1FCD GREEK PSILI AND VARIA 402 | U_GREEK_PSILI_AND_OXIA = 0x1FCE, // U+1FCE GREEK PSILI AND OXIA 403 | U_GREEK_PSILI_AND_PERISPOMENI = 0x1FCF, // U+1FCF GREEK PSILI AND PERISPOMENI 404 | U_GREEK_DASIA_AND_VARIA = 0x1FDD, // U+1FDD GREEK DASIA AND VARIA 405 | U_GREEK_DASIA_AND_OXIA = 0x1FDE, // U+1FDE GREEK DASIA AND OXIA 406 | U_GREEK_DASIA_AND_PERISPOMENI = 0x1FDF, // U+1FDF GREEK DASIA AND PERISPOMENI 407 | U_GREEK_DIALYTIKA_AND_VARIA = 0x1FED, // U+1FED GREEK DIALYTIKA AND VARIA 408 | U_GREEK_DIALYTIKA_AND_OXIA = 0x1FEE, // U+1FEE GREEK DIALYTIKA AND OXIA 409 | U_GREEK_VARIA = 0x1FEF, // U+1FEF GREEK VARIA 410 | U_GREEK_OXIA = 0x1FFD, // U+1FFD GREEK OXIA 411 | U_GREEK_DASIA = 0x1FFE, // U+1FFE GREEK DASIA 412 | 413 | 414 | U_OVERLINE = 0x203E, // Unicode Character 'OVERLINE' 415 | 416 | /** 417 | * UTF-8 BOM 418 | * Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF) 419 | * http://www.fileformat.info/info/unicode/char/feff/index.htm 420 | */ 421 | UTF8_BOM = 65279 422 | } 423 | 424 | namespace CharCode { 425 | 426 | /** 427 | * Indicates whether a Unicode character code is categorized as a Latin1 character. 428 | * @param charCode The unicode character code to check. 429 | */ 430 | export function isLatin1(charCode: CharCode): boolean { 431 | return charCode <= 255; 432 | } 433 | 434 | /** 435 | * Indicates whether a Unicode character code is categorized as an ASCII character. 436 | * @param charCode The unicode character code to check. 437 | */ 438 | export function isAscii(charCode: CharCode): boolean { 439 | return charCode <= 127; 440 | } 441 | 442 | /** 443 | * Indicates whether a Unicode character code is categorized as white space. 444 | * @param charCode The unicode character code to check. 445 | */ 446 | export function isWhiteSpace(charCode: CharCode): boolean { 447 | return isWhiteSpaceLatin1(charCode); 448 | } 449 | 450 | /** 451 | * Indicates whether a Unicode character code is categorized as white space. 452 | * @param charCode The unicode character code to check. 453 | */ 454 | function isWhiteSpaceLatin1(charCode: CharCode): boolean { 455 | return charCode === 32 || (charCode >= 9 && charCode <= 13) || (charCode === 160 || charCode === 133); 456 | } 457 | 458 | /** 459 | * Indicates whether a Unicode character code is categorized as a symbol character. 460 | * @param charCode The unicode character code to check. 461 | */ 462 | export function isSymbol(charCode: CharCode): boolean { 463 | return (charCode >= 33 && charCode <= 47) || (charCode >= 58 && charCode <= 64) || (charCode >= 91 && charCode <= 96) || (charCode >= 123 && charCode <= 126); 464 | } 465 | 466 | /** 467 | * Indicates whether a Unicode character code is categorized as a decimal digit. 468 | * @param charCode The unicode character code to check. 469 | */ 470 | export function isDigit(charCode: CharCode): boolean { 471 | return charCode >= 48 && charCode <= 57; 472 | } 473 | 474 | /** 475 | * Indicates whether a Unicode character code is categorized as an uppercase alpha. 476 | * @param charCode The unicode character code to check. 477 | */ 478 | export function isAlphaUpper(charCode: CharCode): boolean { 479 | return charCode >= 65 && charCode <= 90; 480 | } 481 | 482 | /** 483 | * Indicates whether a Unicode character code is categorized as a lowercase alpha. 484 | * @param charCode The unicode character code to check. 485 | */ 486 | export function isAlphaLower(charCode: CharCode): boolean { 487 | return charCode >= 97 && charCode <= 122; 488 | } 489 | 490 | /** 491 | * Determine whether the specified character code is a alpha numeric. 492 | * @param charCode The unicode character code to check. 493 | */ 494 | export function isAlphaNumeric(charCode: CharCode): boolean { 495 | return isDigit(charCode) || isAlphaUpper(charCode) || isAlphaLower(charCode); 496 | } 497 | } 498 | 499 | export default CharCode; -------------------------------------------------------------------------------- /phpcs-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpcs-server", 3 | "version": "1.0.5", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "arr-diff": { 8 | "version": "4.0.0", 9 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 10 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" 11 | }, 12 | "arr-flatten": { 13 | "version": "1.1.0", 14 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 15 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" 16 | }, 17 | "arr-union": { 18 | "version": "3.1.0", 19 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 20 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" 21 | }, 22 | "array-unique": { 23 | "version": "0.3.2", 24 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", 25 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" 26 | }, 27 | "assign-symbols": { 28 | "version": "1.0.0", 29 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 30 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" 31 | }, 32 | "atob": { 33 | "version": "2.0.3", 34 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", 35 | "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=" 36 | }, 37 | "base": { 38 | "version": "0.11.2", 39 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", 40 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", 41 | "requires": { 42 | "cache-base": "1.0.1", 43 | "class-utils": "0.3.6", 44 | "component-emitter": "1.2.1", 45 | "define-property": "1.0.0", 46 | "isobject": "3.0.1", 47 | "mixin-deep": "1.3.1", 48 | "pascalcase": "0.1.1" 49 | }, 50 | "dependencies": { 51 | "define-property": { 52 | "version": "1.0.0", 53 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 54 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 55 | "requires": { 56 | "is-descriptor": "1.0.2" 57 | } 58 | } 59 | } 60 | }, 61 | "braces": { 62 | "version": "2.3.1", 63 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", 64 | "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", 65 | "requires": { 66 | "arr-flatten": "1.1.0", 67 | "array-unique": "0.3.2", 68 | "define-property": "1.0.0", 69 | "extend-shallow": "2.0.1", 70 | "fill-range": "4.0.0", 71 | "isobject": "3.0.1", 72 | "kind-of": "6.0.2", 73 | "repeat-element": "1.1.2", 74 | "snapdragon": "0.8.1", 75 | "snapdragon-node": "2.1.1", 76 | "split-string": "3.1.0", 77 | "to-regex": "3.0.2" 78 | }, 79 | "dependencies": { 80 | "define-property": { 81 | "version": "1.0.0", 82 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 83 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 84 | "requires": { 85 | "is-descriptor": "1.0.2" 86 | } 87 | }, 88 | "extend-shallow": { 89 | "version": "2.0.1", 90 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 91 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 92 | "requires": { 93 | "is-extendable": "0.1.1" 94 | } 95 | } 96 | } 97 | }, 98 | "cache-base": { 99 | "version": "1.0.1", 100 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", 101 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", 102 | "requires": { 103 | "collection-visit": "1.0.0", 104 | "component-emitter": "1.2.1", 105 | "get-value": "2.0.6", 106 | "has-value": "1.0.0", 107 | "isobject": "3.0.1", 108 | "set-value": "2.0.0", 109 | "to-object-path": "0.3.0", 110 | "union-value": "1.0.0", 111 | "unset-value": "1.0.0" 112 | } 113 | }, 114 | "class-utils": { 115 | "version": "0.3.6", 116 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", 117 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", 118 | "requires": { 119 | "arr-union": "3.1.0", 120 | "define-property": "0.2.5", 121 | "isobject": "3.0.1", 122 | "static-extend": "0.1.2" 123 | }, 124 | "dependencies": { 125 | "define-property": { 126 | "version": "0.2.5", 127 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 128 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 129 | "requires": { 130 | "is-descriptor": "0.1.6" 131 | } 132 | }, 133 | "is-accessor-descriptor": { 134 | "version": "0.1.6", 135 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 136 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 137 | "requires": { 138 | "kind-of": "3.2.2" 139 | }, 140 | "dependencies": { 141 | "kind-of": { 142 | "version": "3.2.2", 143 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 144 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 145 | "requires": { 146 | "is-buffer": "1.1.6" 147 | } 148 | } 149 | } 150 | }, 151 | "is-data-descriptor": { 152 | "version": "0.1.4", 153 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 154 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 155 | "requires": { 156 | "kind-of": "3.2.2" 157 | }, 158 | "dependencies": { 159 | "kind-of": { 160 | "version": "3.2.2", 161 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 162 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 163 | "requires": { 164 | "is-buffer": "1.1.6" 165 | } 166 | } 167 | } 168 | }, 169 | "is-descriptor": { 170 | "version": "0.1.6", 171 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 172 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 173 | "requires": { 174 | "is-accessor-descriptor": "0.1.6", 175 | "is-data-descriptor": "0.1.4", 176 | "kind-of": "5.1.0" 177 | } 178 | }, 179 | "kind-of": { 180 | "version": "5.1.0", 181 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 182 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 183 | } 184 | } 185 | }, 186 | "collection-visit": { 187 | "version": "1.0.0", 188 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", 189 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", 190 | "requires": { 191 | "map-visit": "1.0.0", 192 | "object-visit": "1.0.1" 193 | } 194 | }, 195 | "component-emitter": { 196 | "version": "1.2.1", 197 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 198 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 199 | }, 200 | "copy-descriptor": { 201 | "version": "0.1.1", 202 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", 203 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" 204 | }, 205 | "cross-spawn": { 206 | "version": "6.0.4", 207 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.4.tgz", 208 | "integrity": "sha512-LDYnK41m8td+nBTk5Jmn55aGVP18iYuUqoM1X3u+ptt7M/g9FPS8C38PNoJTMfjoNx4fmiwWToPpiZklGRLbIA==", 209 | "requires": { 210 | "nice-try": "1.0.4", 211 | "path-key": "2.0.1", 212 | "semver": "5.5.0", 213 | "shebang-command": "1.2.0", 214 | "which": "1.3.0" 215 | } 216 | }, 217 | "debug": { 218 | "version": "2.6.9", 219 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 220 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 221 | "requires": { 222 | "ms": "2.0.0" 223 | } 224 | }, 225 | "decode-uri-component": { 226 | "version": "0.2.0", 227 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 228 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" 229 | }, 230 | "define-property": { 231 | "version": "2.0.2", 232 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", 233 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", 234 | "requires": { 235 | "is-descriptor": "1.0.2", 236 | "isobject": "3.0.1" 237 | } 238 | }, 239 | "expand-brackets": { 240 | "version": "2.1.4", 241 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", 242 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", 243 | "requires": { 244 | "debug": "2.6.9", 245 | "define-property": "0.2.5", 246 | "extend-shallow": "2.0.1", 247 | "posix-character-classes": "0.1.1", 248 | "regex-not": "1.0.2", 249 | "snapdragon": "0.8.1", 250 | "to-regex": "3.0.2" 251 | }, 252 | "dependencies": { 253 | "define-property": { 254 | "version": "0.2.5", 255 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 256 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 257 | "requires": { 258 | "is-descriptor": "0.1.6" 259 | } 260 | }, 261 | "extend-shallow": { 262 | "version": "2.0.1", 263 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 264 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 265 | "requires": { 266 | "is-extendable": "0.1.1" 267 | } 268 | }, 269 | "is-accessor-descriptor": { 270 | "version": "0.1.6", 271 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 272 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 273 | "requires": { 274 | "kind-of": "3.2.2" 275 | }, 276 | "dependencies": { 277 | "kind-of": { 278 | "version": "3.2.2", 279 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 280 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 281 | "requires": { 282 | "is-buffer": "1.1.6" 283 | } 284 | } 285 | } 286 | }, 287 | "is-data-descriptor": { 288 | "version": "0.1.4", 289 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 290 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 291 | "requires": { 292 | "kind-of": "3.2.2" 293 | }, 294 | "dependencies": { 295 | "kind-of": { 296 | "version": "3.2.2", 297 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 298 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 299 | "requires": { 300 | "is-buffer": "1.1.6" 301 | } 302 | } 303 | } 304 | }, 305 | "is-descriptor": { 306 | "version": "0.1.6", 307 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 308 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 309 | "requires": { 310 | "is-accessor-descriptor": "0.1.6", 311 | "is-data-descriptor": "0.1.4", 312 | "kind-of": "5.1.0" 313 | } 314 | }, 315 | "kind-of": { 316 | "version": "5.1.0", 317 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 318 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 319 | } 320 | } 321 | }, 322 | "extend-shallow": { 323 | "version": "3.0.2", 324 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 325 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 326 | "requires": { 327 | "assign-symbols": "1.0.0", 328 | "is-extendable": "1.0.1" 329 | }, 330 | "dependencies": { 331 | "is-extendable": { 332 | "version": "1.0.1", 333 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 334 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 335 | "requires": { 336 | "is-plain-object": "2.0.4" 337 | } 338 | } 339 | } 340 | }, 341 | "extglob": { 342 | "version": "2.0.4", 343 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", 344 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", 345 | "requires": { 346 | "array-unique": "0.3.2", 347 | "define-property": "1.0.0", 348 | "expand-brackets": "2.1.4", 349 | "extend-shallow": "2.0.1", 350 | "fragment-cache": "0.2.1", 351 | "regex-not": "1.0.2", 352 | "snapdragon": "0.8.1", 353 | "to-regex": "3.0.2" 354 | }, 355 | "dependencies": { 356 | "define-property": { 357 | "version": "1.0.0", 358 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 359 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 360 | "requires": { 361 | "is-descriptor": "1.0.2" 362 | } 363 | }, 364 | "extend-shallow": { 365 | "version": "2.0.1", 366 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 367 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 368 | "requires": { 369 | "is-extendable": "0.1.1" 370 | } 371 | } 372 | } 373 | }, 374 | "fill-range": { 375 | "version": "4.0.0", 376 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", 377 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", 378 | "requires": { 379 | "extend-shallow": "2.0.1", 380 | "is-number": "3.0.0", 381 | "repeat-string": "1.6.1", 382 | "to-regex-range": "2.1.1" 383 | }, 384 | "dependencies": { 385 | "extend-shallow": { 386 | "version": "2.0.1", 387 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 388 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 389 | "requires": { 390 | "is-extendable": "0.1.1" 391 | } 392 | } 393 | } 394 | }, 395 | "for-in": { 396 | "version": "1.0.2", 397 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 398 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" 399 | }, 400 | "fragment-cache": { 401 | "version": "0.2.1", 402 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", 403 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", 404 | "requires": { 405 | "map-cache": "0.2.2" 406 | } 407 | }, 408 | "get-value": { 409 | "version": "2.0.6", 410 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 411 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" 412 | }, 413 | "has-value": { 414 | "version": "1.0.0", 415 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", 416 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", 417 | "requires": { 418 | "get-value": "2.0.6", 419 | "has-values": "1.0.0", 420 | "isobject": "3.0.1" 421 | } 422 | }, 423 | "has-values": { 424 | "version": "1.0.0", 425 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", 426 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", 427 | "requires": { 428 | "is-number": "3.0.0", 429 | "kind-of": "4.0.0" 430 | }, 431 | "dependencies": { 432 | "kind-of": { 433 | "version": "4.0.0", 434 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 435 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 436 | "requires": { 437 | "is-buffer": "1.1.6" 438 | } 439 | } 440 | } 441 | }, 442 | "is-accessor-descriptor": { 443 | "version": "1.0.0", 444 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 445 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 446 | "requires": { 447 | "kind-of": "6.0.2" 448 | } 449 | }, 450 | "is-buffer": { 451 | "version": "1.1.6", 452 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 453 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 454 | }, 455 | "is-data-descriptor": { 456 | "version": "1.0.0", 457 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 458 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 459 | "requires": { 460 | "kind-of": "6.0.2" 461 | } 462 | }, 463 | "is-descriptor": { 464 | "version": "1.0.2", 465 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 466 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 467 | "requires": { 468 | "is-accessor-descriptor": "1.0.0", 469 | "is-data-descriptor": "1.0.0", 470 | "kind-of": "6.0.2" 471 | } 472 | }, 473 | "is-extendable": { 474 | "version": "0.1.1", 475 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 476 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" 477 | }, 478 | "is-number": { 479 | "version": "3.0.0", 480 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 481 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 482 | "requires": { 483 | "kind-of": "3.2.2" 484 | }, 485 | "dependencies": { 486 | "kind-of": { 487 | "version": "3.2.2", 488 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 489 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 490 | "requires": { 491 | "is-buffer": "1.1.6" 492 | } 493 | } 494 | } 495 | }, 496 | "is-odd": { 497 | "version": "2.0.0", 498 | "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", 499 | "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", 500 | "requires": { 501 | "is-number": "4.0.0" 502 | }, 503 | "dependencies": { 504 | "is-number": { 505 | "version": "4.0.0", 506 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", 507 | "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" 508 | } 509 | } 510 | }, 511 | "is-plain-object": { 512 | "version": "2.0.4", 513 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 514 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 515 | "requires": { 516 | "isobject": "3.0.1" 517 | } 518 | }, 519 | "is-windows": { 520 | "version": "1.0.2", 521 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 522 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" 523 | }, 524 | "isarray": { 525 | "version": "1.0.0", 526 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 527 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 528 | }, 529 | "isexe": { 530 | "version": "2.0.0", 531 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 532 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 533 | }, 534 | "isobject": { 535 | "version": "3.0.1", 536 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 537 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" 538 | }, 539 | "kind-of": { 540 | "version": "6.0.2", 541 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 542 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" 543 | }, 544 | "lazy-cache": { 545 | "version": "2.0.2", 546 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", 547 | "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", 548 | "requires": { 549 | "set-getter": "0.1.0" 550 | } 551 | }, 552 | "map-cache": { 553 | "version": "0.2.2", 554 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", 555 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" 556 | }, 557 | "map-visit": { 558 | "version": "1.0.0", 559 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", 560 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", 561 | "requires": { 562 | "object-visit": "1.0.1" 563 | } 564 | }, 565 | "micromatch": { 566 | "version": "3.1.9", 567 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz", 568 | "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==", 569 | "requires": { 570 | "arr-diff": "4.0.0", 571 | "array-unique": "0.3.2", 572 | "braces": "2.3.1", 573 | "define-property": "2.0.2", 574 | "extend-shallow": "3.0.2", 575 | "extglob": "2.0.4", 576 | "fragment-cache": "0.2.1", 577 | "kind-of": "6.0.2", 578 | "nanomatch": "1.2.9", 579 | "object.pick": "1.3.0", 580 | "regex-not": "1.0.2", 581 | "snapdragon": "0.8.1", 582 | "to-regex": "3.0.2" 583 | } 584 | }, 585 | "mixin-deep": { 586 | "version": "1.3.1", 587 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", 588 | "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", 589 | "requires": { 590 | "for-in": "1.0.2", 591 | "is-extendable": "1.0.1" 592 | }, 593 | "dependencies": { 594 | "is-extendable": { 595 | "version": "1.0.1", 596 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 597 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 598 | "requires": { 599 | "is-plain-object": "2.0.4" 600 | } 601 | } 602 | } 603 | }, 604 | "ms": { 605 | "version": "2.0.0", 606 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 607 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 608 | }, 609 | "nanomatch": { 610 | "version": "1.2.9", 611 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", 612 | "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", 613 | "requires": { 614 | "arr-diff": "4.0.0", 615 | "array-unique": "0.3.2", 616 | "define-property": "2.0.2", 617 | "extend-shallow": "3.0.2", 618 | "fragment-cache": "0.2.1", 619 | "is-odd": "2.0.0", 620 | "is-windows": "1.0.2", 621 | "kind-of": "6.0.2", 622 | "object.pick": "1.3.0", 623 | "regex-not": "1.0.2", 624 | "snapdragon": "0.8.1", 625 | "to-regex": "3.0.2" 626 | } 627 | }, 628 | "nice-try": { 629 | "version": "1.0.4", 630 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", 631 | "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==" 632 | }, 633 | "object-copy": { 634 | "version": "0.1.0", 635 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", 636 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", 637 | "requires": { 638 | "copy-descriptor": "0.1.1", 639 | "define-property": "0.2.5", 640 | "kind-of": "3.2.2" 641 | }, 642 | "dependencies": { 643 | "define-property": { 644 | "version": "0.2.5", 645 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 646 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 647 | "requires": { 648 | "is-descriptor": "0.1.6" 649 | } 650 | }, 651 | "is-accessor-descriptor": { 652 | "version": "0.1.6", 653 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 654 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 655 | "requires": { 656 | "kind-of": "3.2.2" 657 | } 658 | }, 659 | "is-data-descriptor": { 660 | "version": "0.1.4", 661 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 662 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 663 | "requires": { 664 | "kind-of": "3.2.2" 665 | } 666 | }, 667 | "is-descriptor": { 668 | "version": "0.1.6", 669 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 670 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 671 | "requires": { 672 | "is-accessor-descriptor": "0.1.6", 673 | "is-data-descriptor": "0.1.4", 674 | "kind-of": "5.1.0" 675 | }, 676 | "dependencies": { 677 | "kind-of": { 678 | "version": "5.1.0", 679 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 680 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 681 | } 682 | } 683 | }, 684 | "kind-of": { 685 | "version": "3.2.2", 686 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 687 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 688 | "requires": { 689 | "is-buffer": "1.1.6" 690 | } 691 | } 692 | } 693 | }, 694 | "object-visit": { 695 | "version": "1.0.1", 696 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", 697 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", 698 | "requires": { 699 | "isobject": "3.0.1" 700 | } 701 | }, 702 | "object.pick": { 703 | "version": "1.3.0", 704 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 705 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 706 | "requires": { 707 | "isobject": "3.0.1" 708 | } 709 | }, 710 | "pascalcase": { 711 | "version": "0.1.1", 712 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", 713 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" 714 | }, 715 | "path-key": { 716 | "version": "2.0.1", 717 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 718 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" 719 | }, 720 | "posix-character-classes": { 721 | "version": "0.1.1", 722 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 723 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" 724 | }, 725 | "regex-not": { 726 | "version": "1.0.2", 727 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", 728 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", 729 | "requires": { 730 | "extend-shallow": "3.0.2", 731 | "safe-regex": "1.1.0" 732 | } 733 | }, 734 | "repeat-element": { 735 | "version": "1.1.2", 736 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", 737 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" 738 | }, 739 | "repeat-string": { 740 | "version": "1.6.1", 741 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 742 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" 743 | }, 744 | "resolve-url": { 745 | "version": "0.2.1", 746 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 747 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" 748 | }, 749 | "ret": { 750 | "version": "0.1.15", 751 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 752 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" 753 | }, 754 | "safe-regex": { 755 | "version": "1.1.0", 756 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 757 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 758 | "requires": { 759 | "ret": "0.1.15" 760 | } 761 | }, 762 | "semver": { 763 | "version": "5.5.0", 764 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 765 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" 766 | }, 767 | "set-getter": { 768 | "version": "0.1.0", 769 | "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", 770 | "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", 771 | "requires": { 772 | "to-object-path": "0.3.0" 773 | } 774 | }, 775 | "set-value": { 776 | "version": "2.0.0", 777 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", 778 | "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", 779 | "requires": { 780 | "extend-shallow": "2.0.1", 781 | "is-extendable": "0.1.1", 782 | "is-plain-object": "2.0.4", 783 | "split-string": "3.1.0" 784 | }, 785 | "dependencies": { 786 | "extend-shallow": { 787 | "version": "2.0.1", 788 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 789 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 790 | "requires": { 791 | "is-extendable": "0.1.1" 792 | } 793 | } 794 | } 795 | }, 796 | "shebang-command": { 797 | "version": "1.2.0", 798 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 799 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 800 | "requires": { 801 | "shebang-regex": "1.0.0" 802 | } 803 | }, 804 | "shebang-regex": { 805 | "version": "1.0.0", 806 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 807 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" 808 | }, 809 | "snapdragon": { 810 | "version": "0.8.1", 811 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", 812 | "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", 813 | "requires": { 814 | "base": "0.11.2", 815 | "debug": "2.6.9", 816 | "define-property": "0.2.5", 817 | "extend-shallow": "2.0.1", 818 | "map-cache": "0.2.2", 819 | "source-map": "0.5.7", 820 | "source-map-resolve": "0.5.1", 821 | "use": "2.0.2" 822 | }, 823 | "dependencies": { 824 | "define-property": { 825 | "version": "0.2.5", 826 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 827 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 828 | "requires": { 829 | "is-descriptor": "0.1.6" 830 | } 831 | }, 832 | "extend-shallow": { 833 | "version": "2.0.1", 834 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 835 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 836 | "requires": { 837 | "is-extendable": "0.1.1" 838 | } 839 | }, 840 | "is-accessor-descriptor": { 841 | "version": "0.1.6", 842 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 843 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 844 | "requires": { 845 | "kind-of": "3.2.2" 846 | }, 847 | "dependencies": { 848 | "kind-of": { 849 | "version": "3.2.2", 850 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 851 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 852 | "requires": { 853 | "is-buffer": "1.1.6" 854 | } 855 | } 856 | } 857 | }, 858 | "is-data-descriptor": { 859 | "version": "0.1.4", 860 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 861 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 862 | "requires": { 863 | "kind-of": "3.2.2" 864 | }, 865 | "dependencies": { 866 | "kind-of": { 867 | "version": "3.2.2", 868 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 869 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 870 | "requires": { 871 | "is-buffer": "1.1.6" 872 | } 873 | } 874 | } 875 | }, 876 | "is-descriptor": { 877 | "version": "0.1.6", 878 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 879 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 880 | "requires": { 881 | "is-accessor-descriptor": "0.1.6", 882 | "is-data-descriptor": "0.1.4", 883 | "kind-of": "5.1.0" 884 | } 885 | }, 886 | "kind-of": { 887 | "version": "5.1.0", 888 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 889 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 890 | } 891 | } 892 | }, 893 | "snapdragon-node": { 894 | "version": "2.1.1", 895 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", 896 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", 897 | "requires": { 898 | "define-property": "1.0.0", 899 | "isobject": "3.0.1", 900 | "snapdragon-util": "3.0.1" 901 | }, 902 | "dependencies": { 903 | "define-property": { 904 | "version": "1.0.0", 905 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 906 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 907 | "requires": { 908 | "is-descriptor": "1.0.2" 909 | } 910 | } 911 | } 912 | }, 913 | "snapdragon-util": { 914 | "version": "3.0.1", 915 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", 916 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", 917 | "requires": { 918 | "kind-of": "3.2.2" 919 | }, 920 | "dependencies": { 921 | "kind-of": { 922 | "version": "3.2.2", 923 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 924 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 925 | "requires": { 926 | "is-buffer": "1.1.6" 927 | } 928 | } 929 | } 930 | }, 931 | "source-map": { 932 | "version": "0.5.7", 933 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 934 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 935 | }, 936 | "source-map-resolve": { 937 | "version": "0.5.1", 938 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", 939 | "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", 940 | "requires": { 941 | "atob": "2.0.3", 942 | "decode-uri-component": "0.2.0", 943 | "resolve-url": "0.2.1", 944 | "source-map-url": "0.4.0", 945 | "urix": "0.1.0" 946 | } 947 | }, 948 | "source-map-url": { 949 | "version": "0.4.0", 950 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", 951 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" 952 | }, 953 | "split-string": { 954 | "version": "3.1.0", 955 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 956 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 957 | "requires": { 958 | "extend-shallow": "3.0.2" 959 | } 960 | }, 961 | "static-extend": { 962 | "version": "0.1.2", 963 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", 964 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", 965 | "requires": { 966 | "define-property": "0.2.5", 967 | "object-copy": "0.1.0" 968 | }, 969 | "dependencies": { 970 | "define-property": { 971 | "version": "0.2.5", 972 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 973 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 974 | "requires": { 975 | "is-descriptor": "0.1.6" 976 | } 977 | }, 978 | "is-accessor-descriptor": { 979 | "version": "0.1.6", 980 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 981 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 982 | "requires": { 983 | "kind-of": "3.2.2" 984 | }, 985 | "dependencies": { 986 | "kind-of": { 987 | "version": "3.2.2", 988 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 989 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 990 | "requires": { 991 | "is-buffer": "1.1.6" 992 | } 993 | } 994 | } 995 | }, 996 | "is-data-descriptor": { 997 | "version": "0.1.4", 998 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 999 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1000 | "requires": { 1001 | "kind-of": "3.2.2" 1002 | }, 1003 | "dependencies": { 1004 | "kind-of": { 1005 | "version": "3.2.2", 1006 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1007 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1008 | "requires": { 1009 | "is-buffer": "1.1.6" 1010 | } 1011 | } 1012 | } 1013 | }, 1014 | "is-descriptor": { 1015 | "version": "0.1.6", 1016 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 1017 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 1018 | "requires": { 1019 | "is-accessor-descriptor": "0.1.6", 1020 | "is-data-descriptor": "0.1.4", 1021 | "kind-of": "5.1.0" 1022 | } 1023 | }, 1024 | "kind-of": { 1025 | "version": "5.1.0", 1026 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 1027 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 1028 | } 1029 | } 1030 | }, 1031 | "to-object-path": { 1032 | "version": "0.3.0", 1033 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 1034 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 1035 | "requires": { 1036 | "kind-of": "3.2.2" 1037 | }, 1038 | "dependencies": { 1039 | "kind-of": { 1040 | "version": "3.2.2", 1041 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1042 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1043 | "requires": { 1044 | "is-buffer": "1.1.6" 1045 | } 1046 | } 1047 | } 1048 | }, 1049 | "to-regex": { 1050 | "version": "3.0.2", 1051 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", 1052 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", 1053 | "requires": { 1054 | "define-property": "2.0.2", 1055 | "extend-shallow": "3.0.2", 1056 | "regex-not": "1.0.2", 1057 | "safe-regex": "1.1.0" 1058 | } 1059 | }, 1060 | "to-regex-range": { 1061 | "version": "2.1.1", 1062 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", 1063 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", 1064 | "requires": { 1065 | "is-number": "3.0.0", 1066 | "repeat-string": "1.6.1" 1067 | } 1068 | }, 1069 | "union-value": { 1070 | "version": "1.0.0", 1071 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", 1072 | "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", 1073 | "requires": { 1074 | "arr-union": "3.1.0", 1075 | "get-value": "2.0.6", 1076 | "is-extendable": "0.1.1", 1077 | "set-value": "0.4.3" 1078 | }, 1079 | "dependencies": { 1080 | "extend-shallow": { 1081 | "version": "2.0.1", 1082 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1083 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1084 | "requires": { 1085 | "is-extendable": "0.1.1" 1086 | } 1087 | }, 1088 | "set-value": { 1089 | "version": "0.4.3", 1090 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", 1091 | "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", 1092 | "requires": { 1093 | "extend-shallow": "2.0.1", 1094 | "is-extendable": "0.1.1", 1095 | "is-plain-object": "2.0.4", 1096 | "to-object-path": "0.3.0" 1097 | } 1098 | } 1099 | } 1100 | }, 1101 | "unset-value": { 1102 | "version": "1.0.0", 1103 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", 1104 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", 1105 | "requires": { 1106 | "has-value": "0.3.1", 1107 | "isobject": "3.0.1" 1108 | }, 1109 | "dependencies": { 1110 | "has-value": { 1111 | "version": "0.3.1", 1112 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", 1113 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", 1114 | "requires": { 1115 | "get-value": "2.0.6", 1116 | "has-values": "0.1.4", 1117 | "isobject": "2.1.0" 1118 | }, 1119 | "dependencies": { 1120 | "isobject": { 1121 | "version": "2.1.0", 1122 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 1123 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 1124 | "requires": { 1125 | "isarray": "1.0.0" 1126 | } 1127 | } 1128 | } 1129 | }, 1130 | "has-values": { 1131 | "version": "0.1.4", 1132 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", 1133 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" 1134 | } 1135 | } 1136 | }, 1137 | "urix": { 1138 | "version": "0.1.0", 1139 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 1140 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" 1141 | }, 1142 | "use": { 1143 | "version": "2.0.2", 1144 | "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", 1145 | "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", 1146 | "requires": { 1147 | "define-property": "0.2.5", 1148 | "isobject": "3.0.1", 1149 | "lazy-cache": "2.0.2" 1150 | }, 1151 | "dependencies": { 1152 | "define-property": { 1153 | "version": "0.2.5", 1154 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 1155 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 1156 | "requires": { 1157 | "is-descriptor": "0.1.6" 1158 | } 1159 | }, 1160 | "is-accessor-descriptor": { 1161 | "version": "0.1.6", 1162 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 1163 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 1164 | "requires": { 1165 | "kind-of": "3.2.2" 1166 | }, 1167 | "dependencies": { 1168 | "kind-of": { 1169 | "version": "3.2.2", 1170 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1171 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1172 | "requires": { 1173 | "is-buffer": "1.1.6" 1174 | } 1175 | } 1176 | } 1177 | }, 1178 | "is-data-descriptor": { 1179 | "version": "0.1.4", 1180 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 1181 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1182 | "requires": { 1183 | "kind-of": "3.2.2" 1184 | }, 1185 | "dependencies": { 1186 | "kind-of": { 1187 | "version": "3.2.2", 1188 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1189 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1190 | "requires": { 1191 | "is-buffer": "1.1.6" 1192 | } 1193 | } 1194 | } 1195 | }, 1196 | "is-descriptor": { 1197 | "version": "0.1.6", 1198 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 1199 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 1200 | "requires": { 1201 | "is-accessor-descriptor": "0.1.6", 1202 | "is-data-descriptor": "0.1.4", 1203 | "kind-of": "5.1.0" 1204 | } 1205 | }, 1206 | "kind-of": { 1207 | "version": "5.1.0", 1208 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 1209 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 1210 | } 1211 | } 1212 | }, 1213 | "vscode-jsonrpc": { 1214 | "version": "3.5.0", 1215 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", 1216 | "integrity": "sha1-hyOdnhZrLXNSJFuKgTWXgEwdY6o=" 1217 | }, 1218 | "vscode-languageserver": { 1219 | "version": "3.5.0", 1220 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0.tgz", 1221 | "integrity": "sha1-0oCZvG3dqMHdFrcH5FThsd2uDbo=", 1222 | "requires": { 1223 | "vscode-languageserver-protocol": "3.5.0", 1224 | "vscode-uri": "1.0.1" 1225 | } 1226 | }, 1227 | "vscode-languageserver-protocol": { 1228 | "version": "3.5.0", 1229 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz", 1230 | "integrity": "sha1-Bnxcvidwl5U5jRGWksl+u6FFIgk=", 1231 | "requires": { 1232 | "vscode-jsonrpc": "3.5.0", 1233 | "vscode-languageserver-types": "3.5.0" 1234 | } 1235 | }, 1236 | "vscode-languageserver-types": { 1237 | "version": "3.5.0", 1238 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", 1239 | "integrity": "sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=" 1240 | }, 1241 | "vscode-uri": { 1242 | "version": "1.0.1", 1243 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.1.tgz", 1244 | "integrity": "sha1-Eahr7+rDxKo+wIYjZRo8gabQu8g=" 1245 | }, 1246 | "which": { 1247 | "version": "1.3.0", 1248 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", 1249 | "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", 1250 | "requires": { 1251 | "isexe": "2.0.0" 1252 | } 1253 | } 1254 | } 1255 | } 1256 | --------------------------------------------------------------------------------