From 219389f28fc3b36a38ecf521044bc50206cf68e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Thu, 26 Oct 2017 07:54:16 +0200 Subject: [PATCH 1/9] feat: add multi root workspace support (#325) closes #283. --- .travis.yml | 10 +- .vscode/launch.json | 35 +- config/tsconfig.base.json | 6 +- package.json | 61 +-- src/common/config/CodeCompletionConfig.ts | 28 ++ src/common/config/CodeOutlineConfig.ts | 16 +- src/common/config/ExtensionConfig.ts | 39 +- src/common/config/ResolverConfig.ts | 11 + src/common/config/index.ts | 1 + src/common/factories/index.ts | 5 + src/common/helpers/DeclarationIndexHelpers.ts | 95 ++++- src/extension/IoC.ts | 36 +- src/extension/IoCSymbols.ts | 3 +- .../MissingImplementationInClassCreator.ts | 39 +- .../code-actions/MissingImportCreator.ts | 28 +- .../config/VscodeCodeCompletionConfig.ts | 30 ++ .../config/VscodeCodeOutlineConfig.ts | 30 ++ src/extension/config/VscodeExtensionConfig.ts | 86 +++++ .../VscodeResolverConfig.ts} | 149 ++------ .../extensions/CodeActionExtension.ts | 23 +- .../extensions/CodeCompletionExtension.ts | 76 ++-- .../DocumentSymbolStructureExtension.ts | 16 +- .../extensions/ImportResolveExtension.ts | 346 ++++-------------- .../OrganizeImportsOnSaveExtension.ts | 7 +- src/extension/managers/ClassManager.ts | 53 ++- src/extension/managers/ImportManager.ts | 36 +- .../utilities/DeclarationIndexMapper.ts | 174 +++++++++ src/extension/utilities/VscodeLogger.ts | 26 +- test/_workspace/.vscode/settings.json | 4 +- test/_workspace_2/file1.ts | 0 test/_workspace_2/file2.ts | 3 + .../MultiRootIndices.test.ts | 6 + .../{ => multi-root-workspace-tests}/index.ts | 5 +- test/multi-root.code-workspace | 20 + .../common/helpers/ImportHelpers.test.ts | 2 +- .../extensions/CodeActionExtension.test.ts | 55 +-- .../CodeCompletionExtension.test.ts | 47 ++- .../DocumentSymbolStructureExtension.test.ts | 27 +- .../extensions/ImportResolveExtension.test.ts | 51 ++- .../OrganizeImportsOnSaveExtension.test.ts | 10 +- .../ImportGroupSettingParser.test.ts | 5 +- .../KeywordImportGroup.test.ts | 14 +- .../import-grouping/RegexImportGroup.test.ts | 15 +- .../import-grouping/RemainImportGroup.test.ts | 15 +- .../extension/managers/ClassManager.test.ts | 19 +- .../extension/managers/ImportManager.test.ts | 26 +- test/single-workspace-tests/index.ts | 44 +++ 47 files changed, 1077 insertions(+), 756 deletions(-) create mode 100644 src/common/config/CodeCompletionConfig.ts create mode 100644 src/extension/config/VscodeCodeCompletionConfig.ts create mode 100644 src/extension/config/VscodeCodeOutlineConfig.ts create mode 100644 src/extension/config/VscodeExtensionConfig.ts rename src/extension/{VscodeExtensionConfig.ts => config/VscodeResolverConfig.ts} (60%) create mode 100644 src/extension/utilities/DeclarationIndexMapper.ts create mode 100644 test/_workspace_2/file1.ts create mode 100644 test/_workspace_2/file2.ts create mode 100644 test/multi-root-workspace-tests/MultiRootIndices.test.ts rename test/{ => multi-root-workspace-tests}/index.ts (92%) create mode 100644 test/multi-root.code-workspace rename test/{ => single-workspace-tests}/common/helpers/ImportHelpers.test.ts (96%) rename test/{ => single-workspace-tests}/extension/extensions/CodeActionExtension.test.ts (90%) rename test/{ => single-workspace-tests}/extension/extensions/CodeCompletionExtension.test.ts (72%) rename test/{ => single-workspace-tests}/extension/extensions/DocumentSymbolStructureExtension.test.ts (74%) rename test/{ => single-workspace-tests}/extension/extensions/ImportResolveExtension.test.ts (90%) rename test/{ => single-workspace-tests}/extension/extensions/OrganizeImportsOnSaveExtension.test.ts (91%) rename test/{ => single-workspace-tests}/extension/import-grouping/ImportGroupSettingParser.test.ts (97%) rename test/{ => single-workspace-tests}/extension/import-grouping/KeywordImportGroup.test.ts (92%) rename test/{ => single-workspace-tests}/extension/import-grouping/RegexImportGroup.test.ts (86%) rename test/{ => single-workspace-tests}/extension/import-grouping/RemainImportGroup.test.ts (81%) rename test/{ => single-workspace-tests}/extension/managers/ClassManager.test.ts (96%) rename test/{ => single-workspace-tests}/extension/managers/ImportManager.test.ts (97%) create mode 100644 test/single-workspace-tests/index.ts diff --git a/.travis.yml b/.travis.yml index 435d94f..8d5f6f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,6 @@ node_js: notifications: email: false -env: - global: - - CODE_TESTS_WORKSPACE=$TRAVIS_BUILD_DIR/test/_workspace - os: - linux @@ -32,8 +28,8 @@ addons: before_install: - if [ $TRAVIS_OS_NAME == "linux" ]; then export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; - sh -e /etc/init.d/xvfb start; - sleep 3; + sh -e /etc/init.d/xvfb start; + sleep 3; fi - rvm get stable - rvm install 2.4 @@ -42,7 +38,7 @@ before_install: install: - yarn install - + before_script: - greenkeeper-lockfile-update - yarn run build diff --git a/.vscode/launch.json b/.vscode/launch.json index 98daa37..09c7f69 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,14 +17,45 @@ ] }, { - "name": "Launch Tests", + "name": "Launch Extension Multi-Root", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceRoot}/test/multi-root.code-workspace", + "--extensionDevelopmentPath=${workspaceRoot}" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/src/**/*.js" + ] + }, + { + "name": "Launch Tests (single Workspace)", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", "args": [ "${workspaceRoot}/test/_workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test" + "--extensionTestsPath=${workspaceRoot}/out/test/single-workspace-tests/" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/test/single-workspace-tests/**/*.js" + ] + }, + { + "name": "Launch Tests (multi-root Workspace)", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceRoot}/test/multi-root.code-workspace", + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/test/multi-root-workspace-tests/" ], "stopOnEntry": false, "sourceMaps": true, diff --git a/config/tsconfig.base.json b/config/tsconfig.base.json index efe393c..3287faf 100644 --- a/config/tsconfig.base.json +++ b/config/tsconfig.base.json @@ -4,7 +4,8 @@ "target": "es6", "outDir": "../out", "lib": [ - "es6" + "es6", + "es2017" ], "rootDir": "..", "emitDecoratorMetadata": true, @@ -20,6 +21,7 @@ "../test/**/*" ], "exclude": [ - "../test/_workspace" + "../test/_workspace", + "../test/_workspace_2" ] } diff --git a/package.json b/package.json index 7df45c6..c87492b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "version": "0.0.0-development", "publisher": "rbbit", "engines": { - "vscode": "^1.13.0", + "vscode": "^1.17.0", "node": ">=8.0.0", "npm": ">=5.3.0" }, @@ -80,13 +80,15 @@ "predevelop": "del-cli ./out", "develop": "tsc", "postinstall": "test -f ./node_modules/vscode/bin/install && node ./node_modules/vscode/bin/install || echo 'vscode/bin/install not found'", - "pretest": "del-cli ./out && tsc -p ./config/tsconfig.test.json && yarn run lint", - "test": "node ./node_modules/vscode/bin/test", "lint": "tslint -c tslint.json --project ./config/tsconfig.build.json", + "pretest": "del-cli ./out && tsc -p ./config/tsconfig.test.json && yarn lint", + "test": "yarn test:single-workspace", + "test:single-workspace": "CODE_TESTS_WORKSPACE=$(pwd)/test/_workspace CODE_TESTS_PATH=$(pwd)/out/test/single-workspace-tests node ./node_modules/vscode/bin/test", + "test:multi-workspace": "CODE_TESTS_WORKSPACE=$(pwd)/test/multi-root.code-workspace CODE_TESTS_PATH=$(pwd)/out/test/multi-root-workspace-tests node ./node_modules/vscode/bin/test", "build": "del-cli ./out && tsc -p ./config/tsconfig.build.json", - "package": "yarn run build && del-cli './*.vsix' && vsce package", + "package": "yarn build && del-cli './*.vsix' && vsce package", "semantic-release-pre": "semantic-release pre", - "semantic-release": "yarn run semantic-release-pre && vsce package && vsce publish -p $VSCE_TOKEN && yarn install && semantic-release post" + "semantic-release": "yarn semantic-release-pre && vsce package && vsce publish -p $VSCE_TOKEN && yarn install && semantic-release post" }, "devDependencies": { "@types/chai": "^4.0.4", @@ -199,25 +201,29 @@ "All" ], "default": "Warnings", - "description": "Defines the log output level in the output window." + "description": "Defines the log output level in the output window.", + "scope": "window" }, - "typescriptHero.completionSortMode": { + "typescriptHero.codeCompletion.completionSortMode": { "enum": [ "default", "bottom" ], "default": "default", - "description": "Import completion sort order" + "description": "Defines the sortmode of the code completion in intellisense (bottom means sorted to bottom).", + "scope": "resource" }, "typescriptHero.resolver.insertSpaceBeforeAndAfterImportBraces": { "type": "boolean", "default": true, - "description": "Defines if there should be a space inside the curly braces of an import statement." + "description": "Defines if there should be a space inside the curly braces of an import statement.", + "scope": "resource" }, "typescriptHero.resolver.insertSemicolons": { "type": "boolean", "default": true, - "description": "Defines if there should be a semicolon at the end of a statement." + "description": "Defines if there should be a semicolon at the end of a statement.", + "scope": "resource" }, "typescriptHero.resolver.stringQuoteStyle": { "enum": [ @@ -225,7 +231,8 @@ "\"" ], "default": "'", - "description": "Defines if single or double quotes should be used." + "description": "Defines if single or double quotes should be used.", + "scope": "resource" }, "typescriptHero.resolver.ignorePatterns": { "type": "array", @@ -238,24 +245,28 @@ "out", "dist" ], - "description": "Defines partial pathes that are ignored during indexing (e.g. 'node_modules' would exclude all modules)." + "description": "Defines partial pathes that are ignored during indexing (e.g. 'node_modules' would exclude all modules).", + "scope": "resource" }, "typescriptHero.resolver.multiLineWrapThreshold": { "type": "number", "minimum": 1, "multipleOf": 1, "default": 125, - "description": "Defines the threshold when an import should be wrapped into a multiline import." + "description": "Defines the threshold when an import should be wrapped into a multiline import.", + "scope": "resource" }, "typescriptHero.resolver.multiLineTrailingComma": { "type": "boolean", "default": true, - "description": "Defined if multi line imports contain the last trailing comma." + "description": "Defined if multi line imports contain the last trailing comma.", + "scope": "resource" }, "typescriptHero.resolver.disableImportsSorting": { "type": "boolean", "default": false, - "description": "Defines if sorting is disable during organize imports." + "description": "Defines if sorting is disable during organize imports.", + "scope": "resource" }, "typescriptHero.resolver.disableImportRemovalOnOrganize": { "type": "boolean", @@ -265,7 +276,8 @@ "typescriptHero.resolver.organizeOnSave": { "type": "boolean", "default": false, - "description": "Defines if the imports should be organized on save." + "description": "Defines if the imports should be organized on save.", + "scope": "resource" }, "typescriptHero.resolver.ignoreImportsForOrganize": { "type": "array", @@ -276,7 +288,8 @@ "default": [ "react" ], - "description": "Defines imports (libraries, so the 'from' part), which are not removed during 'organize imports'." + "description": "Defines imports (libraries, so the 'from' part), which are not removed during 'organize imports'.", + "scope": "resource" }, "typescriptHero.resolver.importGroups": { "type": "array", @@ -345,7 +358,8 @@ "Modules", "Workspace" ], - "description": "Defines the groups of the imports ordering. Multiple groups possible, see readme for instructions." + "description": "Defines the groups of the imports ordering. Multiple groups possible, see readme for instructions.", + "scope": "resource" }, "typescriptHero.resolver.resolverMode": { "enum": [ @@ -353,18 +367,21 @@ "ES6", "Both" ], - "default": "TypeScript", - "description": "Defines the mode of the symbol resolver (i.e. if JavaScript files should be indexed as well (experimental)." + "default": "Both", + "description": "Defines the mode of the symbol resolver. (Note that JavaScript mode only indexes workspace files)", + "scope": "resource" }, "typescriptHero.resolver.promptForSpecifiers": { "type": "boolean", "default": true, - "description": "Defines if typescript hero should ask the user for default specifiers or duplicate specifier aliases." + "description": "Defines if typescript hero should ask the user for default specifiers or duplicate specifier aliases.", + "scope": "window" }, "typescriptHero.codeOutline.enabled": { "type": "boolean", "default": true, - "description": "Defines if the code outline feature (and window) are enabled or not." + "description": "Defines if the code outline feature (and window) are enabled or not.", + "scope": "window" } } } diff --git a/src/common/config/CodeCompletionConfig.ts b/src/common/config/CodeCompletionConfig.ts new file mode 100644 index 0000000..617bea6 --- /dev/null +++ b/src/common/config/CodeCompletionConfig.ts @@ -0,0 +1,28 @@ +import { Uri } from 'vscode'; + +/** + * Configuration interface for the code outline feature. + * + * @export + * @interface CodeCompletionConfig + */ +export interface CodeCompletionConfig { + /** + * The given resource URI (if any) for the actual configuration. + * Is needed to determine the actual config values for multi root environments. + * + * @readonly + * @type {Uri} + * @memberof CodeCompletionConfig + */ + resource?: Uri; + + /** + * Defines the used completion sort mode (i.e. if the completions should be sorted to the bottom of the list). + * + * @readonly + * @type {('default' | 'bottom')} + * @memberof CodeCompletionConfig + */ + completionSortMode: 'default' | 'bottom'; +} diff --git a/src/common/config/CodeOutlineConfig.ts b/src/common/config/CodeOutlineConfig.ts index 0ae656f..e6c5aee 100644 --- a/src/common/config/CodeOutlineConfig.ts +++ b/src/common/config/CodeOutlineConfig.ts @@ -1,13 +1,25 @@ +import { Uri } from 'vscode'; + /** * Configuration interface for the code outline feature. - * + * * @export * @interface CodeOutlineConfig */ export interface CodeOutlineConfig { + /** + * The given resource URI (if any) for the actual configuration. + * Is needed to determine the actual config values for multi root environments. + * + * @readonly + * @type {Uri} + * @memberof CodeOutlineConfig + */ + resource?: Uri; + /** * Defined if the code outline feature is enabled or not. - * + * * @type {boolean} * @memberof CodeOutlineConfig */ diff --git a/src/common/config/ExtensionConfig.ts b/src/common/config/ExtensionConfig.ts index a090178..7111110 100644 --- a/src/common/config/ExtensionConfig.ts +++ b/src/common/config/ExtensionConfig.ts @@ -1,26 +1,47 @@ +import { Uri } from 'vscode'; + +import { CodeCompletionConfig } from './CodeCompletionConfig'; import { CodeOutlineConfig } from './CodeOutlineConfig'; import { ResolverConfig } from './ResolverConfig'; /** * Configuration interface for TypeScript Hero * Contains all exposed config endpoints. - * + * * @export * @interface ExtensionConfig */ export interface ExtensionConfig { + /** + * The given resource URI (if any) for the actual configuration. + * Is needed to determine the actual config values for multi root environments. + * + * @readonly + * @type {Uri} + * @memberof ExtensionConfig + */ + resource?: Uri; + /** * The actual log level. - * + * * @readonly * @type {string} * @memberof ExtensionConfig */ verbosity: string; + /** + * Returns a list of possible language IDs that are registered within this extension. + * + * @type {string[]} + * @memberof ExtensionConfig + */ + possibleLanguages: string[]; + /** * Configuration object for the resolver extension. - * + * * @readonly * @type {ResolverConfig} * @memberof ExtensionConfig @@ -29,7 +50,7 @@ export interface ExtensionConfig { /** * Configuration object for the code outline extension. - * + * * @readonly * @type {CodeOutlineConfig} * @memberof ExtensionConfig @@ -37,13 +58,11 @@ export interface ExtensionConfig { codeOutline: CodeOutlineConfig; /** - * Completion sorting mode: - * default: Use default VSCode sorting mode - * bottom: Push to bottom - * + * Configuration object for the code completion extension. + * * @readonly - * @type {'default'|'bottom'} + * @type {CodeCompletionConfig} * @memberof ExtensionConfig */ - completionSortMode: 'default' | 'bottom'; + codeCompletion: CodeCompletionConfig; } diff --git a/src/common/config/ResolverConfig.ts b/src/common/config/ResolverConfig.ts index 85ff6d1..0457f80 100644 --- a/src/common/config/ResolverConfig.ts +++ b/src/common/config/ResolverConfig.ts @@ -1,4 +1,5 @@ import { TypescriptGenerationOptions } from 'typescript-parser'; +import { Uri } from 'vscode'; import { ImportGroup } from '../../extension/import-grouping'; import { ResolverMode } from '../enums'; @@ -9,6 +10,16 @@ import { ResolverMode } from '../enums'; * @interface ResolverConfig */ export interface ResolverConfig { + /** + * The given resource URI (if any) for the actual configuration. + * Is needed to determine the actual config values for multi root environments. + * + * @readonly + * @type {Uri} + * @memberof ResolverConfig + */ + resource?: Uri; + /** * Defines, if there should be a space between the brace and the import specifiers. * {Symbol} vs { Symbol } diff --git a/src/common/config/index.ts b/src/common/config/index.ts index 4a95f94..04b8fa7 100644 --- a/src/common/config/index.ts +++ b/src/common/config/index.ts @@ -1,3 +1,4 @@ export * from './ExtensionConfig'; export * from './ResolverConfig'; export * from './CodeOutlineConfig'; +export * from './CodeCompletionConfig'; diff --git a/src/common/factories/index.ts b/src/common/factories/index.ts index 53b7469..3b2f7ee 100644 --- a/src/common/factories/index.ts +++ b/src/common/factories/index.ts @@ -1,6 +1,11 @@ import { TypescriptCodeGenerator } from 'typescript-parser'; +import { Uri } from 'vscode'; + +import { ExtensionConfig } from '../config'; /** * IOC Factory for the {TypescriptCodeGenerator}. */ export type TypescriptCodeGeneratorFactory = () => TypescriptCodeGenerator; + +export type ConfigFactory = (resource?: Uri) => ExtensionConfig; diff --git a/src/common/helpers/DeclarationIndexHelpers.ts b/src/common/helpers/DeclarationIndexHelpers.ts index f131565..fd27adc 100644 --- a/src/common/helpers/DeclarationIndexHelpers.ts +++ b/src/common/helpers/DeclarationIndexHelpers.ts @@ -1,5 +1,9 @@ +import { existsSync } from 'fs'; import { join, normalize, parse, relative } from 'path'; import { DeclarationInfo, ExternalModuleImport, Import, NamedImport, NamespaceImport } from 'typescript-parser'; +import { RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode'; + +import { ExtensionConfig } from '../config'; /** * Calculates a list of declarationInfos filtered by the already imported ones in the given document. @@ -24,15 +28,11 @@ export function getDeclarationsFilteredByImports( const importedLib = getAbsolutLibraryName(tsImport.libraryName, documentPath, rootPath); if (tsImport instanceof NamedImport) { - declarations = declarations - .filter(o => o.from !== importedLib || !(tsImport as NamedImport).specifiers - .some(s => s.specifier === o.declaration.name)); - // if (tsImport.defaultAlias) { - // else if (tsImport instanceof DefaultImport) { - // declarations = declarations - // .filter(o => (!(o.declaration instanceof DefaultDeclaration) || importedLib !== o.from)); - // } - // } + declarations = declarations.filter( + o => o.from !== importedLib || + !tsImport.specifiers.some(s => s.specifier === o.declaration.name), + // || tsImport.defaultAlias !== o.declaration.name, + ); } else if (tsImport instanceof NamespaceImport || tsImport instanceof ExternalModuleImport) { declarations = declarations.filter(o => o.from !== tsImport.libraryName); } @@ -88,3 +88,80 @@ export function getRelativeLibraryName(library: string, actualFilePath: string, } return relativePath.replace(/\\/g, '/'); } + +/** + * This function searches for files in a specific workspace folder. The files are relative to the given + * workspace folder and the searched type is determined by the configuration of the extension (TS, JS or Both mode). + * + * @export + * @param {ExtensionConfig} config + * @param {WorkspaceFolder} workspaceFolder + * @returns {Promise} + */ +export async function findFiles(config: ExtensionConfig, workspaceFolder: WorkspaceFolder): Promise { + const searches: PromiseLike[] = [ + workspace.findFiles( + new RelativePattern(workspaceFolder, `{${config.resolver.resolverModeFileGlobs.join(',')}}`), + new RelativePattern(workspaceFolder, '{**/node_modules/**,**/typings/**}'), + ), + ]; + + // TODO: check the package json and index javascript file in node_modules (?) + + let globs: string[] = []; + let ignores = ['**/typings/**']; + const excludePatterns = config.resolver.ignorePatterns; + const rootPath = workspaceFolder.uri.fsPath; + + if (rootPath && existsSync(join(rootPath, 'package.json'))) { + const packageJson = require(join(rootPath, 'package.json')); + if (packageJson['dependencies']) { + globs = globs.concat( + Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0) + .map(o => `**/node_modules/${o}/**/*.d.ts`), + ); + ignores = ignores.concat( + Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0) + .map(o => `**/node_modules/${o}/node_modules/**`), + ); + } + if (packageJson['devDependencies']) { + globs = globs.concat( + Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0) + .map(o => `**/node_modules/${o}/**/*.d.ts`), + ); + ignores = ignores.concat( + Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0) + .map(o => `**/node_modules/${o}/node_modules/**`), + ); + } + } else { + globs.push('**/node_modules/**/*.d.ts'); + } + + searches.push( + workspace.findFiles( + new RelativePattern(workspaceFolder, `{${globs.join(',')}}`), + new RelativePattern(workspaceFolder, `{${ignores.join(',')}}`), + ), + ); + + searches.push( + workspace.findFiles( + new RelativePattern(workspaceFolder, '**/typings/**/*.d.ts'), + new RelativePattern(workspaceFolder, '**/node_modules/**'), + ), + ); + + let uris = await Promise.all(searches); + + uris = uris.map((o, idx) => idx === 0 ? + o.filter( + f => f.fsPath + .replace(rootPath || '', '') + .split(/\\|\//) + .every(p => excludePatterns.indexOf(p) < 0)) : + o, + ); + return uris.reduce((all, cur) => all.concat(cur), []).map(o => o.fsPath); +} diff --git a/src/extension/IoC.ts b/src/extension/IoC.ts index 095da96..fd4545f 100644 --- a/src/extension/IoC.ts +++ b/src/extension/IoC.ts @@ -1,11 +1,13 @@ import { Container as IoCContainer, interfaces } from 'inversify'; import inversifyInjectDecorators from 'inversify-inject-decorators'; -import { DeclarationIndex, TypescriptCodeGenerator, TypescriptParser } from 'typescript-parser'; -import { ExtensionContext, workspace } from 'vscode'; +import { TypescriptCodeGenerator, TypescriptParser } from 'typescript-parser'; +import { ExtensionContext, Uri } from 'vscode'; import { ExtensionConfig } from '../common/config'; +import { ConfigFactory } from '../common/factories'; import { Logger } from '../common/utilities'; import { CodeActionCreator, MissingImplementationInClassCreator, MissingImportCreator } from './code-actions'; +import { VscodeExtensionConfig } from './config/VscodeExtensionConfig'; import { BaseExtension } from './extensions/BaseExtension'; import { CodeActionExtension } from './extensions/CodeActionExtension'; import { CodeCompletionExtension } from './extensions/CodeCompletionExtension'; @@ -14,38 +16,32 @@ import { ImportResolveExtension } from './extensions/ImportResolveExtension'; import { OrganizeImportsOnSaveExtension } from './extensions/OrganizeImportsOnSaveExtension'; import { iocSymbols } from './IoCSymbols'; import { TypeScriptHero } from './TypeScriptHero'; +import { DeclarationIndexMapper } from './utilities/DeclarationIndexMapper'; import { VscodeLogger } from './utilities/VscodeLogger'; -import { VscodeExtensionConfig } from './VscodeExtensionConfig'; const container = new IoCContainer(); -container.bind(iocSymbols.rootPath).toConstantValue(workspace.rootPath || ''); container.bind(TypeScriptHero).to(TypeScriptHero).inSingletonScope(); -container.bind(iocSymbols.configuration).to(VscodeExtensionConfig).inSingletonScope(); -container - .bind(iocSymbols.declarationIndex) - .toDynamicValue((context: interfaces.Context) => { - const parser = context.container.get(iocSymbols.typescriptParser); - return new DeclarationIndex(parser, context.container.get(iocSymbols.rootPath)); - }) - .inSingletonScope(); + +container.bind(iocSymbols.declarationIndexMapper).to(DeclarationIndexMapper).inSingletonScope(); container .bind(iocSymbols.typescriptParser) - .toDynamicValue(() => { - return new TypescriptParser(); - }) - .inSingletonScope(); + .toConstantValue(new TypescriptParser()); container .bind>(iocSymbols.generatorFactory) .toFactory((context: interfaces.Context) => { - return () => { - const config = context.container.get(iocSymbols.configuration); - return new TypescriptCodeGenerator(config.resolver.generationOptions); + return (resource?: Uri) => { + const configFactory = context.container.get(iocSymbols.configuration); + return new TypescriptCodeGenerator(configFactory(resource).resolver.generationOptions); }; }); +container + .bind>(iocSymbols.configuration) + .toFactory(() => (resource?: Uri) => new VscodeExtensionConfig(resource)); + // Extensions container.bind(iocSymbols.extensions).to(ImportResolveExtension).inSingletonScope(); container.bind(iocSymbols.extensions).to(CodeCompletionExtension).inSingletonScope(); @@ -59,7 +55,7 @@ container .toFactory((context: interfaces.Context) => { return (prefix?: string) => { const extContext = context.container.get(iocSymbols.extensionContext); - const config = context.container.get(iocSymbols.configuration); + const config = context.container.get(iocSymbols.configuration)(); return new VscodeLogger(extContext, config, prefix); }; diff --git a/src/extension/IoCSymbols.ts b/src/extension/IoCSymbols.ts index 193dcec..5fc8ef5 100644 --- a/src/extension/IoCSymbols.ts +++ b/src/extension/IoCSymbols.ts @@ -8,7 +8,6 @@ export const iocSymbols = { loggerFactory: Symbol('loggerFactory'), generatorFactory: Symbol('generatorFactory'), codeActionCreators: Symbol('codeActionCreators'), - declarationIndex: Symbol('declarationIndex'), + declarationIndexMapper: Symbol('declarationIndexMapper'), typescriptParser: Symbol('typescriptParser'), - rootPath: Symbol('rootPath'), }; diff --git a/src/extension/code-actions/MissingImplementationInClassCreator.ts b/src/extension/code-actions/MissingImplementationInClassCreator.ts index f0e1a3b..251f058 100644 --- a/src/extension/code-actions/MissingImplementationInClassCreator.ts +++ b/src/extension/code-actions/MissingImplementationInClassCreator.ts @@ -1,21 +1,16 @@ import { inject, injectable } from 'inversify'; -import { - ClassLikeDeclaration, - DeclarationIndex, - GenericDeclaration, - NamedImport, - TypescriptParser, -} from 'typescript-parser'; -import { Command, Diagnostic, TextDocument } from 'vscode'; +import { ClassLikeDeclaration, GenericDeclaration, NamedImport, TypescriptParser } from 'typescript-parser'; +import { Command, Diagnostic, TextDocument, workspace } from 'vscode'; import { getAbsolutLibraryName } from '../../common/helpers'; import { iocSymbols } from '../IoCSymbols'; +import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { ImplementPolymorphElements, NoopCodeAction } from './CodeAction'; import { CodeActionCreator } from './CodeActionCreator'; /** * Action creator that handles missing implementations in a class. - * + * * @export * @class MissingImplementationInClassCreator * @extends {CodeActionCreator} @@ -24,18 +19,17 @@ import { CodeActionCreator } from './CodeActionCreator'; export class MissingImplementationInClassCreator extends CodeActionCreator { constructor( @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, - @inject(iocSymbols.declarationIndex) private index: DeclarationIndex, - @inject(iocSymbols.rootPath) private rootPath: string, + @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(); } /** * Determines if the given diagnostic can be handled by this creator. - * - * @param {Diagnostic} diagnostic - * @returns {boolean} - * + * + * @param {Diagnostic} diagnostic + * @returns {boolean} + * * @memberof MissingImplementationInClassCreator */ public canHandleDiagnostic(diagnostic: Diagnostic): boolean { @@ -45,19 +39,22 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { /** * Handles the given diagnostic. Must return an array of commands that are given to the light bulb. - * + * * @param {TextDocument} document The commands that are created until now * @param {Command[]} commands The commands that are created until now * @param {Diagnostic} diagnostic The diagnostic to handle - * @returns {Promise} - * + * @returns {Promise} + * * @memberof MissingImplementationInClassCreator */ public async handleDiagnostic(document: TextDocument, commands: Command[], diagnostic: Diagnostic): Promise { const match = /class ['"](.*)['"] incorrectly implements.*['"](.*)['"]\./ig.exec(diagnostic.message) || /non-abstract class ['"](.*)['"].*implement inherited.*from class ['"](.*)['"]\./ig.exec(diagnostic.message); - if (!match) { + const index = this.indices.getIndexForFile(document.uri); + const rootFolder = workspace.getWorkspaceFolder(document.uri); + + if (!match || !index || !rootFolder) { return commands; } @@ -76,9 +73,9 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { o => o instanceof NamedImport && o.specifiers.some(s => s.specifier === specifier), ); const declaration = (parsedDocument.declarations.find(o => o.name === specifier) || - (this.index.declarationInfos.find( + (index.declarationInfos.find( o => o.declaration.name === specifier && - o.from === getAbsolutLibraryName(alreadyImported!.libraryName, document.fileName, this.rootPath), + o.from === getAbsolutLibraryName(alreadyImported!.libraryName, document.fileName, rootFolder.uri.fsPath), ) || { declaration: undefined }).declaration) as (ClassLikeDeclaration & GenericDeclaration) | undefined; if (commands.some((o: Command) => o.title.indexOf(specifier) >= 0)) { diff --git a/src/extension/code-actions/MissingImportCreator.ts b/src/extension/code-actions/MissingImportCreator.ts index 9f490e2..bcdc634 100644 --- a/src/extension/code-actions/MissingImportCreator.ts +++ b/src/extension/code-actions/MissingImportCreator.ts @@ -1,14 +1,14 @@ import { inject, injectable } from 'inversify'; -import { DeclarationIndex } from 'typescript-parser'; import { Command, Diagnostic, TextDocument } from 'vscode'; import { iocSymbols } from '../IoCSymbols'; +import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { AddImportCodeAction, AddMissingImportsCodeAction, NoopCodeAction } from './CodeAction'; import { CodeActionCreator } from './CodeActionCreator'; /** * Action creator that handles missing imports in files. - * + * * @export * @class MissingImportCreator * @extends {CodeActionCreator} @@ -16,17 +16,17 @@ import { CodeActionCreator } from './CodeActionCreator'; @injectable() export class MissingImportCreator extends CodeActionCreator { constructor( - @inject(iocSymbols.declarationIndex) private index: DeclarationIndex, + @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(); } /** * Determines if the given diagnostic can be handled by this creator. - * - * @param {Diagnostic} diagnostic - * @returns {boolean} - * + * + * @param {Diagnostic} diagnostic + * @returns {boolean} + * * @memberof MissingImportCreator */ public canHandleDiagnostic(diagnostic: Diagnostic): boolean { @@ -35,21 +35,23 @@ export class MissingImportCreator extends CodeActionCreator { /** * Handles the given diagnostic. Must return an array of commands that are given to the light bulb. - * + * * @param {TextDocument} document The commands that are created until now * @param {Command[]} commands The commands that are created until now * @param {Diagnostic} diagnostic The diagnostic to handle - * @returns {Promise} - * + * @returns {Promise} + * * @memberof MissingImportCreator */ public async handleDiagnostic(document: TextDocument, commands: Command[], diagnostic: Diagnostic): Promise { const match = /cannot find name ['"](.*)['"]/ig.exec(diagnostic.message); - if (!match) { + const index = this.indices.getIndexForFile(document.uri); + + if (!match || !index) { return commands; } - const infos = this.index.declarationInfos.filter(o => o.declaration.name === match[1]); + const infos = index.declarationInfos.filter(o => o.declaration.name === match[1]); if (infos.length > 0) { for (const info of infos) { commands.push(this.createCommand( @@ -65,7 +67,7 @@ export class MissingImportCreator extends CodeActionCreator { ) { commands.push(this.createCommand( 'Add all missing imports if possible.', - new AddMissingImportsCodeAction(document, this.index), + new AddMissingImportsCodeAction(document, index), )); } } else { diff --git a/src/extension/config/VscodeCodeCompletionConfig.ts b/src/extension/config/VscodeCodeCompletionConfig.ts new file mode 100644 index 0000000..634532e --- /dev/null +++ b/src/extension/config/VscodeCodeCompletionConfig.ts @@ -0,0 +1,30 @@ +import { Uri, workspace, WorkspaceConfiguration } from 'vscode'; + +import { CodeCompletionConfig } from '../../common/config'; + +const sectionKey = 'typescriptHero.codeCompletion'; + +/** + * Configuration interface for the code outline feature. + * + * @class VscodeCodeCompletionConfig + * @implements {CodeCompletionConfig} + */ +export class VscodeCodeCompletionConfig implements CodeCompletionConfig { + private get workspaceSection(): WorkspaceConfiguration { + return workspace.getConfiguration(sectionKey, this.resource); + } + + /** + * Defines the used completion sort mode (i.e. if the completions should be sorted to the bottom of the list). + * + * @readonly + * @type {'default'|'bottom'} + * @memberof VscodeCodeCompletionConfig + */ + public get completionSortMode(): 'default' | 'bottom' { + return this.workspaceSection.get<'default' | 'bottom'>('completionSortMode', 'default'); + } + + constructor(public readonly resource?: Uri) { } +} diff --git a/src/extension/config/VscodeCodeOutlineConfig.ts b/src/extension/config/VscodeCodeOutlineConfig.ts new file mode 100644 index 0000000..4d1db04 --- /dev/null +++ b/src/extension/config/VscodeCodeOutlineConfig.ts @@ -0,0 +1,30 @@ +import { Uri, workspace, WorkspaceConfiguration } from 'vscode'; + +import { CodeOutlineConfig } from '../../common/config'; + +const sectionKey = 'typescriptHero.codeOutline'; + +/** + * Configuration interface for the code outline feature. + * + * @class VscodeCodeOutlineConfig + * @implements {CodeOutlineConfig} + */ +export class VscodeCodeOutlineConfig implements CodeOutlineConfig { + private get workspaceSection(): WorkspaceConfiguration { + return workspace.getConfiguration(sectionKey, this.resource); + } + + /** + * Defined if the code outline feature is enabled or not. + * + * @readonly + * @type {boolean} + * @memberof VscodeCodeOutlineConfig + */ + public get outlineEnabled(): boolean { + return this.workspaceSection.get('enabled', true); + } + + constructor(public readonly resource?: Uri) { } +} diff --git a/src/extension/config/VscodeExtensionConfig.ts b/src/extension/config/VscodeExtensionConfig.ts new file mode 100644 index 0000000..35ac546 --- /dev/null +++ b/src/extension/config/VscodeExtensionConfig.ts @@ -0,0 +1,86 @@ +import { injectable } from 'inversify'; +import { Uri, workspace, WorkspaceConfiguration } from 'vscode'; + +import { CodeCompletionConfig, CodeOutlineConfig, ExtensionConfig, ResolverConfig } from '../../common/config'; +import { VscodeCodeCompletionConfig } from './VscodeCodeCompletionConfig'; +import { VscodeCodeOutlineConfig } from './VscodeCodeOutlineConfig'; +import { VscodeResolverConfig } from './VscodeResolverConfig'; + +const sectionKey = 'typescriptHero'; + +/** + * Configuration class for TypeScript Hero + * Contains all exposed config endpoints. + * + * @export + * @class VscodeExtensionConfig + */ +@injectable() +export class VscodeExtensionConfig implements ExtensionConfig { + public readonly possibleLanguages: string[] = [ + 'typescript', + 'typescriptreact', + 'javascript', + 'javascriptreact', + ]; + + private resolverConfig: ResolverConfig; + private codeOutlineConfig: CodeOutlineConfig; + private codeCompletionConfig: CodeCompletionConfig; + + private get workspaceSection(): WorkspaceConfiguration { + return workspace.getConfiguration(sectionKey, this.resource); + } + + /** + * The actual log level. + * + * @readonly + * @type {string} + * @memberof VscodeExtensionConfig + */ + public get verbosity(): string { + return this.workspaceSection.get('verbosity', 'Warning'); + } + + /** + * Configuration object for the resolver extension. + * + * @readonly + * @type {ResolverConfig} + * @memberof VscodeExtensionConfig + */ + public get resolver(): ResolverConfig { + return this.resolverConfig; + } + + /** + * Configuration object for the code outline extension. + * + * @readonly + * @type {CodeOutlineConfig} + * @memberof VscodeExtensionConfig + */ + public get codeOutline(): CodeOutlineConfig { + return this.codeOutlineConfig; + } + + /** + * Configuration object for the code completion extension. + * + * @readonly + * @type {CodeCompletionConfig} + * @memberof VscodeExtensionConfig + */ + public get codeCompletion(): CodeCompletionConfig { + return this.codeCompletionConfig; + } + + constructor(public readonly resource?: Uri) { + this.codeCompletionConfig = new VscodeCodeCompletionConfig(resource); + this.codeOutlineConfig = new VscodeCodeOutlineConfig(resource); + this.resolverConfig = new VscodeResolverConfig(resource); + } +} + + diff --git a/src/extension/VscodeExtensionConfig.ts b/src/extension/config/VscodeResolverConfig.ts similarity index 60% rename from src/extension/VscodeExtensionConfig.ts rename to src/extension/config/VscodeResolverConfig.ts index 23ac1dc..9e08717 100644 --- a/src/extension/VscodeExtensionConfig.ts +++ b/src/extension/config/VscodeResolverConfig.ts @@ -1,83 +1,20 @@ -import { injectable } from 'inversify'; import { TypescriptGenerationOptions } from 'typescript-parser'; -import { workspace, WorkspaceConfiguration } from 'vscode'; +import { Uri, workspace, WorkspaceConfiguration } from 'vscode'; -import { ExtensionConfig, ResolverConfig } from '../common/config'; -import { CodeOutlineConfig } from '../common/config/CodeOutlineConfig'; -import { ResolverMode } from '../common/enums'; -import { ImportGroup, ImportGroupSetting, ImportGroupSettingParser, RemainImportGroup } from './import-grouping'; +import { ResolverConfig } from '../../common/config'; +import { ResolverMode } from '../../common/enums'; +import { ImportGroup, ImportGroupSetting, ImportGroupSettingParser, RemainImportGroup } from '../import-grouping'; -const sectionKey = 'typescriptHero'; - -/** - * Configuration class for TypeScript Hero - * Contains all exposed config endpoints. - * - * @export - * @class VscodeExtensionConfig - */ -@injectable() -export class VscodeExtensionConfig implements ExtensionConfig { - private resolverConfig: ResolverConfig = new VscodeResolverConfig(); - private codeOutlineConfig: CodeOutlineConfig = new VscodeCodeOutlineConfig(); - - private get workspaceSection(): WorkspaceConfiguration { - return workspace.getConfiguration(sectionKey); - } - - /** - * The actual log level. - * - * @readonly - * @type {string} - * @memberof VscodeExtensionConfig - */ - public get verbosity(): string { - return this.workspaceSection.get('verbosity') || 'Warning'; - } - - /** - * Configuration object for the resolver extension. - * - * @readonly - * @type {ResolverConfig} - * @memberof VscodeExtensionConfig - */ - public get resolver(): ResolverConfig { - return this.resolverConfig; - } - - /** - * Configuration object for the code outline extension. - * - * @readonly - * @type {CodeOutlineConfig} - * @memberof VscodeExtensionConfig - */ - public get codeOutline(): CodeOutlineConfig { - return this.codeOutlineConfig; - } - - /** - * Completion sort mode - * - * @readonly - * @type {'default'|'bottom'} - * @memberof VscodeExtensionConfig - */ - public get completionSortMode(): 'default' | 'bottom' { - return this.workspaceSection.get<'default' | 'bottom'>('completionSortMode') || 'default'; - } -} +const sectionKey = 'typescriptHero.resolver'; /** * Configuration class for the resolver extension. * * @class VscodeResolverConfig */ -class VscodeResolverConfig implements ResolverConfig { +export class VscodeResolverConfig implements ResolverConfig { private get workspaceSection(): WorkspaceConfiguration { - return workspace.getConfiguration(sectionKey); + return workspace.getConfiguration(sectionKey, this.resource); } /** @@ -89,8 +26,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get insertSpaceBeforeAndAfterImportBraces(): boolean { - const value = this.workspaceSection.get('resolver.insertSpaceBeforeAndAfterImportBraces'); - return value !== undefined ? value : true; + return this.workspaceSection.get('insertSpaceBeforeAndAfterImportBraces', true); } /** @@ -102,8 +38,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get insertSemicolons(): boolean { - const value = this.workspaceSection.get('resolver.insertSemicolons'); - return value !== undefined ? value : true; + return this.workspaceSection.get('insertSemicolons', true); } /** @@ -114,7 +49,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get stringQuoteStyle(): string { - return this.workspaceSection.get('resolver.stringQuoteStyle') || `'`; + return this.workspaceSection.get('stringQuoteStyle', `'`); } /** @@ -126,11 +61,14 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get ignorePatterns(): string[] { - return this.workspaceSection.get('resolver.ignorePatterns') || [ - 'build', - 'out', - 'dist', - ]; + return this.workspaceSection.get( + 'ignorePatterns', + [ + 'build', + 'out', + 'dist', + ], + ); } /** @@ -141,7 +79,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get multiLineWrapThreshold(): number { - return this.workspaceSection.get('resolver.multiLineWrapThreshold') || 125; + return this.workspaceSection.get('multiLineWrapThreshold', 125); } /** @@ -158,8 +96,7 @@ class VscodeResolverConfig implements ResolverConfig { * } from 'whatever'; */ public get multiLineTrailingComma(): boolean { - const value = this.workspaceSection.get('resolver.multiLineTrailingComma'); - return value !== undefined ? value : true; + return this.workspaceSection.get('multiLineTrailingComma', true); } /** @@ -170,8 +107,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof ResolverConfig */ public get disableImportSorting(): boolean { - const value = this.workspaceSection.get('resolver.disableImportsSorting'); - return value !== undefined ? value : false; + return this.workspaceSection.get('disableImportsSorting', false); } /** @@ -182,8 +118,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof ResolverConfig */ public get disableImportRemovalOnOrganize(): boolean { - const value = this.workspaceSection.get('resolver.disableImportRemovalOnOrganize'); - return value !== undefined ? value : false; + return this.workspaceSection.get('disableImportRemovalOnOrganize', false); } /** @@ -194,7 +129,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get tabSize(): number { - return workspace.getConfiguration().get('editor.tabSize') || 4; + return workspace.getConfiguration().get('editor.tabSize', 4); } /** @@ -205,7 +140,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get ignoreImportsForOrganize(): string[] { - return this.workspaceSection.get('resolver.ignoreImportsForOrganize') || []; + return this.workspaceSection.get('ignoreImportsForOrganize', []); } /** @@ -215,7 +150,7 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get importGroups(): ImportGroup[] { - const groups = this.workspaceSection.get('resolver.importGroups'); + const groups = this.workspaceSection.get('importGroups'); let importGroups: ImportGroup[] = []; try { @@ -253,14 +188,14 @@ class VscodeResolverConfig implements ResolverConfig { } /** - * Current mode of the resolver. + * Current mode of the * * @readonly * @type {ResolverMode} * @memberof VscodeResolverConfig */ public get resolverMode(): ResolverMode { - const mode = this.workspaceSection.get('resolver.resolverMode', 'TypeScript'); + const mode = this.workspaceSection.get('resolverMode', 'TypeScript'); return ResolverMode[mode] || ResolverMode.TypeScript; } @@ -330,8 +265,8 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get organizeOnSave(): boolean { - const typescriptHeroValue = this.workspaceSection.get('resolver.organizeOnSave', true); - const editorValue = workspace.getConfiguration().get('editor.formatOnSave', false); + const typescriptHeroValue = this.workspaceSection.get('organizeOnSave', false); + const editorValue = workspace.getConfiguration('editor', this.resource).get('formatOnSave', false); return typescriptHeroValue && editorValue; } @@ -344,30 +279,8 @@ class VscodeResolverConfig implements ResolverConfig { * @memberof VscodeResolverConfig */ public get promptForSpecifiers(): boolean { - return this.workspaceSection.get('resolver.promptForSpecifiers', false); + return this.workspaceSection.get('promptForSpecifiers', false); } -} -/** - * Configuration interface for the code outline feature. - * - * @class VscodeCodeOutlineConfig - * @implements {CodeOutlineConfig} - */ -class VscodeCodeOutlineConfig implements CodeOutlineConfig { - private get workspaceSection(): WorkspaceConfiguration { - return workspace.getConfiguration(sectionKey); - } - - /** - * Defined if the code outline feature is enabled or not. - * - * @readonly - * @type {boolean} - * @memberof VscodeCodeOutlineConfig - */ - public get outlineEnabled(): boolean { - const value = this.workspaceSection.get('codeOutline.enabled'); - return value !== undefined ? value : true; - } + constructor(public readonly resource?: Uri) { } } diff --git a/src/extension/extensions/CodeActionExtension.ts b/src/extension/extensions/CodeActionExtension.ts index 94580f2..2634847 100644 --- a/src/extension/extensions/CodeActionExtension.ts +++ b/src/extension/extensions/CodeActionExtension.ts @@ -1,5 +1,4 @@ import { inject, injectable, multiInject } from 'inversify'; -import { DeclarationIndex } from 'typescript-parser'; import { CancellationToken, CodeActionContext, @@ -17,13 +16,14 @@ import { Logger, LoggerFactory } from '../../common/utilities'; import { CodeAction } from '../code-actions/CodeAction'; import { CodeActionCreator } from '../code-actions/CodeActionCreator'; import { iocSymbols } from '../IoCSymbols'; +import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { BaseExtension } from './BaseExtension'; /** * Provider instance that is responsible for the "light bulb" feature. - * It provides actions to take when errors occur in the current document (such as missing imports or + * It provides actions to take when errors occur in the current document (such as missing imports or * non implemented interfaces.). - * + * * @export * @class CodeActionExtension * @implements {CodeActionProvider} @@ -36,7 +36,7 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv @inject(iocSymbols.extensionContext) context: ExtensionContext, @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, @multiInject(iocSymbols.codeActionCreators) private actionCreators: CodeActionCreator[], - @inject(iocSymbols.declarationIndex) private index: DeclarationIndex, + @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(context); this.logger = loggerFactory('CodeActionExtension'); @@ -44,7 +44,7 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv /** * Initialized the extension. Registers the commands and other disposables to the context. - * + * * @memberof ImportResolveExtension */ public initialize(): void { @@ -60,7 +60,7 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv /** * Disposes the extension. - * + * * @memberof ImportResolveExtension */ public dispose(): void { @@ -69,13 +69,13 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv /** * Provides the commands to execute for a given problem. - * + * * @param {TextDocument} document * @param {Range} range * @param {CodeActionContext} context * @param {CancellationToken} token * @returns {Promise} - * + * * @memberof CodeActionExtension */ public async provideCodeActions( @@ -84,7 +84,8 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv context: CodeActionContext, _token: CancellationToken, ): Promise { - if (!this.index.indexReady) { + const index = this.indices.getIndexForFile(document.uri); + if (!index || !index.indexReady) { return []; } @@ -102,11 +103,11 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv /** * Executes a code action. If the result is false, a warning is shown. - * + * * @private * @param {CodeAction} codeAction * @returns {Promise} - * + * * @memberof CodeFixExtension */ private async executeCodeAction(codeAction: CodeAction | undefined): Promise { diff --git a/src/extension/extensions/CodeCompletionExtension.ts b/src/extension/extensions/CodeCompletionExtension.ts index f5eff50..4a01f6d 100644 --- a/src/extension/extensions/CodeCompletionExtension.ts +++ b/src/extension/extensions/CodeCompletionExtension.ts @@ -1,5 +1,5 @@ import { inject, injectable } from 'inversify'; -import { DeclarationIndex, DeclarationInfo, TypescriptParser } from 'typescript-parser'; +import { DeclarationInfo, TypescriptParser } from 'typescript-parser'; import { CancellationToken, commands, @@ -9,21 +9,21 @@ import { languages, Position, TextDocument, - Disposable, workspace, } from 'vscode'; -import { ExtensionConfig } from '../../common/config'; +import { ConfigFactory } from '../../common/factories'; import { getDeclarationsFilteredByImports } from '../../common/helpers'; import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers/ImportManager'; +import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { getItemKind } from '../utilities/utilityFunctions'; import { BaseExtension } from './BaseExtension'; /** * Extension that provides code completion for typescript files. Uses the calculated index to provide information. - * + * * @export * @class CodeCompletionExtension * @extends {BaseExtension} @@ -32,15 +32,13 @@ import { BaseExtension } from './BaseExtension'; @injectable() export class CodeCompletionExtension extends BaseExtension implements CompletionItemProvider { private logger: Logger; - private languageRegisters: Disposable[] = []; constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, - @inject(iocSymbols.declarationIndex) private index: DeclarationIndex, - @inject(iocSymbols.rootPath) private rootPath: string, - @inject(iocSymbols.configuration) private config: ExtensionConfig, + @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, + @inject(iocSymbols.configuration) private config: ConfigFactory, ) { super(context); this.logger = loggerFactory('CodeCompletionExtension'); @@ -48,27 +46,14 @@ export class CodeCompletionExtension extends BaseExtension implements Completion /** * Initialized the extension. Registers the commands and other disposables to the context. - * + * * @memberof CodeCompletionExtension */ public initialize(): void { - for (const lang of this.config.resolver.resolverModeLanguages) { - this.languageRegisters.push(languages.registerCompletionItemProvider(lang, this)); + for (const lang of this.config().possibleLanguages) { + this.context.subscriptions.push(languages.registerCompletionItemProvider(lang, this)); } - this.context.subscriptions.push(workspace.onDidChangeConfiguration(() => { - if (this.languageRegisters.length !== this.config.resolver.resolverModeLanguages.length) { - this.logger.info('ResolverMode has changed, registering to new configuration languages'); - for (const register of this.languageRegisters) { - register.dispose(); - } - this.languageRegisters = []; - for (const lang of this.config.resolver.resolverModeLanguages) { - this.languageRegisters.push(languages.registerCompletionItemProvider(lang, this)); - } - } - })); - this.context.subscriptions.push( commands.registerCommand( 'typescriptHero.codeCompletion.executeIntellisenseItem', @@ -82,24 +67,21 @@ export class CodeCompletionExtension extends BaseExtension implements Completion /** * Disposes the extension. - * + * * @memberof CodeCompletionExtension */ public dispose(): void { - for (const register of this.languageRegisters) { - register.dispose(); - } this.logger.info('Disposed'); } /** * Provides completion items for a given position in the given document. - * - * @param {TextDocument} document - * @param {Position} position - * @param {CancellationToken} token - * @returns {Promise<(CompletionItem[] | null)>} - * + * + * @param {TextDocument} document + * @param {Position} position + * @param {CancellationToken} token + * @returns {Promise<(CompletionItem[] | null)>} + * * @memberof CodeCompletionExtension */ public async provideCompletionItems( @@ -107,7 +89,15 @@ export class CodeCompletionExtension extends BaseExtension implements Completion position: Position, token: CancellationToken, ): Promise { - if (!this.index.indexReady) { + const index = this.indices.getIndexForFile(document.uri); + const config = this.config(document.uri); + const rootFolder = workspace.getWorkspaceFolder(document.uri); + + if (!index || + !index.indexReady || + !config.resolver.resolverModeLanguages.some(lng => lng === document.languageId) || + !rootFolder + ) { return null; } @@ -123,7 +113,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion if (!searchWord || token.isCancellationRequested || - !this.index.indexReady || + !index.indexReady || (lineText.substring(0, position.character).match(/["'`]/g) || []).length % 2 === 1 || lineText.match(/^\s*(\/\/|\/\*\*|\*\/|\*)/g) || lineText.startsWith('import ') || @@ -135,10 +125,10 @@ export class CodeCompletionExtension extends BaseExtension implements Completion const parsed = await this.parser.parseSource(document.getText()); const declarations = getDeclarationsFilteredByImports( - this.index.declarationInfos, + index.declarationInfos, document.fileName, parsed.imports, - this.rootPath, + rootFolder.uri.fsPath, ) .filter(o => !parsed.declarations.some(d => d.name === o.declaration.name)) .filter(o => !parsed.usages.some(d => d === o.declaration.name)); @@ -155,7 +145,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion title: 'Execute intellisense insert', command: 'typescriptHero.codeCompletion.executeIntellisenseItem', }; - if (this.config.completionSortMode === 'bottom') { + if (config.codeCompletion.completionSortMode === 'bottom') { item.sortText = `9999-${declaration.declaration.name}`; } items.push(item); @@ -166,11 +156,11 @@ export class CodeCompletionExtension extends BaseExtension implements Completion /** * Executes a intellisense item that provided a document and a declaration to add. * Does make the calculation of the text edits async. - * + * * @private - * @param {TextDocument} document - * @param {DeclarationInfo} declaration - * @returns {Promise} + * @param {TextDocument} document + * @param {DeclarationInfo} declaration + * @returns {Promise} * @memberof CodeCompletionExtension */ private async executeIntellisenseItem(document: TextDocument, declaration: DeclarationInfo): Promise { diff --git a/src/extension/extensions/DocumentSymbolStructureExtension.ts b/src/extension/extensions/DocumentSymbolStructureExtension.ts index 760b9ad..8332f6d 100644 --- a/src/extension/extensions/DocumentSymbolStructureExtension.ts +++ b/src/extension/extensions/DocumentSymbolStructureExtension.ts @@ -13,7 +13,7 @@ import { workspace, } from 'vscode'; -import { ExtensionConfig } from '../../common/config'; +import { ConfigFactory } from '../../common/factories'; import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { BaseStructureTreeItem } from '../provider-items/document-structure/BaseStructureTreeItem'; @@ -42,7 +42,7 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, - @inject(iocSymbols.configuration) private config: ExtensionConfig, + @inject(iocSymbols.configuration) private config: ConfigFactory, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, ) { super(context); @@ -85,15 +85,17 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T } public async getChildren(element?: BaseStructureTreeItem): Promise> { - if (!this.config.codeOutline.outlineEnabled) { - return [new DisabledStructureTreeItem()]; - } - if (!window.activeTextEditor) { return []; } - if (!this.config.resolver.resolverModeLanguages.some( + const config = this.config(window.activeTextEditor.document.uri); + + if (!config.codeOutline.outlineEnabled) { + return [new DisabledStructureTreeItem()]; + } + + if (!config.resolver.resolverModeLanguages.some( lang => lang === window.activeTextEditor!.document.languageId, )) { return [new NotParseableStructureTreeItem()]; diff --git a/src/extension/extensions/ImportResolveExtension.ts b/src/extension/extensions/ImportResolveExtension.ts index abff4db..f906dd6 100644 --- a/src/extension/extensions/ImportResolveExtension.ts +++ b/src/extension/extensions/ImportResolveExtension.ts @@ -1,122 +1,18 @@ -import { existsSync } from 'fs'; import { inject, injectable } from 'inversify'; -import { join } from 'path'; -import { DeclarationIndex, DeclarationInfo, FileChanges, TypescriptParser } from 'typescript-parser'; -import { - commands, - ExtensionContext, - FileSystemWatcher, - ProgressLocation, - StatusBarAlignment, - StatusBarItem, - Uri, - window, - workspace, -} from 'vscode'; - -import { ExtensionConfig } from '../../common/config'; -import { ResolverMode } from '../../common/enums'; +import { DeclarationInfo, TypescriptParser } from 'typescript-parser'; +import { commands, ExtensionContext, StatusBarAlignment, StatusBarItem, window, workspace } from 'vscode'; + import { getDeclarationsFilteredByImports } from '../../common/helpers'; import { ResolveQuickPickItem } from '../../common/quick-pick-items'; import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers'; +import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { BaseExtension } from './BaseExtension'; type DeclarationsForImportOptions = { cursorSymbol: string, documentSource: string, documentPath: string }; type MissingDeclarationsForFileOptions = { documentSource: string, documentPath: string }; -/** - * Compares the ignorepatterns (if they have the same elements ignored). - * - * @param {string[]} local - * @param {string[]} config - * @returns {boolean} - */ -function compareIgnorePatterns(local: string[], config: string[]): boolean { - if (local.length !== config.length) { - return false; - } - const localSorted = local.sort(); - const configSorted = config.sort(); - - for (let x = 0; x < configSorted.length; x += 1) { - if (configSorted[x] !== localSorted[x]) { - return false; - } - } - - return true; -} - -/** - * Search for typescript / typescript react files in the workspace and return the path to them. - * This is needed for the initial load of the index. - * - * @export - * @param {ExtensionConfig} config - * @returns {Promise} - */ -export async function findFiles(config: ExtensionConfig, rootPath: string): Promise { - const searches: PromiseLike[] = [ - workspace.findFiles( - `{${config.resolver.resolverModeFileGlobs.join(',')}}`, - '{**/node_modules/**,**/typings/**}', - ), - ]; - - // TODO: check the package json and index javascript file in node_modules (?) - - let globs: string[] = []; - let ignores = ['**/typings/**']; - const excludePatterns = config.resolver.ignorePatterns; - - if (rootPath && existsSync(join(rootPath, 'package.json'))) { - const packageJson = require(join(rootPath, 'package.json')); - if (packageJson['dependencies']) { - globs = globs.concat( - Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0) - .map(o => `**/node_modules/${o}/**/*.d.ts`), - ); - ignores = ignores.concat( - Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0) - .map(o => `**/node_modules/${o}/node_modules/**`), - ); - } - if (packageJson['devDependencies']) { - globs = globs.concat( - Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0) - .map(o => `**/node_modules/${o}/**/*.d.ts`), - ); - ignores = ignores.concat( - Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0) - .map(o => `**/node_modules/${o}/node_modules/**`), - ); - } - } else { - globs.push('**/node_modules/**/*.d.ts'); - } - searches.push( - workspace.findFiles(`{${globs.join(',')}}`, `{${ignores.join(',')}}`), - ); - - searches.push( - workspace.findFiles('**/typings/**/*.d.ts', '**/node_modules/**'), - ); - - let uris = await Promise.all(searches); - - uris = uris.map((o, idx) => idx === 0 ? - o.filter( - f => f.fsPath - .replace(rootPath || '', '') - .split(/\\|\//) - .every(p => excludePatterns.indexOf(p) < 0)) : - o, - ); - return uris.reduce((all, cur) => all.concat(cur), []).map(o => o.fsPath); -} - const resolverOk = 'TSH Resolver $(check)'; const resolverSyncing = 'TSH Resolver $(sync)'; const resolverErr = 'TSH Resolver $(flame)'; @@ -124,7 +20,7 @@ const resolverErr = 'TSH Resolver $(flame)'; /** * Extension that resolves imports. Contains various actions to add imports to a document, add missing * imports and organize imports. Also can rebuild the symbol cache. - * + * * @export * @class ImportResolveExtension * @extends {BaseExtension} @@ -133,17 +29,12 @@ const resolverErr = 'TSH Resolver $(flame)'; export class ImportResolveExtension extends BaseExtension { private logger: Logger; private statusBarItem: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left, 4); - private ignorePatterns: string[]; - private fileWatcher: FileSystemWatcher; - private actualMode: ResolverMode; constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, - @inject(iocSymbols.configuration) private config: ExtensionConfig, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, - @inject(iocSymbols.declarationIndex) private index: DeclarationIndex, - @inject(iocSymbols.rootPath) private rootPath: string, + @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(context); this.logger = loggerFactory('ImportResolveExtension'); @@ -151,174 +42,61 @@ export class ImportResolveExtension extends BaseExtension { /** * Initialized the extension. Registers the commands and other disposables to the context. - * + * * @memberof ImportResolveExtension */ public initialize(): void { - this.actualMode = this.config.resolver.resolverMode; - this.ignorePatterns = this.config.resolver.ignorePatterns; - - this.fileWatcher = workspace.createFileSystemWatcher( - `{${this.config.resolver.resolverModeFileGlobs.join(',')},**/package.json,**/typings.json}`, - ); - this.context.subscriptions.push(this.statusBarItem); - this.context.subscriptions.push(this.fileWatcher); this.statusBarItem.text = resolverOk; - this.statusBarItem.tooltip = - `Click to manually reindex all files; Actual mode: ${ResolverMode[this.config.resolver.resolverMode]}`; + this.statusBarItem.tooltip = 'Click to manually reindex all files'; this.statusBarItem.command = 'typescriptHero.resolve.rebuildCache'; + this.context.subscriptions.push(this.indices.onStartIndexing(() => { + this.statusBarItem.text = resolverSyncing; + })); + this.context.subscriptions.push(this.indices.onFinishIndexing(() => { + this.statusBarItem.text = resolverOk; + })); + this.context.subscriptions.push(this.indices.onIndexingError(() => { + this.statusBarItem.text = resolverErr; + })); this.statusBarItem.show(); this.commandRegistrations(); - this.context.subscriptions.push(workspace.onDidChangeConfiguration(() => { - let build = false; - if (!compareIgnorePatterns(this.ignorePatterns, this.config.resolver.ignorePatterns)) { - this.logger.info('The typescriptHero.resolver.ignorePatterns setting was modified, reload the index.'); - this.ignorePatterns = this.config.resolver.ignorePatterns; - build = true; - } - if (this.actualMode !== this.config.resolver.resolverMode) { - this.logger.info('The typescriptHero.resolver.resolverMode setting was modified, reload the index.'); - this.statusBarItem.tooltip = - `Click to manually reindex all files; Actual mode: ${ResolverMode[this.config.resolver.resolverMode]}`; - this.actualMode = this.config.resolver.resolverMode; - build = true; - } - if (build) { - this.buildIndex(); - } - })); - - let timeout: NodeJS.Timer | undefined; - let events: FileChanges | undefined; - - const fileWatcherEvent = (event: string, uri: Uri) => { - if (timeout) { - clearTimeout(timeout); - } - if (!events) { - events = { - created: [], - updated: [], - deleted: [], - }; - } - events[event].push(uri.fsPath); - - timeout = setTimeout( - () => { - if (events) { - this.rebuildForFileChanges(events); - events = undefined; - } - }, - 500, - ); - }; - - this.fileWatcher.onDidCreate(uri => fileWatcherEvent('created', uri)); - this.fileWatcher.onDidChange(uri => fileWatcherEvent('updated', uri)); - this.fileWatcher.onDidDelete(uri => fileWatcherEvent('deleted', uri)); - - this.buildIndex(); - this.logger.info('Initialized'); } /** * Disposes the extension. - * + * * @memberof ImportResolveExtension */ public dispose(): void { this.logger.info('Disposed'); } - /** - * Instructs the index to build an index for the found files (actually searches for all files in the - * current workspace). - * - * @private - * @returns {Promise} - * - * @memberof ImportResolveExtension - */ - private async buildIndex(): Promise { - await this.abstractIndexFunction('Create index.', async () => { - const files = await findFiles(this.config, this.rootPath); - this.logger.info(`Calculating index for ${files.length} files.`); - await this.index.buildIndex(files); - }); - } - - /** - * Instructs the index to rebuild the partial index for the changed files. - * - * @private - * @param {FileChanges} changes - * @returns {Promise} - * @memberof ImportResolveExtension - */ - private async rebuildForFileChanges(changes: FileChanges): Promise { - this.abstractIndexFunction('Reindex changes.', async () => { - await this.index.reindexForChanges(changes); - }); - } - - /** - * Abstracts the build and rebuild functions to be just one call withProgress. - * - * @private - * @param {string} title - * @param {() => Promise} func - * @returns {Promise} - * @memberof ImportResolveExtension - */ - private async abstractIndexFunction(title: string, func: () => Promise): Promise { - await window.withProgress( - { - title, - location: ProgressLocation.Window, - }, - async (progress) => { - this.logger.info('(Re-)Calculating index.'); - progress.report({ message: '(Re-)Calculating index.' }); - this.statusBarItem.text = resolverSyncing; - - try { - await func(); - this.logger.info('(Re-)Calculate finished.'); - progress.report({ message: '(Re-)Calculate finished.' }); - this.statusBarItem.text = resolverOk; - } catch (e) { - this.logger.error('There was an error during the index (re)calculation.', e); - progress.report({ message: 'There was an error during the index (re)calculation.' }); - this.statusBarItem.text = resolverErr; - } - }, - ); - } - /** * Add an import from the whole list. Calls the vscode gui, where the user can * select a symbol to import. - * + * * @private * @returns {Promise} - * + * * @memberof ResolveExtension */ private async addImport(): Promise { - if (!this.index.indexReady) { + if (!window.activeTextEditor) { + return; + } + const index = this.indices.getIndexForFile(window.activeTextEditor.document.uri); + if (!index || !index.indexReady) { this.showCacheWarning(); return; } try { const selectedItem = await window.showQuickPick( - this.index.declarationInfos.map(o => new ResolveQuickPickItem(o)), + index.declarationInfos.map(o => new ResolveQuickPickItem(o)), { placeHolder: 'Add import to document:' }, ); if (selectedItem) { @@ -334,17 +112,18 @@ export class ImportResolveExtension extends BaseExtension { /** * Add an import from the whole list. Calls the vscode gui, where the user can * select a symbol to import. - * + * * @private * @returns {Promise} - * + * * @memberof ImportResolveExtension */ private async addImportUnderCursor(): Promise { if (!window.activeTextEditor) { return; } - if (!this.index.indexReady) { + const index = this.indices.getIndexForFile(window.activeTextEditor.document.uri); + if (!index || !index.indexReady) { this.showCacheWarning(); return; } @@ -384,17 +163,18 @@ export class ImportResolveExtension extends BaseExtension { /** * Adds all missing imports to the actual document if possible. If multiple declarations are found, * a quick pick list is shown to the user and he needs to decide, which import to use. - * + * * @private * @returns {Promise} - * + * * @memberof ImportResolveExtension */ private async addMissingImports(): Promise { if (!window.activeTextEditor) { return; } - if (!this.index.indexReady) { + const index = this.indices.getIndexForFile(window.activeTextEditor.document.uri); + if (!index || !index.indexReady) { this.showCacheWarning(); return; } @@ -417,10 +197,10 @@ export class ImportResolveExtension extends BaseExtension { /** * Organizes the imports of the actual document. Sorts and formats them correctly. - * + * * @private * @returns {Promise} - * + * * @memberof ImportResolveExtension */ private async organizeImports(): Promise { @@ -438,11 +218,11 @@ export class ImportResolveExtension extends BaseExtension { /** * Effectifely adds an import quick pick item to a document - * + * * @private * @param {DeclarationInfo} declaration * @returns {Promise} - * + * * @memberof ImportResolveExtension */ private async addImportToDocument(declaration: DeclarationInfo): Promise { @@ -455,10 +235,10 @@ export class ImportResolveExtension extends BaseExtension { /** * Returns the string under the cursor. - * + * * @private * @returns {string} - * + * * @memberof ImportResolveExtension */ private getSymbolUnderCursor(): string { @@ -474,9 +254,9 @@ export class ImportResolveExtension extends BaseExtension { /** * Shows a user warning if the resolve index is not ready yet. - * + * * @private - * + * * @memberof ImportResolveExtension */ private showCacheWarning(): void { @@ -486,25 +266,35 @@ export class ImportResolveExtension extends BaseExtension { /** * Calculates the possible imports for a given document source with a filter for the given symbol. * Returns a list of declaration infos that may be used for select picker or something. - * + * * @private * @param {DeclarationsForImportOptions} {cursorSymbol, documentSource, documentPath} * @returns {(Promise)} - * + * * @memberof ImportResolveExtension */ private async getDeclarationsForImport( { cursorSymbol, documentSource, documentPath }: DeclarationsForImportOptions, ): Promise { this.logger.info(`Calculate possible imports for document with filter "${cursorSymbol}"`); + if (!window.activeTextEditor) { + return []; + } + + const index = this.indices.getIndexForFile(window.activeTextEditor.document.uri); + const rootFolder = workspace.getWorkspaceFolder(window.activeTextEditor.document.uri); + + if (!index || !index.indexReady || !rootFolder) { + return []; + } const parsedSource = await this.parser.parseSource(documentSource); const activeDocumentDeclarations = parsedSource.declarations.map(o => o.name); const declarations = getDeclarationsFilteredByImports( - this.index.declarationInfos, + index.declarationInfos, documentPath, parsedSource.imports, - this.rootPath, + rootFolder.uri.fsPath, ).filter(o => o.declaration.name.startsWith(cursorSymbol)); return [ @@ -516,24 +306,34 @@ export class ImportResolveExtension extends BaseExtension { /** * Calculates the missing imports of a document. Parses the documents source and then * tries to resolve all possible declaration infos for the usages (used identifiers). - * + * * @private * @param {MissingDeclarationsForFileOptions} {documentSource, documentPath} * @returns {(Promise<(DeclarationInfo | ImportUserDecision)[]>)} - * + * * @memberof ImportResolveExtension */ private async getMissingDeclarationsForFile( { documentSource, documentPath }: MissingDeclarationsForFileOptions, ): Promise<(DeclarationInfo)[]> { - // TODO + if (!window.activeTextEditor) { + return []; + } + + const index = this.indices.getIndexForFile(window.activeTextEditor.document.uri); + const rootFolder = workspace.getWorkspaceFolder(window.activeTextEditor.document.uri); + + if (!index || !index.indexReady || !rootFolder) { + return []; + } + const parsedDocument = await this.parser.parseSource(documentSource); const missingDeclarations: (DeclarationInfo)[] = []; const declarations = getDeclarationsFilteredByImports( - this.index.declarationInfos, + index.declarationInfos, documentPath, parsedDocument.imports, - this.rootPath, + rootFolder.uri.fsPath, ); for (const usage of parsedDocument.nonLocalUsages) { @@ -553,7 +353,7 @@ export class ImportResolveExtension extends BaseExtension { /** * Registers the commands for this extension. - * + * * @private * @memberof ImportResolveExtension */ @@ -576,7 +376,7 @@ export class ImportResolveExtension extends BaseExtension { commands.registerTextEditorCommand('typescriptHero.resolve.organizeImports', () => this.organizeImports()), ); this.context.subscriptions.push( - commands.registerCommand('typescriptHero.resolve.rebuildCache', () => this.buildIndex()), + commands.registerCommand('typescriptHero.resolve.rebuildCache', () => this.indices.rebuildAll()), ); } } diff --git a/src/extension/extensions/OrganizeImportsOnSaveExtension.ts b/src/extension/extensions/OrganizeImportsOnSaveExtension.ts index bdf1a54..c13526f 100644 --- a/src/extension/extensions/OrganizeImportsOnSaveExtension.ts +++ b/src/extension/extensions/OrganizeImportsOnSaveExtension.ts @@ -1,7 +1,7 @@ import { inject, injectable } from 'inversify'; import { ExtensionContext, workspace } from 'vscode'; -import { ExtensionConfig } from '../../common/config'; +import { ConfigFactory } from '../../common/factories'; import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers'; @@ -27,7 +27,7 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, - @inject(iocSymbols.configuration) private config: ExtensionConfig, + @inject(iocSymbols.configuration) private config: ConfigFactory, ) { super(context); this.logger = loggerFactory('OrganizeImportsOnSaveExtension'); @@ -40,7 +40,8 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { */ public initialize(): void { this.context.subscriptions.push(workspace.onWillSaveTextDocument((event) => { - if (!this.config.resolver.organizeOnSave) { + const config = this.config(event.document.uri); + if (!config.resolver.organizeOnSave) { this.logger.info('Organize on save is deactivated through config.'); return; } diff --git a/src/extension/managers/ClassManager.ts b/src/extension/managers/ClassManager.ts index 741faf1..7b77859 100644 --- a/src/extension/managers/ClassManager.ts +++ b/src/extension/managers/ClassManager.ts @@ -11,7 +11,6 @@ import { } from 'typescript-parser'; import { Position, Range, TextDocument, TextEdit, workspace, WorkspaceEdit } from 'vscode'; -import { ExtensionConfig } from '../../common/config'; import { ClassNotFoundError, MethodDuplicated, @@ -29,7 +28,7 @@ type VisibleObject = { visibility?: DeclarationVisibility }; /** * Sortfunction for changeable objects. Does sort the objects by visibility. - * + * * @param {Changeable} o1 * @param {Changeable} o2 * @returns {number} @@ -54,7 +53,7 @@ function sortByVisibility(o1: Changeable, o2: Changeable(iocSymbols.generatorFactory)(); } - private static get config(): ExtensionConfig { - return Container.get(iocSymbols.configuration); - } - private ctor: Changeable; private properties: Changeable[] = []; private methods: Changeable[] = []; @@ -90,12 +85,12 @@ export class ClassManager implements ObjectManager { * Creates an instance of a ClassManager. * Does parse the document text first and returns a promise that * resolves to a ClassManager. - * + * * @static * @param {TextDocument} document The document that should be managed * @param {string} className The name of the class that should be managed * @returns {Promise} - * + * * @memberof ClassManager */ public static async create(document: TextDocument, className: string): Promise { @@ -112,10 +107,10 @@ export class ClassManager implements ObjectManager { /** * Checks if a property with the given name exists on the virtual class. - * + * * @param {string} name * @returns {boolean} - * + * * @memberof ClassManager */ public hasProperty(name: string): boolean { @@ -124,12 +119,12 @@ export class ClassManager implements ObjectManager { /** * Add a property to the virtual class. Creates a Changeable object with the .isNew flag set to true. - * + * * @param {(string | PropertyDeclaration)} nameOrDeclaration * @param {DeclarationVisibility} [visibility] * @param {string} [type] * @returns {this} - * + * * @memberof ClassManager */ public addProperty( @@ -158,10 +153,10 @@ export class ClassManager implements ObjectManager { /** * Remove (aka set isDeleted) a property from the virtual class. - * + * * @param {string} name * @returns {this} - * + * * @memberof ClassManager */ public removeProperty(name: string): this { @@ -181,10 +176,10 @@ export class ClassManager implements ObjectManager { /** * Checks if a method with the given name does exist on the virtual class. - * + * * @param {string} name * @returns {boolean} - * + * * @memberof ClassManager */ public hasMethod(name: string): boolean { @@ -193,13 +188,13 @@ export class ClassManager implements ObjectManager { /** * Add a method to the virtual class. - * + * * @param {(string | MethodDeclaration)} nameOrDeclaration * @param {DeclarationVisibility} [visibility] * @param {string} [type] * @param {ParameterDeclaration[]} [parameters] * @returns {this} - * + * * @memberof ClassManager */ public addMethod( @@ -230,10 +225,10 @@ export class ClassManager implements ObjectManager { /** * Removes a method from the virtual class. - * + * * @param {string} name * @returns {this} - * + * * @memberof ClassManager */ public removeMethod(name: string): this { @@ -257,9 +252,9 @@ export class ClassManager implements ObjectManager { * - Delete properties * - Update changed properties (still TODO) * - Insert new properties - * + * * @returns {Promise} - * + * * @memberof ClassManager */ public async commit(): Promise { @@ -276,11 +271,11 @@ export class ClassManager implements ObjectManager { /** * Determines if a propertydeclaration is injected by the constructor. * I.e. constructor(public foo: string)... - * + * * @private * @param {PropertyDeclaration} property * @returns {boolean} - * + * * @memberof ClassManager */ private isInConstructor(property: PropertyDeclaration): boolean { @@ -293,10 +288,10 @@ export class ClassManager implements ObjectManager { /** * Calculates TextEdits for properties. - * + * * @private * @returns {TextEdit[]} - * + * * @memberof ClassManager */ private calculatePropertyEdits(): TextEdit[] { @@ -338,10 +333,10 @@ export class ClassManager implements ObjectManager { /** * Calculates TextEdits for methods. - * + * * @private * @returns {TextEdit[]} - * + * * @memberof ClassManager */ private calculateMethodEdits(): TextEdit[] { diff --git a/src/extension/managers/ImportManager.ts b/src/extension/managers/ImportManager.ts index 2bc5f0c..9562ba7 100644 --- a/src/extension/managers/ImportManager.ts +++ b/src/extension/managers/ImportManager.ts @@ -17,6 +17,7 @@ import { import { InputBoxOptions, Range, TextDocument, TextEdit, window, workspace, WorkspaceEdit } from 'vscode'; import { ExtensionConfig } from '../../common/config'; +import { ConfigFactory } from '../../common/factories'; import { getAbsolutLibraryName, getDeclarationsFilteredByImports, @@ -55,23 +56,28 @@ export class ImportManager implements ObjectManager { return Container.get(iocSymbols.typescriptParser); } - private static get config(): ExtensionConfig { - return Container.get(iocSymbols.configuration); + private static get config(): ConfigFactory { + return Container.get(iocSymbols.configuration); } private static get generator(): TypescriptCodeGenerator { return Container.get<() => TypescriptCodeGenerator>(iocSymbols.generatorFactory)(); } - private static get rootPath(): string { - return Container.get(iocSymbols.rootPath); - } - private importGroups: ImportGroup[]; private imports: Import[] = []; private userImportDecisions: { [usage: string]: DeclarationInfo[] }[] = []; private organize: boolean; + private get config(): ExtensionConfig { + return ImportManager.config(this.document.uri); + } + + private get rootPath(): string | undefined { + const rootFolder = workspace.getWorkspaceFolder(this.document.uri); + return rootFolder ? rootFolder.uri.fsPath : undefined; + } + /** * Document resource for this controller. Contains the parsed document. * @@ -113,7 +119,7 @@ export class ImportManager implements ObjectManager { */ public reset(): void { this.imports = this._parsedDocument.imports.map(o => o.clone()); - this.importGroups = ImportManager.config.resolver.importGroups; + this.importGroups = this.config.resolver.importGroups; this.addImportsToGroups(this.imports); } @@ -133,7 +139,7 @@ export class ImportManager implements ObjectManager { o => declarationInfo.from === getAbsolutLibraryName( o.libraryName, this.document.fileName, - ImportManager.rootPath, + this.rootPath, ) && o instanceof NamedImport, ) as NamedImport; @@ -149,7 +155,7 @@ export class ImportManager implements ObjectManager { let imp: Import = new NamedImport(getRelativeLibraryName( declarationInfo.from, this.document.fileName, - ImportManager.rootPath, + this.rootPath, )); if (declarationInfo.declaration instanceof ModuleDeclaration) { @@ -183,7 +189,7 @@ export class ImportManager implements ObjectManager { index.declarationInfos, this.document.fileName, this.imports, - ImportManager.rootPath, + this.rootPath, ); for (const usage of this._parsedDocument.nonLocalUsages) { @@ -213,11 +219,11 @@ export class ImportManager implements ObjectManager { this.organize = true; let keep: Import[] = []; - if (ImportManager.config.resolver.disableImportRemovalOnOrganize) { + if (this.config.resolver.disableImportRemovalOnOrganize) { keep = this.imports; } else { for (const actImport of this.imports) { - if (ImportManager.config.resolver.ignoreImportsForOrganize.indexOf(actImport.libraryName) >= 0) { + if (this.config.resolver.ignoreImportsForOrganize.indexOf(actImport.libraryName) >= 0) { keep.push(actImport); continue; } @@ -241,7 +247,7 @@ export class ImportManager implements ObjectManager { } } - if (!ImportManager.config.resolver.disableImportSorting) { + if (!this.config.resolver.disableImportSorting) { keep = [ ...keep.filter(o => o instanceof StringImport).sort(importSort), ...keep.filter(o => !(o instanceof StringImport)).sort(importSort), @@ -432,7 +438,7 @@ export class ImportManager implements ObjectManager { const specifiers = getSpecifiers(); if ( specifiers.filter(o => o === imp.defaultAlias).length > 1 && - ImportManager.config.resolver.promptForSpecifiers + this.config.resolver.promptForSpecifiers ) { imp.defaultAlias = await this.getDefaultIdentifier(imp.defaultAlias); } @@ -442,7 +448,7 @@ export class ImportManager implements ObjectManager { const specifiers = getSpecifiers(); if ( specifiers.filter(o => o === (spec.alias || spec.specifier)).length > 1 && - ImportManager.config.resolver.promptForSpecifiers + this.config.resolver.promptForSpecifiers ) { spec.alias = await this.getSpecifierAlias(spec.alias || spec.specifier); } diff --git a/src/extension/utilities/DeclarationIndexMapper.ts b/src/extension/utilities/DeclarationIndexMapper.ts new file mode 100644 index 0000000..122f784 --- /dev/null +++ b/src/extension/utilities/DeclarationIndexMapper.ts @@ -0,0 +1,174 @@ +import { inject, injectable, postConstruct } from 'inversify'; +import { DeclarationIndex, FileChanges, TypescriptParser } from 'typescript-parser'; +import { + Event, + EventEmitter, + ExtensionContext, + FileSystemWatcher, + RelativePattern, + Uri, + workspace, + WorkspaceFolder, + WorkspaceFoldersChangeEvent, +} from 'vscode'; + +import { ConfigFactory } from '../../common/factories'; +import { findFiles } from '../../common/helpers'; +import { Logger, LoggerFactory } from '../../common/utilities'; +import { iocSymbols } from '../../extension/IoCSymbols'; + +interface WorkspaceIndex { + index: DeclarationIndex; + folder: WorkspaceFolder; + watcher: FileSystemWatcher; +} + +// TODO move did change configuration to all indices +// TODO: update index on change of configs + +@injectable() +export class DeclarationIndexMapper { + public readonly onStartIndexing: Event; + public readonly onFinishIndexing: Event; + public readonly onIndexingError: Event<{ index: WorkspaceIndex, error: Error }>; + + private _onStartIndexing: EventEmitter; + private _onFinishIndexing: EventEmitter; + private _onIndexingError: EventEmitter<{ index: WorkspaceIndex, error: Error }>; + + private logger: Logger; + private indizes: { [uri: string]: WorkspaceIndex } = {}; + + constructor( + @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.extensionContext) private context: ExtensionContext, + @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, + @inject(iocSymbols.configuration) private config: ConfigFactory, + ) { + this._onFinishIndexing = new EventEmitter(); + this._onStartIndexing = new EventEmitter(); + this._onIndexingError = new EventEmitter(); + + this.onFinishIndexing = this._onFinishIndexing.event; + this.onStartIndexing = this._onStartIndexing.event; + this.onIndexingError = this._onIndexingError.event; + + this.context.subscriptions.push(this._onFinishIndexing); + this.context.subscriptions.push(this._onIndexingError); + this.context.subscriptions.push(this._onStartIndexing); + + this.logger = loggerFactory('DeclarationIndexMapper'); + } + + @postConstruct() + public initialize(): void { + this.context.subscriptions.push(workspace.onDidChangeWorkspaceFolders(e => this.workspaceChanged(e))); + this.logger.info( + `Fired up index mapper, got ${(workspace.workspaceFolders || []).length} workspaces.`, + workspace.workspaceFolders, + ); + for (const folder of (workspace.workspaceFolders || []).filter(workspace => workspace.uri.scheme === 'file')) { + this.initializeIndex(folder); + } + this.logger.info('Initialized'); + } + + public rebuildAll(): void { + for (const index of Object.values(this.indizes)) { + index.watcher.dispose(); + index.index.reset(); + } + this.indizes = {}; + for (const folder of (workspace.workspaceFolders || []).filter(workspace => workspace.uri.scheme === 'file')) { + this.initializeIndex(folder); + } + } + + public getIndexForFile(fileUri: Uri): DeclarationIndex | undefined { + const workspaceFolder = workspace.getWorkspaceFolder(fileUri); + if (!workspaceFolder || !this.indizes[workspaceFolder.uri.fsPath]) { + return; + } + + return this.indizes[workspaceFolder.uri.fsPath].index; + } + + private workspaceChanged(event: WorkspaceFoldersChangeEvent): void { + this.logger.info('Workspaces changed.', event); + for (const add of event.added) { + if (this.indizes[add.uri.fsPath]) { + this.logger.warning(`The workspace with the path ${add.uri.fsPath} already exists. Skipping.`); + continue; + } + this.initializeIndex(add); + } + + for (const remove of event.removed) { + this.indizes[remove.uri.fsPath].index.reset(); + this.indizes[remove.uri.fsPath].watcher.dispose(); + delete this.indizes[remove.uri.fsPath]; + } + } + + private async initializeIndex(folder: WorkspaceFolder): Promise { + const index = new DeclarationIndex(this.parser, folder.uri.fsPath); + const config = this.config(folder.uri); + const files = await findFiles(config, folder); + const watcher = workspace.createFileSystemWatcher( + new RelativePattern( + folder, + `{${config.resolver.resolverModeFileGlobs.join(',')},**/package.json,**/typings.json}`, + ), + ); + const workspaceIndex = { + index, + folder, + watcher, + }; + + this._onStartIndexing.fire(workspaceIndex); + + let timeout: NodeJS.Timer | undefined; + let events: FileChanges | undefined; + + const fileWatcherEvent = (event: string, uri: Uri) => { + if (timeout) { + clearTimeout(timeout); + } + if (!events) { + events = { + created: [], + updated: [], + deleted: [], + }; + } + events[event].push(uri.fsPath); + + timeout = setTimeout( + async () => { + if (events) { + this.logger.info(`Refreshing index for workspace ${folder.name}.`); + await index.reindexForChanges(events); + this.logger.info(`Finished indexing for workspace ${folder.name}.`); + events = undefined; + } + }, + 500, + ); + }; + + watcher.onDidCreate(uri => fileWatcherEvent('created', uri)); + watcher.onDidChange(uri => fileWatcherEvent('updated', uri)); + watcher.onDidDelete(uri => fileWatcherEvent('deleted', uri)); + + try { + await index.buildIndex(files); + this.indizes[folder.uri.fsPath] = workspaceIndex; + this.logger.info(`Finished building index for workspace "${folder.name}".`); + this._onFinishIndexing.fire(workspaceIndex); + } catch (error) { + this.logger.error(`Error during build of index for workspace "${folder.name}"`, error); + this._onIndexingError.fire({ error, index: workspaceIndex }); + } + } +} diff --git a/src/extension/utilities/VscodeLogger.ts b/src/extension/utilities/VscodeLogger.ts index a804538..907d96a 100644 --- a/src/extension/utilities/VscodeLogger.ts +++ b/src/extension/utilities/VscodeLogger.ts @@ -5,7 +5,7 @@ import { ExtensionContext, OutputChannel, window } from 'vscode'; /** * Central logger instance of the extension. - * + * * @export * @class VscodeLogger */ @@ -21,10 +21,10 @@ export class VscodeLogger implements Logger { /** * Logs an error message. Provided data is logged out after the message. - * + * * @param {string} message * @param {*} [data] - * + * * @memberof VscodeLogger */ public error(message: string, data?: any): void { @@ -38,10 +38,10 @@ export class VscodeLogger implements Logger { /** * Logs a warning message. Provided data is logged out after the message. - * + * * @param {string} message * @param {*} [data] - * + * * @memberof VscodeLogger */ public warning(message: string, data?: any): void { @@ -55,10 +55,10 @@ export class VscodeLogger implements Logger { /** * Logs an info message. Provided data is logged out after the message. - * + * * @param {string} message * @param {*} [data] - * + * * @memberof VscodeLogger */ public info(message: string, data?: any): void { @@ -73,13 +73,13 @@ export class VscodeLogger implements Logger { /** * Internal method to actually do the logging. Checks if the output should be done and logs * the data into the output channel and the console (if debugging). - * + * * @private * @param {LogLevel} level * @param {string} severity * @param {string} message * @param {*} [data] - * + * * @memberof VscodeLogger */ private log(level: LogLevel, severity: string, message: string, data?: any): void { @@ -101,10 +101,10 @@ export class VscodeLogger implements Logger { /** * Returns a propper formatted date for logging. - * + * * @private * @returns {string} - * + * * @memberof Logger */ private getDate(): string { @@ -127,10 +127,10 @@ export class VscodeLogger implements Logger { /** * Maps the configuration string to a propper enum value of LogLevel. - * + * * @private * @returns {LogLevel} - * + * * @memberof VscodeLogger */ private getLogLevel(): LogLevel { diff --git a/test/_workspace/.vscode/settings.json b/test/_workspace/.vscode/settings.json index e1da5dd..c5f10cc 100755 --- a/test/_workspace/.vscode/settings.json +++ b/test/_workspace/.vscode/settings.json @@ -14,5 +14,7 @@ "typescriptHero.codeOutline.enabled": true, "typescriptHero.resolver.organizeOnSave": false, "typescriptHero.resolver.promptForSpecifiers": true, - "editor.formatOnSave": true + "editor.formatOnSave": true, + "typescriptHero.codeCompletion.completionSortMode": "default", + "typescriptHero.resolver.disableImportRemovalOnOrganize": false } diff --git a/test/_workspace_2/file1.ts b/test/_workspace_2/file1.ts new file mode 100644 index 0000000..e69de29 diff --git a/test/_workspace_2/file2.ts b/test/_workspace_2/file2.ts new file mode 100644 index 0000000..5ef1a5e --- /dev/null +++ b/test/_workspace_2/file2.ts @@ -0,0 +1,3 @@ +export class ClassInFile2 { } + +export default class DefaultClassInFile2 { } diff --git a/test/multi-root-workspace-tests/MultiRootIndices.test.ts b/test/multi-root-workspace-tests/MultiRootIndices.test.ts new file mode 100644 index 0000000..5d02a97 --- /dev/null +++ b/test/multi-root-workspace-tests/MultiRootIndices.test.ts @@ -0,0 +1,6 @@ + +describe('Multi root indices', () => { + + it('should be tested; will be done as soon as the feature is default enabled.'); + +}); diff --git a/test/index.ts b/test/multi-root-workspace-tests/index.ts similarity index 92% rename from test/index.ts rename to test/multi-root-workspace-tests/index.ts index 31f24fd..9956ef9 100644 --- a/test/index.ts +++ b/test/multi-root-workspace-tests/index.ts @@ -2,8 +2,8 @@ import 'reflect-metadata'; import { ExtensionContext, Memento } from 'vscode'; -import { Container } from '../src/extension/IoC'; -import { iocSymbols } from '../src/extension/IoCSymbols'; +import { Container } from '../../src/extension/IoC'; +import { iocSymbols } from '../../src/extension/IoCSymbols'; // tslint:disable @@ -19,7 +19,6 @@ import { iocSymbols } from '../src/extension/IoCSymbols'; // to report the results back to the caller. When the tests are finished, return // a possible error to the callback or null if none. - class ContextMock implements ExtensionContext { subscriptions: { dispose(): any }[] = []; workspaceState: Memento; diff --git a/test/multi-root.code-workspace b/test/multi-root.code-workspace new file mode 100644 index 0000000..7cc4784 --- /dev/null +++ b/test/multi-root.code-workspace @@ -0,0 +1,20 @@ +{ + "folders": [ + { + "path": "_workspace" + }, + { + "path": "_workspace_2" + }, + { + "path": "_workspace/server" + } + ], + "settings": { + "typescriptHero.verbosity": "Warnings", + "typescriptHero.codeOutline.enabled": true, + "typescriptHero.resolver.organizeOnSave": false, + "typescriptHero.resolver.promptForSpecifiers": true, + "editor.formatOnSave": true + } +} diff --git a/test/common/helpers/ImportHelpers.test.ts b/test/single-workspace-tests/common/helpers/ImportHelpers.test.ts similarity index 96% rename from test/common/helpers/ImportHelpers.test.ts rename to test/single-workspace-tests/common/helpers/ImportHelpers.test.ts index 9adafd5..781d69a 100644 --- a/test/common/helpers/ImportHelpers.test.ts +++ b/test/single-workspace-tests/common/helpers/ImportHelpers.test.ts @@ -1,6 +1,6 @@ import * as chai from 'chai'; -import { getImportInsertPosition } from '../../../src/common/helpers'; +import { getImportInsertPosition } from '../../../../src/common/helpers'; chai.should(); diff --git a/test/extension/extensions/CodeActionExtension.test.ts b/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts similarity index 90% rename from test/extension/extensions/CodeActionExtension.test.ts rename to test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts index f9d0acc..d5f6b59 100644 --- a/test/extension/extensions/CodeActionExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts @@ -1,20 +1,24 @@ import * as chai from 'chai'; import { join } from 'path'; import * as sinon from 'sinon'; +import sinonChai = require('sinon-chai'); import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import { ExtensionContext, Position, Range, TextDocument, window, workspace } from 'vscode'; -import { LoggerFactory } from '../../../src/common/utilities'; -import { AddImportCodeAction, CodeAction, ImplementPolymorphElements } from '../../../src/extension/code-actions/CodeAction'; +import { ConfigFactory } from '../../../../src/common/factories'; +import { LoggerFactory } from '../../../../src/common/utilities'; +import { AddImportCodeAction, CodeAction, ImplementPolymorphElements } from '../../../../src/extension/code-actions'; import { MissingImplementationInClassCreator, -} from '../../../src/extension/code-actions/MissingImplementationInClassCreator'; -import { MissingImportCreator } from '../../../src/extension/code-actions/MissingImportCreator'; -import { CodeActionExtension } from '../../../src/extension/extensions/CodeActionExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +} from '../../../../src/extension/code-actions/MissingImplementationInClassCreator'; +import { MissingImportCreator } from '../../../../src/extension/code-actions/MissingImportCreator'; +import { CodeActionExtension } from '../../../../src/extension/extensions/CodeActionExtension'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; chai.should(); +chai.use(sinonChai); class SpyCodeAction implements CodeAction { constructor(private spy: sinon.SinonSpy, private result: boolean) { } @@ -25,18 +29,19 @@ class SpyCodeAction implements CodeAction { } } -const rootPath = Container.get(iocSymbols.rootPath); - describe('CodeActionExtension', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; let extension: any; before(async () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); const parser = Container.get(iocSymbols.typescriptParser); + const config = Container.get(iocSymbols.configuration); + const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); - const index = Container.get(iocSymbols.declarationIndex); + const index = new DeclarationIndex(parser, rootPath); await index.buildIndex( [ join( @@ -58,12 +63,14 @@ describe('CodeActionExtension', () => { ], ); + fakeMapper.getIndexForFile = sinon.spy(() => index); + const creators = [ - new MissingImportCreator(index as any), - new MissingImplementationInClassCreator(parser, index as any, rootPath), + new MissingImportCreator(fakeMapper), + new MissingImplementationInClassCreator(parser, fakeMapper), ]; - extension = new CodeActionExtension(ctx, logger, creators, index as any); + extension = new CodeActionExtension(ctx, logger, creators, fakeMapper); }); describe('executeCodeAction', () => { @@ -187,7 +194,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'Foobar' implement inherited from class 'CodeFixImplementAbstract'.`, + `non-abstract class 'Foobar' implement inherited from class 'CodeFixImplementAbstract'.`, }, ], }, @@ -254,7 +261,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: `non-abstract class 'Foobar' ` + - `implement inherited from class 'GenericAbstractClass'.`, + `implement inherited from class 'GenericAbstractClass'.`, }, ], }, @@ -310,7 +317,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: `non-abstract class 'AbstractImplement' ` + - `implement inherited from class 'CodeFixImplementAbstract'.`, + `implement inherited from class 'CodeFixImplementAbstract'.`, }, ], }, @@ -358,8 +365,8 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'InternalAbstractImplement' ` + - `implement inherited from class 'InternalAbstract'.`, + `non-abstract class 'InternalAbstractImplement' ` + + `implement inherited from class 'InternalAbstract'.`, }, ], }, @@ -380,8 +387,8 @@ describe('CodeActionExtension', () => { { diagnostics: [ { - message: - `class 'ImplementGenericInterface' incorrectly implements 'GenericInterface'.`, + message: `class 'ImplementGenericInterface' incorrectly ` + + `implements 'GenericInterface'.`, }, ], }, @@ -405,8 +412,8 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'ImplementGenericAbstract' ` + - `implement inherited from class 'GenericAbstractClass'.`, + `non-abstract class 'ImplementGenericAbstract' ` + + `implement inherited from class 'GenericAbstractClass'.`, }, ], }, @@ -462,7 +469,7 @@ describe('CodeActionExtension', () => { cmds.should.have.lengthOf(2); const action = cmds[0]; - action.title.should.equal('Import "Class1" from "/server/indices".'); + action.title.should.equal('Import "Class1" from "/server/indices/MyClass".'); action.arguments[0].should.be.an.instanceof(AddImportCodeAction); }); @@ -487,7 +494,7 @@ describe('CodeActionExtension', () => { cmds.should.have.lengthOf(3); let action = cmds[0]; - action.title.should.equal('Import "FancierLibraryClass" from "/server/indices".'); + action.title.should.equal('Import "FancierLibraryClass" from "/server/indices/MyClass".'); action.arguments[0].should.be.an.instanceof(AddImportCodeAction); action = cmds[1]; diff --git a/test/extension/extensions/CodeCompletionExtension.test.ts b/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts similarity index 72% rename from test/extension/extensions/CodeCompletionExtension.test.ts rename to test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts index 8beca1a..a42c6ed 100644 --- a/test/extension/extensions/CodeCompletionExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts @@ -1,24 +1,25 @@ import * as chai from 'chai'; import { join } from 'path'; +import * as sinon from 'sinon'; import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { LoggerFactory } from '../../../src/common/utilities'; -import { CodeCompletionExtension } from '../../../src/extension/extensions/CodeCompletionExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +import { ConfigFactory } from '../../../../src/common/factories'; +import { LoggerFactory } from '../../../../src/common/utilities'; +import { CodeCompletionExtension } from '../../../../src/extension/extensions/CodeCompletionExtension'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; +import { VscodeExtensionConfig } from '../../../../src/extension/config/VscodeExtensionConfig'; const should = chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); - describe('CodeCompletionExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; const token = new vscode.CancellationTokenSource().token; let document: vscode.TextDocument; let extension: CodeCompletionExtension; - let config: ExtensionConfig; before(async () => { const file = join( @@ -31,9 +32,10 @@ describe('CodeCompletionExtension', () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); const parser = Container.get(iocSymbols.typescriptParser); - const index = Container.get(iocSymbols.declarationIndex); - config = Container.get(iocSymbols.configuration); + const config = Container.get(iocSymbols.configuration); + const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); + const index = new DeclarationIndex(parser, rootPath); await index.buildIndex( [ join( @@ -47,7 +49,9 @@ describe('CodeCompletionExtension', () => { ], ); - extension = new CodeCompletionExtension(ctx, logger, parser, index as any, rootPath, config); + fakeMapper.getIndexForFile = sinon.spy(() => index); + + extension = new CodeCompletionExtension(ctx, logger, parser, fakeMapper, config); }); it('shoud resolve to null if typing in a string', async () => { @@ -85,12 +89,21 @@ describe('CodeCompletionExtension', () => { }); it('should use custom sort order when config.completionSortMode is bottom', async () => { - Object.defineProperty(config, 'completionSortMode', { value: 'bottom', writable: true }); - const result = await extension.provideCompletionItems(document, new vscode.Position(6, 5), token); - should.exist(result![0].sortText); - result![0].sortText!.should.equal('9999-MyClass'); - - Object.defineProperty(config, 'completionSortMode', { value: 'default' }); + const orig = (extension as any).config; + const config = new VscodeExtensionConfig(); + (config as any).codeCompletionConfig = { + completionSortMode: 'bottom', + }; + + (extension as any).config = sinon.spy(() => config); + + try { + const result = await extension.provideCompletionItems(document, new vscode.Position(6, 5), token); + should.exist(result![0].sortText); + result![0].sortText!.should.equal('9999-MyClass'); + } finally { + (extension as any).config = orig; + } }); it('shoud add an insert command text edit if import would be new', async () => { diff --git a/test/extension/extensions/DocumentSymbolStructureExtension.test.ts b/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts similarity index 74% rename from test/extension/extensions/DocumentSymbolStructureExtension.test.ts rename to test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts index 817bd95..9930532 100644 --- a/test/extension/extensions/DocumentSymbolStructureExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts @@ -2,27 +2,29 @@ import { join } from 'path'; import { TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { LoggerFactory } from '../../../src/common/utilities'; -import { DocumentSymbolStructureExtension } from '../../../src/extension/extensions/DocumentSymbolStructureExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; -import { BaseStructureTreeItem } from '../../../src/extension/provider-items/document-structure/BaseStructureTreeItem'; +import { ConfigFactory } from '../../../../src/common/factories'; +import { LoggerFactory } from '../../../../src/common/utilities'; +import { DocumentSymbolStructureExtension } from '../../../../src/extension/extensions/DocumentSymbolStructureExtension'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { BaseStructureTreeItem } from '../../../../src/extension/provider-items/document-structure/BaseStructureTreeItem'; import { DeclarationStructureTreeItem, -} from '../../../src/extension/provider-items/document-structure/DeclarationStructureTreeItem'; +} from '../../../../src/extension/provider-items/document-structure/DeclarationStructureTreeItem'; import { DisabledStructureTreeItem, -} from '../../../src/extension/provider-items/document-structure/DisabledStructureTreeItem'; -import { ImportsStructureTreeItem } from '../../../src/extension/provider-items/document-structure/ImportsStructureTreeItem'; +} from '../../../../src/extension/provider-items/document-structure/DisabledStructureTreeItem'; +import { + ImportsStructureTreeItem, +} from '../../../../src/extension/provider-items/document-structure/ImportsStructureTreeItem'; import { NotParseableStructureTreeItem, -} from '../../../src/extension/provider-items/document-structure/NotParseableStructureTreeItem'; +} from '../../../../src/extension/provider-items/document-structure/NotParseableStructureTreeItem'; -const rootPath = Container.get(iocSymbols.rootPath); describe('DocumentSymbolStructureExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; let extension: DocumentSymbolStructureExtension; const file = join( rootPath, @@ -33,7 +35,7 @@ describe('DocumentSymbolStructureExtension', () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); const parser = Container.get(iocSymbols.typescriptParser); - const config = Container.get(iocSymbols.configuration); + const config = Container.get(iocSymbols.configuration); extension = new DocumentSymbolStructureExtension(ctx, logger, config, parser); }); @@ -55,7 +57,6 @@ describe('DocumentSymbolStructureExtension', () => { }); it('should return a "file not parsable" if it is no ts file', async () => { - const rootPath = Container.get(iocSymbols.rootPath); const file = join( rootPath, 'extension/extensions/documentSymbolStructureExtension/notParsable.txt', diff --git a/test/extension/extensions/ImportResolveExtension.test.ts b/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts similarity index 90% rename from test/extension/extensions/ImportResolveExtension.test.ts rename to test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts index d6708c8..906ec3e 100644 --- a/test/extension/extensions/ImportResolveExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts @@ -1,20 +1,22 @@ import * as chai from 'chai'; import { join } from 'path'; +import * as sinon from 'sinon'; import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { LoggerFactory } from '../../../src/common/utilities'; -import { ImportResolveExtension } from '../../../src/extension/extensions/ImportResolveExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +import { ConfigFactory } from '../../../../src/common/factories'; +import { LoggerFactory } from '../../../../src/common/utilities'; +import { ImportResolveExtension } from '../../../../src/extension/extensions/ImportResolveExtension'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); describe('TypeScript Mode: ImportResolveExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; let extension: any; before(async () => { @@ -28,10 +30,11 @@ describe('TypeScript Mode: ImportResolveExtension', () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); - const config = Container.get(iocSymbols.configuration); + const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); + const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); - const index = Container.get(iocSymbols.declarationIndex); + const index = new DeclarationIndex(parser, rootPath); await index.buildIndex( [ join( @@ -53,7 +56,9 @@ describe('TypeScript Mode: ImportResolveExtension', () => { ], ); - extension = new ImportResolveExtension(ctx, logger, config, parser, index, rootPath); + fakeMapper.getIndexForFile = sinon.spy(() => index); + + extension = new ImportResolveExtension(ctx, logger, parser, fakeMapper); }); describe('addImportToDocument', () => { @@ -184,7 +189,7 @@ describe('TypeScript Mode: ImportResolveExtension', () => { }); }); - + describe('organizeImports with exports', () => { const file = join(rootPath, 'extension/extensions/importResolveExtension/organizeImportsWithExports.ts'); @@ -223,6 +228,7 @@ describe('TypeScript Mode: ImportResolveExtension', () => { describe('JavaScript Mode: ImportResolveExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; let extension: any; before(async () => { @@ -236,10 +242,11 @@ describe('JavaScript Mode: ImportResolveExtension', () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); - const config = Container.get(iocSymbols.configuration); + const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); + const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); - const index = Container.get(iocSymbols.declarationIndex); + const index = new DeclarationIndex(parser, rootPath); await index.buildIndex( [ join( @@ -257,7 +264,9 @@ describe('JavaScript Mode: ImportResolveExtension', () => { ], ); - extension = new ImportResolveExtension(ctx, logger, config, parser, index, rootPath); + fakeMapper.getIndexForFile = sinon.spy(() => index); + + extension = new ImportResolveExtension(ctx, logger, parser, fakeMapper); }); describe('addImportToDocument', () => { @@ -318,6 +327,7 @@ describe('JavaScript Mode: ImportResolveExtension', () => { describe('Mixed Mode: ImportResolveExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; let extension: any; before(async () => { @@ -331,10 +341,11 @@ describe('Mixed Mode: ImportResolveExtension', () => { const ctx = Container.get(iocSymbols.extensionContext); const logger = Container.get(iocSymbols.loggerFactory); - const config = Container.get(iocSymbols.configuration); + const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); + const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); - const index = Container.get(iocSymbols.declarationIndex); + const index = new DeclarationIndex(parser, rootPath); await index.buildIndex( [ join( @@ -356,7 +367,9 @@ describe('Mixed Mode: ImportResolveExtension', () => { ], ); - extension = new ImportResolveExtension(ctx, logger, config, parser, index, rootPath); + fakeMapper.getIndexForFile = sinon.spy(() => index); + + extension = new ImportResolveExtension(ctx, logger, parser, fakeMapper); }); describe('addImportToDocument in .js file', () => { @@ -399,7 +412,7 @@ describe('Mixed Mode: ImportResolveExtension', () => { await extension.addImportToDocument(items[0]); document.getText().should.equal(`import { JSFoobar } from './jsfile';\n`); }); - + it('shoud write a named import correctly (TS)', async () => { const items = await extension.getDeclarationsForImport({ cursorSymbol: 'AddImportSameDirectory', @@ -411,7 +424,7 @@ describe('Mixed Mode: ImportResolveExtension', () => { }); }); - + describe('addImportToDocument in .ts file', () => { const file = join( rootPath, @@ -452,7 +465,7 @@ describe('Mixed Mode: ImportResolveExtension', () => { await extension.addImportToDocument(items[0]); document.getText().should.equal(`import { JSFoobar } from './jsfile';\n`); }); - + it('shoud write a named import correctly (TS)', async () => { const items = await extension.getDeclarationsForImport({ cursorSymbol: 'AddImportSameDirectory', diff --git a/test/extension/extensions/OrganizeImportsOnSaveExtension.test.ts b/test/single-workspace-tests/extension/extensions/OrganizeImportsOnSaveExtension.test.ts similarity index 91% rename from test/extension/extensions/OrganizeImportsOnSaveExtension.test.ts rename to test/single-workspace-tests/extension/extensions/OrganizeImportsOnSaveExtension.test.ts index 71d138b..3cda502 100644 --- a/test/extension/extensions/OrganizeImportsOnSaveExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/OrganizeImportsOnSaveExtension.test.ts @@ -3,16 +3,16 @@ import { join } from 'path'; import { DeclarationIndex } from 'typescript-parser'; import * as vscode from 'vscode'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; -import { ImportManager } from '../../../src/extension/managers'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { ImportManager } from '../../../../src/extension/managers'; chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); describe('OrganizeImportsOnSaveExtension', () => { + const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath; let document: vscode.TextDocument; let index: DeclarationIndex; @@ -25,7 +25,7 @@ describe('OrganizeImportsOnSaveExtension', () => { await vscode.window.showTextDocument(document); - index = Container.get(iocSymbols.declarationIndex); + index = new DeclarationIndex(Container.get(iocSymbols.typescriptParser), rootPath); await index.buildIndex( [ join( diff --git a/test/extension/import-grouping/ImportGroupSettingParser.test.ts b/test/single-workspace-tests/extension/import-grouping/ImportGroupSettingParser.test.ts similarity index 97% rename from test/extension/import-grouping/ImportGroupSettingParser.test.ts rename to test/single-workspace-tests/extension/import-grouping/ImportGroupSettingParser.test.ts index f5148ee..2f981c3 100644 --- a/test/extension/import-grouping/ImportGroupSettingParser.test.ts +++ b/test/single-workspace-tests/extension/import-grouping/ImportGroupSettingParser.test.ts @@ -1,11 +1,12 @@ +import * as chai from 'chai'; + import { ImportGroupIdentifierInvalidError, ImportGroupKeyword, ImportGroupSettingParser, KeywordImportGroup, RegexImportGroup, -} from '../../../src/extension/import-grouping'; -import * as chai from 'chai'; +} from '../../../../src/extension/import-grouping'; chai.should(); diff --git a/test/extension/import-grouping/KeywordImportGroup.test.ts b/test/single-workspace-tests/extension/import-grouping/KeywordImportGroup.test.ts similarity index 92% rename from test/extension/import-grouping/KeywordImportGroup.test.ts rename to test/single-workspace-tests/extension/import-grouping/KeywordImportGroup.test.ts index b63f8d6..29c82f2 100644 --- a/test/extension/import-grouping/KeywordImportGroup.test.ts +++ b/test/single-workspace-tests/extension/import-grouping/KeywordImportGroup.test.ts @@ -1,27 +1,25 @@ import * as chai from 'chai'; import { join } from 'path'; import { File, TypescriptCodeGenerator, TypescriptParser } from 'typescript-parser'; +import { workspace } from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { TypescriptCodeGeneratorFactory } from '../../../src/common/factories'; -import { ImportGroupKeyword, KeywordImportGroup } from '../../../src/extension/import-grouping'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +import { TypescriptCodeGeneratorFactory } from '../../../../src/common/factories'; +import { ImportGroupKeyword, KeywordImportGroup } from '../../../../src/extension/import-grouping'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); describe('KeywordImportGroup', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; let file: File; let importGroup: KeywordImportGroup; - let config: ExtensionConfig; let generator: TypescriptCodeGenerator; before(async () => { const parser = Container.get(iocSymbols.typescriptParser); - config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); file = await parser.parseFile( join( diff --git a/test/extension/import-grouping/RegexImportGroup.test.ts b/test/single-workspace-tests/extension/import-grouping/RegexImportGroup.test.ts similarity index 86% rename from test/extension/import-grouping/RegexImportGroup.test.ts rename to test/single-workspace-tests/extension/import-grouping/RegexImportGroup.test.ts index 74b2ed1..49e88c5 100644 --- a/test/extension/import-grouping/RegexImportGroup.test.ts +++ b/test/single-workspace-tests/extension/import-grouping/RegexImportGroup.test.ts @@ -1,27 +1,24 @@ import * as chai from 'chai'; import { join } from 'path'; import { File, NamedImport, TypescriptCodeGenerator, TypescriptParser } from 'typescript-parser'; +import { workspace } from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { TypescriptCodeGeneratorFactory } from '../../../src/common/factories'; -import { RegexImportGroup } from '../../../src/extension/import-grouping'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +import { TypescriptCodeGeneratorFactory } from '../../../../src/common/factories'; +import { RegexImportGroup } from '../../../../src/extension/import-grouping'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); - describe('RegexImportGroup', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; let file: File; let importGroup: RegexImportGroup; - let config: ExtensionConfig; let generator: TypescriptCodeGenerator; before(async () => { const parser = Container.get(iocSymbols.typescriptParser); - config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); file = await parser.parseFile( join( diff --git a/test/extension/import-grouping/RemainImportGroup.test.ts b/test/single-workspace-tests/extension/import-grouping/RemainImportGroup.test.ts similarity index 81% rename from test/extension/import-grouping/RemainImportGroup.test.ts rename to test/single-workspace-tests/extension/import-grouping/RemainImportGroup.test.ts index 54209a0..647b9e9 100644 --- a/test/extension/import-grouping/RemainImportGroup.test.ts +++ b/test/single-workspace-tests/extension/import-grouping/RemainImportGroup.test.ts @@ -1,27 +1,24 @@ import * as chai from 'chai'; import { join } from 'path'; import { File, TypescriptCodeGenerator, TypescriptParser } from 'typescript-parser'; +import { workspace } from 'vscode'; -import { ExtensionConfig } from '../../../src/common/config'; -import { TypescriptCodeGeneratorFactory } from '../../../src/common/factories'; -import { RemainImportGroup } from '../../../src/extension/import-grouping'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; +import { TypescriptCodeGeneratorFactory } from '../../../../src/common/factories'; +import { RemainImportGroup } from '../../../../src/extension/import-grouping'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; chai.should(); -const rootPath = Container.get(iocSymbols.rootPath); - describe('RemainImportGroup', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; let file: File; let importGroup: RemainImportGroup; - let config: ExtensionConfig; let generator: TypescriptCodeGenerator; before(async () => { const parser = Container.get(iocSymbols.typescriptParser); - config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); file = await parser.parseFile( join( diff --git a/test/extension/managers/ClassManager.test.ts b/test/single-workspace-tests/extension/managers/ClassManager.test.ts similarity index 96% rename from test/extension/managers/ClassManager.test.ts rename to test/single-workspace-tests/extension/managers/ClassManager.test.ts index c596860..3abddcd 100644 --- a/test/extension/managers/ClassManager.test.ts +++ b/test/single-workspace-tests/extension/managers/ClassManager.test.ts @@ -10,19 +10,18 @@ import { } from 'typescript-parser'; import { Position, Range, TextDocument, window, workspace } from 'vscode'; -import { findFiles } from '../../../src/extension/extensions/ImportResolveExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; -import { ClassManager } from '../../../src/extension/managers/ClassManager'; -import { VscodeExtensionConfig } from '../../../src/extension/VscodeExtensionConfig'; +import { findFiles } from '../../../../src/common/helpers'; +import { VscodeExtensionConfig } from '../../../../src/extension/config/VscodeExtensionConfig'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { ClassManager } from '../../../../src/extension/managers/ClassManager'; const should = chai.should(); chai.use(sinonChai); -const rootPath = Container.get(iocSymbols.rootPath); - describe('ClassManager', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; const file = join(rootPath, 'extension/managers/ClassManagerFile.ts'); let document: TextDocument; let documentText: string; @@ -30,10 +29,10 @@ describe('ClassManager', () => { let files: string[]; before(async () => { - const config = new VscodeExtensionConfig(); - files = await findFiles(config, rootPath); + const config = new VscodeExtensionConfig(workspace.workspaceFolders![0].uri); + files = await findFiles(config, workspace.workspaceFolders![0]); - index = Container.get(iocSymbols.declarationIndex); + index = new DeclarationIndex(Container.get(iocSymbols.typescriptParser), rootPath); await index.buildIndex(files); document = await workspace.openTextDocument(file); diff --git a/test/extension/managers/ImportManager.test.ts b/test/single-workspace-tests/extension/managers/ImportManager.test.ts similarity index 97% rename from test/extension/managers/ImportManager.test.ts rename to test/single-workspace-tests/extension/managers/ImportManager.test.ts index 04c1250..749c7f2 100644 --- a/test/extension/managers/ImportManager.test.ts +++ b/test/single-workspace-tests/extension/managers/ImportManager.test.ts @@ -5,11 +5,11 @@ import sinonChai = require('sinon-chai'); import { DeclarationIndex, File, NamedImport } from 'typescript-parser'; import { Position, Range, TextDocument, window, workspace } from 'vscode'; -import { findFiles } from '../../../src/extension/extensions/ImportResolveExtension'; -import { Container } from '../../../src/extension/IoC'; -import { iocSymbols } from '../../../src/extension/IoCSymbols'; -import { ImportManager } from '../../../src/extension/managers'; -import { VscodeExtensionConfig } from '../../../src/extension/VscodeExtensionConfig'; +import { findFiles } from '../../../../src/common/helpers'; +import { VscodeExtensionConfig } from '../../../../src/extension/config/VscodeExtensionConfig'; +import { Container } from '../../../../src/extension/IoC'; +import { iocSymbols } from '../../../../src/extension/IoCSymbols'; +import { ImportManager } from '../../../../src/extension/managers'; const should = chai.should(); chai.use(sinonChai); @@ -35,10 +35,9 @@ function restoreInputBox(stub: sinon.SinonStub): void { stub.restore(); } -const rootPath = Container.get(iocSymbols.rootPath); - describe('ImportManager', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; const file = join(rootPath, 'extension/managers/ImportManagerFile.ts'); let document: TextDocument; let documentText: string; @@ -46,10 +45,10 @@ describe('ImportManager', () => { let files: string[]; before(async () => { - const config = new VscodeExtensionConfig(); - files = await findFiles(config, rootPath); + const config = new VscodeExtensionConfig(workspace.workspaceFolders![0].uri); + files = await findFiles(config, workspace.workspaceFolders![0]); - index = index = Container.get(iocSymbols.declarationIndex); + index = new DeclarationIndex(Container.get(iocSymbols.typescriptParser), rootPath); await index.buildIndex(files); document = await workspace.openTextDocument(file); @@ -886,6 +885,7 @@ describe('ImportManager', () => { describe('ImportManager with .tsx files', () => { + const rootPath = workspace.workspaceFolders![0].uri.fsPath; const file = join(rootPath, 'extension/managers/ImportManagerFile.tsx'); let document: TextDocument; let documentText: string; @@ -893,10 +893,10 @@ describe('ImportManager with .tsx files', () => { let files: string[]; before(async () => { - const config = new VscodeExtensionConfig(); - files = await findFiles(config, rootPath); + const config = new VscodeExtensionConfig(workspace.workspaceFolders![0].uri); + files = await findFiles(config, workspace.workspaceFolders![0]); - index = index = Container.get(iocSymbols.declarationIndex); + index = new DeclarationIndex(Container.get(iocSymbols.typescriptParser), rootPath); await index.buildIndex(files); document = await workspace.openTextDocument(file); diff --git a/test/single-workspace-tests/index.ts b/test/single-workspace-tests/index.ts new file mode 100644 index 0000000..9956ef9 --- /dev/null +++ b/test/single-workspace-tests/index.ts @@ -0,0 +1,44 @@ +import 'reflect-metadata'; + +import { ExtensionContext, Memento } from 'vscode'; + +import { Container } from '../../src/extension/IoC'; +import { iocSymbols } from '../../src/extension/IoCSymbols'; + +// tslint:disable + +// +// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING +// +// This file is providing the test runner to use when running extension tests. +// By default the test runner in use is Mocha based. +// +// You can provide your own test runner if you want to override it by exporting +// a function run(testRoot: string, clb: (error:Error) => void) that the extension +// host can call to run the tests. The test runner is expected to use console.log +// to report the results back to the caller. When the tests are finished, return +// a possible error to the callback or null if none. + +class ContextMock implements ExtensionContext { + subscriptions: { dispose(): any }[] = []; + workspaceState: Memento; + globalState: Memento; + extensionPath: string = ''; + storagePath: string = ''; + asAbsolutePath(): string { + return ''; + } +} + +Container.bind(iocSymbols.extensionContext).toConstantValue(new ContextMock()); + +const testRunner = require('vscode/lib/testrunner'); + +// You can directly control Mocha options by uncommenting the following lines +// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info +testRunner.configure({ + ui: 'bdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) + useColors: true // colored output from test results +}); + +module.exports = testRunner; From ae143d79a6c92aa6167f9f8c3b52834b8092322c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Sat, 28 Oct 2017 11:08:49 +0200 Subject: [PATCH 2/9] feat: improve logging and error handling (#326) Adding winstonjs to improve and centralize the logging part of typescript hero. On an uncatched exception, it now asks to show the collected logs in the editor. --- .vscode/launch.json | 6 + package.json | 15 +- src/common/config/ExtensionConfig.ts | 4 +- src/common/utilities/LogLevel.ts | 12 -- src/common/utilities/Logger.ts | 53 ------- src/common/utilities/index.ts | 2 - src/extension/IoC.ts | 19 +-- src/extension/IoCSymbols.ts | 2 +- src/extension/TypeScriptHero.ts | 17 +- src/extension/code-actions/CodeAction.ts | 61 +++++-- .../MissingImplementationInClassCreator.ts | 21 +++ .../code-actions/MissingImportCreator.ts | 20 +++ src/extension/config/VscodeExtensionConfig.ts | 10 +- .../extensions/CodeActionExtension.ts | 22 ++- .../extensions/CodeCompletionExtension.ts | 31 +++- .../DocumentSymbolStructureExtension.ts | 19 ++- .../extensions/ImportResolveExtension.ts | 95 +++++++++-- .../OrganizeImportsOnSaveExtension.ts | 27 ++-- src/extension/managers/ClassManager.ts | 35 ++++ src/extension/managers/ImportManager.ts | 31 ++++ .../utilities/DeclarationIndexMapper.ts | 73 +++++++-- src/extension/utilities/VscodeLogger.ts | 148 ----------------- src/extension/utilities/winstonLogger.ts | 150 ++++++++++++++++++ test/_workspace/.vscode/settings.json | 2 +- .../extensions/CodeActionExtension.test.ts | 24 +-- .../CodeCompletionExtension.test.ts | 6 +- .../DocumentSymbolStructureExtension.test.ts | 4 +- .../extensions/ImportResolveExtension.test.ts | 8 +- yarn.lock | 102 +++++++++++- 29 files changed, 671 insertions(+), 348 deletions(-) delete mode 100644 src/common/utilities/LogLevel.ts delete mode 100644 src/common/utilities/Logger.ts delete mode 100644 src/common/utilities/index.ts delete mode 100644 src/extension/utilities/VscodeLogger.ts create mode 100644 src/extension/utilities/winstonLogger.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 09c7f69..5af24ef 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,6 +10,9 @@ "${workspaceRoot}/test/_workspace", "--extensionDevelopmentPath=${workspaceRoot}" ], + "env": { + "EXT_DEBUG": "true" + }, "stopOnEntry": false, "sourceMaps": true, "outFiles": [ @@ -25,6 +28,9 @@ "${workspaceRoot}/test/multi-root.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}" ], + "env": { + "EXT_DEBUG": "true" + }, "stopOnEntry": false, "sourceMaps": true, "outFiles": [ diff --git a/package.json b/package.json index c87492b..07dbc19 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,8 @@ "reflect-metadata": "^0.1.10", "tslib": "^1.7.1", "typescript": "~2.5.3", - "typescript-parser": "^2.0.0" + "typescript-parser": "^2.0.0", + "winston": "^3.0.0-rc1" }, "activationEvents": [ "onLanguage:typescript", @@ -195,13 +196,13 @@ "properties": { "typescriptHero.verbosity": { "enum": [ - "Nothing", - "Errors", - "Warnings", - "All" + "error", + "warn", + "info", + "debug" ], - "default": "Warnings", - "description": "Defines the log output level in the output window.", + "default": "warn", + "description": "Defines the log output level in the output window. In the log file, it's always info or debug.", "scope": "window" }, "typescriptHero.codeCompletion.completionSortMode": { diff --git a/src/common/config/ExtensionConfig.ts b/src/common/config/ExtensionConfig.ts index 7111110..22e0e6c 100644 --- a/src/common/config/ExtensionConfig.ts +++ b/src/common/config/ExtensionConfig.ts @@ -26,10 +26,10 @@ export interface ExtensionConfig { * The actual log level. * * @readonly - * @type {string} + * @type {'error' | 'warn' | 'info' | 'debug'} * @memberof ExtensionConfig */ - verbosity: string; + verbosity: 'error' | 'warn' | 'info' | 'debug'; /** * Returns a list of possible language IDs that are registered within this extension. diff --git a/src/common/utilities/LogLevel.ts b/src/common/utilities/LogLevel.ts deleted file mode 100644 index 98f696b..0000000 --- a/src/common/utilities/LogLevel.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Enum for the log level. Determines if a message is logged into the output. - * - * @export - * @enum {number} - */ -export const enum LogLevel { - Nothing, - Errors, - Warnings, - All, -} diff --git a/src/common/utilities/Logger.ts b/src/common/utilities/Logger.ts deleted file mode 100644 index 647891c..0000000 --- a/src/common/utilities/Logger.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Factory type for IoC. - * - * @typedef LoggerFactory - */ -export type LoggerFactory = (prefix?: string) => Logger; - -/** - * Interface for logging instances, implement the basic methods needed for logging. - * If a prefix is provided, it should use it before all messages. - * - * @export - * @interface Logger - */ -export interface Logger { - /** - * The prefix used for the messages. - * - * @type {string} - * @memberof Logger - */ - readonly prefix?: string; - - /** - * Logs a message marked as error. If additional data is provided, it's logged as well. - * - * @param {string} message - * @param {*} [data] - * - * @memberof Logger - */ - error(message: string, data?: any): void; - - /** - * Logs a message marked as warning. If additional data is provided, it's logged as well. - * - * @param {string} message - * @param {*} [data] - * - * @memberof Logger - */ - warning(message: string, data?: any): void; - - /** - * Logs a message marked as info. If additional data is provided, it's logged as well. - * - * @param {string} message - * @param {*} [data] - * - * @memberof Logger - */ - info(message: string, data?: any): void; -} diff --git a/src/common/utilities/index.ts b/src/common/utilities/index.ts deleted file mode 100644 index 6df4e82..0000000 --- a/src/common/utilities/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './LogLevel'; -export * from './Logger'; diff --git a/src/extension/IoC.ts b/src/extension/IoC.ts index fd4545f..9c540e5 100644 --- a/src/extension/IoC.ts +++ b/src/extension/IoC.ts @@ -5,7 +5,6 @@ import { ExtensionContext, Uri } from 'vscode'; import { ExtensionConfig } from '../common/config'; import { ConfigFactory } from '../common/factories'; -import { Logger } from '../common/utilities'; import { CodeActionCreator, MissingImplementationInClassCreator, MissingImportCreator } from './code-actions'; import { VscodeExtensionConfig } from './config/VscodeExtensionConfig'; import { BaseExtension } from './extensions/BaseExtension'; @@ -17,7 +16,7 @@ import { OrganizeImportsOnSaveExtension } from './extensions/OrganizeImportsOnSa import { iocSymbols } from './IoCSymbols'; import { TypeScriptHero } from './TypeScriptHero'; import { DeclarationIndexMapper } from './utilities/DeclarationIndexMapper'; -import { VscodeLogger } from './utilities/VscodeLogger'; +import winstonLogger, { Logger } from './utilities/winstonLogger'; const container = new IoCContainer(); @@ -51,15 +50,13 @@ container.bind(iocSymbols.extensions).to(OrganizeImportsOnSaveExt // Logging container - .bind>(iocSymbols.loggerFactory) - .toFactory((context: interfaces.Context) => { - return (prefix?: string) => { - const extContext = context.container.get(iocSymbols.extensionContext); - const config = context.container.get(iocSymbols.configuration)(); - - return new VscodeLogger(extContext, config, prefix); - }; - }); + .bind(iocSymbols.logger) + .toDynamicValue((context: interfaces.Context) => { + const extContext = context.container.get(iocSymbols.extensionContext); + const config = context.container.get(iocSymbols.configuration)(); + return winstonLogger(config.verbosity, extContext); + }) + .inSingletonScope(); // Code Action Extension (action creators) container.bind(iocSymbols.codeActionCreators).to(MissingImportCreator); diff --git a/src/extension/IoCSymbols.ts b/src/extension/IoCSymbols.ts index 5fc8ef5..aac9c1f 100644 --- a/src/extension/IoCSymbols.ts +++ b/src/extension/IoCSymbols.ts @@ -5,7 +5,7 @@ export const iocSymbols = { configuration: Symbol('config'), extensionContext: Symbol('context'), extensions: Symbol('extensions'), - loggerFactory: Symbol('loggerFactory'), + logger: Symbol('logger'), generatorFactory: Symbol('generatorFactory'), codeActionCreators: Symbol('codeActionCreators'), declarationIndexMapper: Symbol('declarationIndexMapper'), diff --git a/src/extension/TypeScriptHero.ts b/src/extension/TypeScriptHero.ts index 1403109..53b7e78 100644 --- a/src/extension/TypeScriptHero.ts +++ b/src/extension/TypeScriptHero.ts @@ -1,40 +1,39 @@ import { inject, injectable, multiInject } from 'inversify'; import { Disposable } from 'vscode'; -import { Logger, LoggerFactory } from '../common/utilities'; import { BaseExtension } from './extensions/BaseExtension'; import { iocSymbols } from './IoCSymbols'; +import { Logger } from './utilities/winstonLogger'; /** * TypeScript Hero vscode extension. * Central entrypoint. - * + * * @export * @class TypeScriptHero * @implements {Disposable} */ @injectable() export class TypeScriptHero implements Disposable { - private logger: Logger; - constructor( - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @multiInject(iocSymbols.extensions) private extensions: BaseExtension[], ) { - this.logger = loggerFactory('TypescriptHero'); - this.logger.info('Activation event called. TypeScriptHero instantiated.'); + this.logger.debug('[%s] activation event, initializing', TypeScriptHero.name); this.extensions.forEach(o => o.initialize()); + this.logger.info('[%s] initialized', TypeScriptHero.name); } /** * Disposes TypeScript Hero. - * + * * @memberof TypeScriptHero */ public dispose(): void { - this.logger.info('Deactivation event called. Disposing TypeScriptHero.'); + this.logger.debug('[%s] deactivation event, disposing', TypeScriptHero.name); for (const ext of this.extensions) { ext.dispose(); } + this.logger.info('[%s] disposed', TypeScriptHero.name); } } diff --git a/src/extension/code-actions/CodeAction.ts b/src/extension/code-actions/CodeAction.ts index e86de6f..bf55f73 100644 --- a/src/extension/code-actions/CodeAction.ts +++ b/src/extension/code-actions/CodeAction.ts @@ -7,12 +7,15 @@ import { } from 'typescript-parser'; import { TextDocument } from 'vscode'; +import { Container } from '../IoC'; +import { iocSymbols } from '../IoCSymbols'; import { ClassManager } from '../managers/ClassManager'; import { ImportManager } from '../managers/ImportManager'; +import { Logger } from '../utilities/winstonLogger'; /** * Interface for all codeactions that are generated by the typescript code action provider. - * + * * @export * @interface CodeAction */ @@ -20,9 +23,9 @@ export interface CodeAction { /** * Executes the code action. Depending on the action, there are several actions performed. - * + * * @returns {Promise} - * + * * @memberof CodeAction */ execute(): Promise; @@ -30,22 +33,31 @@ export interface CodeAction { /** * Code action that adds a missing import the the actual document. - * + * * @export * @class AddImportCodeAction * @implements {CodeAction} */ export class AddImportCodeAction implements CodeAction { + private static get logger(): Logger { + return Container.get(iocSymbols.logger); + } + constructor(private document: TextDocument, private importToAdd: DeclarationInfo) { } /** * Executes the code action. Depending on the action, there are several actions performed. - * + * * @returns {Promise} - * + * * @memberof AddImportCodeAction */ public async execute(): Promise { + AddImportCodeAction.logger.debug( + '[%s] add import for declaration "%s"', + AddImportCodeAction.name, + this.importToAdd.declaration.name, + ); const controller = await ImportManager.create(this.document); return controller.addDeclarationImport(this.importToAdd).commit(); } @@ -53,22 +65,31 @@ export class AddImportCodeAction implements CodeAction { /** * Code action that adds all missing imports to the actual document, based on the non-local usages. - * + * * @export * @class AddMissingImportsCodeAction * @implements {CodeAction} */ export class AddMissingImportsCodeAction implements CodeAction { + private static get logger(): Logger { + return Container.get(iocSymbols.logger); + } + constructor(private document: TextDocument, private resolveIndex: DeclarationIndex) { } /** * Executes the code action. Depending on the action, there are several actions performed. - * + * * @returns {Promise} - * + * * @memberof AddMissingImportsCodeAction */ public async execute(): Promise { + AddMissingImportsCodeAction.logger.debug( + '[%s] add all missing imports for document "%s"', + AddMissingImportsCodeAction.name, + this.document.fileName, + ); const controller = await ImportManager.create(this.document); return controller.addMissingImports(this.resolveIndex).commit(); } @@ -77,7 +98,7 @@ export class AddMissingImportsCodeAction implements CodeAction { /** * Code action that does literally nothing. Is used to "communicate" with the user. E.g. if * an import cannot be resolved, the lightbulb will show "cannot resolve ". - * + * * @export * @class NoopCodeAction * @implements {CodeAction} @@ -85,9 +106,9 @@ export class AddMissingImportsCodeAction implements CodeAction { export class NoopCodeAction implements CodeAction { /** * Executes the code action. Depending on the action, there are several actions performed. - * + * * @returns {Promise} - * + * * @memberof NoopCodeAction */ public execute(): Promise { @@ -97,12 +118,16 @@ export class NoopCodeAction implements CodeAction { /** * Code action that does implement missing properties and methods from interfaces or abstract classes. - * + * * @export * @class ImplementPolymorphElements * @implements {CodeAction} */ export class ImplementPolymorphElements implements CodeAction { + private static get logger(): Logger { + return Container.get(iocSymbols.logger); + } + constructor( private document: TextDocument, private managedClass: string, @@ -112,12 +137,18 @@ export class ImplementPolymorphElements implements CodeAction { /** * Executes the code action. Depending on the action, there are several actions performed. - * + * * @returns {Promise} - * + * * @memberof ImplementPolymorphElements */ public async execute(): Promise { + ImplementPolymorphElements.logger.debug( + '[%s] implement polymorph elements for class "%s"', + ImplementPolymorphElements.name, + this.managedClass, + { file: this.document.fileName }, + ); const controller = await ClassManager.create(this.document, this.managedClass); let typeKeys; diff --git a/src/extension/code-actions/MissingImplementationInClassCreator.ts b/src/extension/code-actions/MissingImplementationInClassCreator.ts index 251f058..e3485fc 100644 --- a/src/extension/code-actions/MissingImplementationInClassCreator.ts +++ b/src/extension/code-actions/MissingImplementationInClassCreator.ts @@ -5,6 +5,7 @@ import { Command, Diagnostic, TextDocument, workspace } from 'vscode'; import { getAbsolutLibraryName } from '../../common/helpers'; import { iocSymbols } from '../IoCSymbols'; import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; +import { Logger } from '../utilities/winstonLogger'; import { ImplementPolymorphElements, NoopCodeAction } from './CodeAction'; import { CodeActionCreator } from './CodeActionCreator'; @@ -20,6 +21,7 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { constructor( @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, + @inject(iocSymbols.logger) private logger: Logger, ) { super(); } @@ -55,6 +57,10 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { const rootFolder = workspace.getWorkspaceFolder(document.uri); if (!match || !index || !rootFolder) { + this.logger.debug( + '[%s] cannot handle the diagnostic', + MissingImplementationInClassCreator.name, + ); return commands; } @@ -80,10 +86,19 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { if (commands.some((o: Command) => o.title.indexOf(specifier) >= 0)) { // Do leave the method when a command with the found class is already added. + this.logger.debug( + '[%s] command with the found class is already added', + MissingImplementationInClassCreator.name, + ); return commands; } if (!declaration) { + this.logger.debug( + '[%s] class definition not found in the index', + MissingImplementationInClassCreator.name, + { specifier }, + ); commands.push(this.createCommand( `Cannot find "${specifier}" in the index or the actual file.`, new NoopCodeAction(), @@ -103,6 +118,12 @@ export class MissingImplementationInClassCreator extends CodeActionCreator { new ImplementPolymorphElements(document, match[1], declaration, typeParams), )); + this.logger.debug( + '[%s] adding commands to handle missing implementation', + MissingImplementationInClassCreator.name, + { specifier, types }, + ); + return commands; } } diff --git a/src/extension/code-actions/MissingImportCreator.ts b/src/extension/code-actions/MissingImportCreator.ts index bcdc634..dc0bded 100644 --- a/src/extension/code-actions/MissingImportCreator.ts +++ b/src/extension/code-actions/MissingImportCreator.ts @@ -1,3 +1,4 @@ +import { Logger } from '../utilities/winstonLogger'; import { inject, injectable } from 'inversify'; import { Command, Diagnostic, TextDocument } from 'vscode'; @@ -17,6 +18,7 @@ import { CodeActionCreator } from './CodeActionCreator'; export class MissingImportCreator extends CodeActionCreator { constructor( @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, + @inject(iocSymbols.logger) private logger: Logger, ) { super(); } @@ -48,6 +50,10 @@ export class MissingImportCreator extends CodeActionCreator { const index = this.indices.getIndexForFile(document.uri); if (!match || !index) { + this.logger.debug( + '[%s] cannot handle the diagnostic', + MissingImportCreator.name, + ); return commands; } @@ -58,6 +64,11 @@ export class MissingImportCreator extends CodeActionCreator { `Import "${info.declaration.name}" from "${info.from}".`, new AddImportCodeAction(document, info), )); + this.logger.debug( + '[%s] add command to import missing specifier', + MissingImportCreator.name, + { symbol: info.declaration.name, library: info.from }, + ); } if ( !commands.some(o => @@ -69,12 +80,21 @@ export class MissingImportCreator extends CodeActionCreator { 'Add all missing imports if possible.', new AddMissingImportsCodeAction(document, index), )); + this.logger.debug( + '[%s] add "import all missing imports" command', + MissingImportCreator.name, + ); } } else { commands.push(this.createCommand( `Cannot find "${match[1]}" in the index.`, new NoopCodeAction(), )); + this.logger.debug( + '[%s] class not found in index', + MissingImportCreator.name, + { specifier: match[1] }, + ); } return commands; diff --git a/src/extension/config/VscodeExtensionConfig.ts b/src/extension/config/VscodeExtensionConfig.ts index 35ac546..94fc225 100644 --- a/src/extension/config/VscodeExtensionConfig.ts +++ b/src/extension/config/VscodeExtensionConfig.ts @@ -36,11 +36,15 @@ export class VscodeExtensionConfig implements ExtensionConfig { * The actual log level. * * @readonly - * @type {string} + * @type {'error' | 'warn' | 'info' | 'debug'} * @memberof VscodeExtensionConfig */ - public get verbosity(): string { - return this.workspaceSection.get('verbosity', 'Warning'); + public get verbosity(): 'error' | 'warn' | 'info' | 'debug' { + const verbosity = this.workspaceSection.get<'error' | 'warn' | 'info' | 'debug'>('verbosity', 'warn'); + if (['error', 'warn', 'info', 'debug'].indexOf(verbosity) < 0) { + return 'warn'; + } + return verbosity; } /** diff --git a/src/extension/extensions/CodeActionExtension.ts b/src/extension/extensions/CodeActionExtension.ts index 2634847..328e0c5 100644 --- a/src/extension/extensions/CodeActionExtension.ts +++ b/src/extension/extensions/CodeActionExtension.ts @@ -12,11 +12,11 @@ import { window, } from 'vscode'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { CodeAction } from '../code-actions/CodeAction'; import { CodeActionCreator } from '../code-actions/CodeActionCreator'; import { iocSymbols } from '../IoCSymbols'; import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; +import { Logger } from '../utilities/winstonLogger'; import { BaseExtension } from './BaseExtension'; /** @@ -30,16 +30,13 @@ import { BaseExtension } from './BaseExtension'; */ @injectable() export class CodeActionExtension extends BaseExtension implements CodeActionProvider { - private logger: Logger; - constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @multiInject(iocSymbols.codeActionCreators) private actionCreators: CodeActionCreator[], @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(context); - this.logger = loggerFactory('CodeActionExtension'); } /** @@ -55,7 +52,7 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv this.context.subscriptions.push(languages.registerCodeActionsProvider('typescript', this)); this.context.subscriptions.push(languages.registerCodeActionsProvider('typescriptreact', this)); - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', CodeActionCreator.name); } /** @@ -64,7 +61,7 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv * @memberof ImportResolveExtension */ public dispose(): void { - this.logger.info('Disposed'); + this.logger.info('[%s] disposed', CodeActionCreator.name); } /** @@ -89,6 +86,13 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv return []; } + this.logger.debug( + '[%s] provide code actions for file', + CodeActionCreator.name, + { file: document.fileName }, + ); + const profiler = this.logger.startTimer(); + let commands: Command[] = []; for (const diagnostic of context.diagnostics) { for (const creator of this.actionCreators) { @@ -98,6 +102,8 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv } } + profiler.done({ message: `[${CodeActionCreator.name}] calculated diagnostics` }); + return commands; } @@ -112,10 +118,12 @@ export class CodeActionExtension extends BaseExtension implements CodeActionProv */ private async executeCodeAction(codeAction: CodeAction | undefined): Promise { if (!codeAction) { + this.logger.warn('[%s] executeCodeAction used without param', CodeActionCreator.name); window.showWarningMessage('This command is for internal use only. It cannot be used from Cmd+P'); return; } if (!await codeAction.execute()) { + this.logger.warn('[%s] code action could not complete', CodeActionCreator.name, { codeAction }); window.showWarningMessage('The provided code action could not complete. Please see the logs.'); } } diff --git a/src/extension/extensions/CodeCompletionExtension.ts b/src/extension/extensions/CodeCompletionExtension.ts index 4a01f6d..4e94f3e 100644 --- a/src/extension/extensions/CodeCompletionExtension.ts +++ b/src/extension/extensions/CodeCompletionExtension.ts @@ -14,11 +14,11 @@ import { import { ConfigFactory } from '../../common/factories'; import { getDeclarationsFilteredByImports } from '../../common/helpers'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers/ImportManager'; import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; import { getItemKind } from '../utilities/utilityFunctions'; +import { Logger } from '../utilities/winstonLogger'; import { BaseExtension } from './BaseExtension'; /** @@ -31,17 +31,14 @@ import { BaseExtension } from './BaseExtension'; */ @injectable() export class CodeCompletionExtension extends BaseExtension implements CompletionItemProvider { - private logger: Logger; - constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, @inject(iocSymbols.configuration) private config: ConfigFactory, ) { super(context); - this.logger = loggerFactory('CodeCompletionExtension'); } /** @@ -62,7 +59,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion ), ); - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', CodeCompletionExtension.name); } /** @@ -71,7 +68,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion * @memberof CodeCompletionExtension */ public dispose(): void { - this.logger.info('Disposed'); + this.logger.info('[%s] disposed', CodeCompletionExtension.name); } /** @@ -98,6 +95,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion !config.resolver.resolverModeLanguages.some(lng => lng === document.languageId) || !rootFolder ) { + this.logger.debug('[%s] resolver not ready or no workspace folder selected', CodeCompletionExtension.name); return null; } @@ -118,10 +116,20 @@ export class CodeCompletionExtension extends BaseExtension implements Completion lineText.match(/^\s*(\/\/|\/\*\*|\*\/|\*)/g) || lineText.startsWith('import ') || lineText.substring(0, position.character).match(new RegExp(`(\w*[.])+${searchWord}`, 'g'))) { + this.logger.debug( + '[%s] did not match criteria to provide intellisense', + CodeCompletionExtension.name, + { searchWord, lineText, indexReady: index.indexReady }, + ); return Promise.resolve(null); } - this.logger.info('Search completion for word.', { searchWord }); + this.logger.debug( + '[%s] provide code completion for "%s"', + CodeCompletionExtension.name, + searchWord, + ); + const profiler = this.logger.startTimer(); const parsed = await this.parser.parseSource(document.getText()); const declarations = getDeclarationsFilteredByImports( @@ -150,6 +158,8 @@ export class CodeCompletionExtension extends BaseExtension implements Completion } items.push(item); } + + profiler.done({ message: `[${CodeCompletionExtension.name}] calculated code completions` }); return items; } @@ -164,6 +174,11 @@ export class CodeCompletionExtension extends BaseExtension implements Completion * @memberof CodeCompletionExtension */ private async executeIntellisenseItem(document: TextDocument, declaration: DeclarationInfo): Promise { + this.logger.debug( + '[%s] execute code completion action', + CodeCompletionExtension.name, + { specifier: declaration.declaration.name, library: declaration.from }, + ); const manager = await ImportManager.create(document); manager.addDeclarationImport(declaration); await manager.commit(); diff --git a/src/extension/extensions/DocumentSymbolStructureExtension.ts b/src/extension/extensions/DocumentSymbolStructureExtension.ts index 8332f6d..8eba072 100644 --- a/src/extension/extensions/DocumentSymbolStructureExtension.ts +++ b/src/extension/extensions/DocumentSymbolStructureExtension.ts @@ -14,7 +14,6 @@ import { } from 'vscode'; import { ConfigFactory } from '../../common/factories'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { BaseStructureTreeItem } from '../provider-items/document-structure/BaseStructureTreeItem'; import { DeclarationStructureTreeItem } from '../provider-items/document-structure/DeclarationStructureTreeItem'; @@ -22,6 +21,7 @@ import { DisabledStructureTreeItem } from '../provider-items/document-structure/ import { ImportsStructureTreeItem } from '../provider-items/document-structure/ImportsStructureTreeItem'; import { NotParseableStructureTreeItem } from '../provider-items/document-structure/NotParseableStructureTreeItem'; import { ResourceStructureTreeItem } from '../provider-items/document-structure/ResourceStructureTreeItem'; +import { Logger } from '../utilities/winstonLogger'; import { BaseExtension } from './BaseExtension'; /** @@ -36,17 +36,15 @@ import { BaseExtension } from './BaseExtension'; export class DocumentSymbolStructureExtension extends BaseExtension implements TreeDataProvider { public readonly onDidChangeTreeData: Event; private _onDidChangeTreeData: EventEmitter; - private logger: Logger; private documentCache: File | undefined; constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @inject(iocSymbols.configuration) private config: ConfigFactory, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, ) { super(context); - this.logger = loggerFactory('DocumentSymbolStructureExtension'); this._onDidChangeTreeData = new EventEmitter(); this.onDidChangeTreeData = this._onDidChangeTreeData.event; } @@ -68,7 +66,7 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T this.context.subscriptions.push(window.onDidChangeActiveTextEditor(() => this.activeWindowChanged())); this.context.subscriptions.push(workspace.onDidSaveTextDocument(() => this.activeWindowChanged())); - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', DocumentSymbolStructureExtension.name); } /** @@ -77,7 +75,7 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T * @memberof DocumentSymbolStructureExtension */ public dispose(): void { - this.logger.info('Disposed'); + this.logger.info('[%s] disposed', DocumentSymbolStructureExtension.name); } public getTreeItem(element: BaseStructureTreeItem): BaseStructureTreeItem { @@ -105,7 +103,11 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T try { this.documentCache = await this.parser.parseSource(window.activeTextEditor.document.getText()); } catch (e) { - this.logger.error('Document could not be parsed.', e); + this.logger.error( + '[%s] document could not be parsed, error: %s', + DocumentSymbolStructureExtension.name, + e, + ); return []; } } @@ -133,6 +135,7 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T */ private async jumpToNode(node: Node | undefined): Promise { if (!node) { + this.logger.warn('[%s] jumpToNode used without param', DocumentSymbolStructureExtension.name); window.showWarningMessage('This command is for internal use only. It cannot be used from Cmd+P'); return; } @@ -155,7 +158,7 @@ export class DocumentSymbolStructureExtension extends BaseExtension implements T * @memberof DocumentSymbolStructureExtension */ private activeWindowChanged(): void { - this.logger.info('Active window changed or document was saved. Reparse file.'); + this.logger.debug('[%s] activeWindowChanged, reparsing', DocumentSymbolStructureExtension.name); this.documentCache = undefined; this._onDidChangeTreeData.fire(); } diff --git a/src/extension/extensions/ImportResolveExtension.ts b/src/extension/extensions/ImportResolveExtension.ts index f906dd6..530094e 100644 --- a/src/extension/extensions/ImportResolveExtension.ts +++ b/src/extension/extensions/ImportResolveExtension.ts @@ -4,10 +4,10 @@ import { commands, ExtensionContext, StatusBarAlignment, StatusBarItem, window, import { getDeclarationsFilteredByImports } from '../../common/helpers'; import { ResolveQuickPickItem } from '../../common/quick-pick-items'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers'; import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper'; +import { Logger } from '../utilities/winstonLogger'; import { BaseExtension } from './BaseExtension'; type DeclarationsForImportOptions = { cursorSymbol: string, documentSource: string, documentPath: string }; @@ -27,17 +27,15 @@ const resolverErr = 'TSH Resolver $(flame)'; */ @injectable() export class ImportResolveExtension extends BaseExtension { - private logger: Logger; private statusBarItem: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left, 4); constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, @inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper, ) { super(context); - this.logger = loggerFactory('ImportResolveExtension'); } /** @@ -64,7 +62,7 @@ export class ImportResolveExtension extends BaseExtension { this.commandRegistrations(); - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', ImportResolveExtension.name); } /** @@ -73,7 +71,7 @@ export class ImportResolveExtension extends BaseExtension { * @memberof ImportResolveExtension */ public dispose(): void { - this.logger.info('Disposed'); + this.logger.info('[%s] disposed', ImportResolveExtension.name); } /** @@ -100,11 +98,20 @@ export class ImportResolveExtension extends BaseExtension { { placeHolder: 'Add import to document:' }, ); if (selectedItem) { - this.logger.info('Add import to document', { resolveItem: selectedItem }); + this.logger.info( + '[%s] add import to document', + ImportResolveExtension.name, + { specifier: selectedItem.declarationInfo.declaration.name, library: selectedItem.declarationInfo.from }, + ); this.addImportToDocument(selectedItem.declarationInfo); } } catch (e) { - this.logger.error('An error happend during import picking', e); + this.logger.error( + '[%s] import could not be added to document, error: %s', + ImportResolveExtension.name, + e, + { file: window.activeTextEditor.document.fileName }, + ); window.showErrorMessage('The import cannot be completed, there was an error during the process.'); } } @@ -129,6 +136,7 @@ export class ImportResolveExtension extends BaseExtension { } try { const selectedSymbol = this.getSymbolUnderCursor(); + this.logger.debug('[%s] add import for symbol under cursor', ImportResolveExtension.name, { selectedSymbol }); if (!!!selectedSymbol) { return; } @@ -139,23 +147,47 @@ export class ImportResolveExtension extends BaseExtension { }); if (resolveItems.length < 1) { + this.logger.info( + '[%s] the symbol was not found or is already imported', + ImportResolveExtension.name, + { selectedSymbol }, + ); window.showInformationMessage( `The symbol '${selectedSymbol}' was not found in the index or is already imported.`, ); } else if (resolveItems.length === 1 && resolveItems[0].declaration.name === selectedSymbol) { - this.logger.info('Add import to document', { resolveItem: resolveItems[0] }); + this.logger.info( + '[%s] add import to document', + ImportResolveExtension.name, + { + specifier: resolveItems[0].declaration.name, + library: resolveItems[0].from, + }, + ); this.addImportToDocument(resolveItems[0]); } else { const selectedItem = await window.showQuickPick( resolveItems.map(o => new ResolveQuickPickItem(o)), { placeHolder: 'Multiple declarations found:' }, ); if (selectedItem) { - this.logger.info('Add import to document', { resolveItem: selectedItem }); + this.logger.info( + '[%s] add import to document', + ImportResolveExtension.name, + { + specifier: selectedItem.declarationInfo.declaration.name, + library: selectedItem.declarationInfo.from, + }, + ); this.addImportToDocument(selectedItem.declarationInfo); } } } catch (e) { - this.logger.error('An error happend during import picking', e); + this.logger.error( + '[%s] import could not be added to document, error: %s', + ImportResolveExtension.name, + e, + { file: window.activeTextEditor.document.fileName }, + ); window.showErrorMessage('The import cannot be completed, there was an error during the process.'); } } @@ -179,6 +211,11 @@ export class ImportResolveExtension extends BaseExtension { return; } try { + this.logger.debug( + '[%s] add all missing imports to the document', + ImportResolveExtension.name, + { file: window.activeTextEditor.document.fileName }, + ); const missing = await this.getMissingDeclarationsForFile({ documentSource: window.activeTextEditor.document.getText(), documentPath: window.activeTextEditor.document.fileName, @@ -190,7 +227,12 @@ export class ImportResolveExtension extends BaseExtension { await ctrl.commit(); } } catch (e) { - this.logger.error('An error happend during import fixing', e); + this.logger.error( + '[%s] missing imports could not be added, error: %s', + ImportResolveExtension.name, + e, + { file: window.activeTextEditor.document.fileName }, + ); window.showErrorMessage('The operation cannot be completed, there was an error during the process.'); } } @@ -208,10 +250,20 @@ export class ImportResolveExtension extends BaseExtension { return false; } try { + this.logger.debug( + '[%s] organize the imports in the document', + ImportResolveExtension.name, + { file: window.activeTextEditor.document.fileName }, + ); const ctrl = await ImportManager.create(window.activeTextEditor.document); return await ctrl.organizeImports().commit(); } catch (e) { - this.logger.error('An error happend during "organize imports".', { error: e }); + this.logger.error( + '[%s] imports could not be organized, error: %s', + ImportResolveExtension.name, + e, + { file: window.activeTextEditor.document.fileName }, + ); return false; } } @@ -260,6 +312,10 @@ export class ImportResolveExtension extends BaseExtension { * @memberof ImportResolveExtension */ private showCacheWarning(): void { + this.logger.warn( + '[%s] index was not ready or not index for this file found', + ImportResolveExtension.name, + ); window.showWarningMessage('Please wait a few seconds longer until the symbol cache has been build.'); } @@ -276,7 +332,6 @@ export class ImportResolveExtension extends BaseExtension { private async getDeclarationsForImport( { cursorSymbol, documentSource, documentPath }: DeclarationsForImportOptions, ): Promise { - this.logger.info(`Calculate possible imports for document with filter "${cursorSymbol}"`); if (!window.activeTextEditor) { return []; } @@ -288,6 +343,12 @@ export class ImportResolveExtension extends BaseExtension { return []; } + this.logger.debug( + '[%s] calculate possible imports for document', + ImportResolveExtension.name, + { cursorSymbol, file: documentPath }, + ); + const parsedSource = await this.parser.parseSource(documentSource); const activeDocumentDeclarations = parsedSource.declarations.map(o => o.name); const declarations = getDeclarationsFilteredByImports( @@ -327,6 +388,12 @@ export class ImportResolveExtension extends BaseExtension { return []; } + this.logger.debug( + '[%s] calculate missing imports for document', + ImportResolveExtension.name, + { file: documentPath }, + ); + const parsedDocument = await this.parser.parseSource(documentSource); const missingDeclarations: (DeclarationInfo)[] = []; const declarations = getDeclarationsFilteredByImports( diff --git a/src/extension/extensions/OrganizeImportsOnSaveExtension.ts b/src/extension/extensions/OrganizeImportsOnSaveExtension.ts index c13526f..e7791ef 100644 --- a/src/extension/extensions/OrganizeImportsOnSaveExtension.ts +++ b/src/extension/extensions/OrganizeImportsOnSaveExtension.ts @@ -2,9 +2,9 @@ import { inject, injectable } from 'inversify'; import { ExtensionContext, workspace } from 'vscode'; import { ConfigFactory } from '../../common/factories'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../IoCSymbols'; import { ImportManager } from '../managers'; +import { Logger } from '../utilities/winstonLogger'; import { BaseExtension } from './BaseExtension'; /** @@ -22,15 +22,13 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { 'javascript', 'javascriptreact', ]; - private logger: Logger; constructor( @inject(iocSymbols.extensionContext) context: ExtensionContext, - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @inject(iocSymbols.configuration) private config: ConfigFactory, ) { super(context); - this.logger = loggerFactory('OrganizeImportsOnSaveExtension'); } /** @@ -42,15 +40,26 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { this.context.subscriptions.push(workspace.onWillSaveTextDocument((event) => { const config = this.config(event.document.uri); if (!config.resolver.organizeOnSave) { - this.logger.info('Organize on save is deactivated through config.'); + this.logger.debug( + '[%s] organizeOnSave is deactivated through config', + OrganizeImportsOnSaveExtension.name, + ); return; } if (this.compatibleLanguages.indexOf(event.document.languageId) < 0) { - this.logger.info(`Organize imports for languageId "${event.document.languageId}" not possible.`); + this.logger.debug( + '[%s] organizeOnSave not possible for given language', + OrganizeImportsOnSaveExtension.name, + { language: event.document.languageId }, + ); return; } - this.logger.info(`Organize on save for document "${event.document.fileName}".`); + this.logger.info( + '[%s] organizeOnSave for file', + OrganizeImportsOnSaveExtension.name, + { file: event.document.fileName }, + ); event.waitUntil( ImportManager .create(event.document) @@ -58,7 +67,7 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { ); })); - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', OrganizeImportsOnSaveExtension.name); } /** @@ -67,6 +76,6 @@ export class OrganizeImportsOnSaveExtension extends BaseExtension { * @memberof OrganizeImportsOnSaveExtension */ public dispose(): void { - this.logger.info('Disposed'); + this.logger.info('[%s] disposed', OrganizeImportsOnSaveExtension.name); } } diff --git a/src/extension/managers/ClassManager.ts b/src/extension/managers/ClassManager.ts index 7b77859..c69fd3f 100644 --- a/src/extension/managers/ClassManager.ts +++ b/src/extension/managers/ClassManager.ts @@ -22,6 +22,7 @@ import { TypescriptCodeGeneratorFactory } from '../../common/factories'; import { Container } from '../IoC'; import { iocSymbols } from '../IoCSymbols'; import { Changeable } from '../proxy-objects/Changeable'; +import { Logger } from '../utilities/winstonLogger'; import { ObjectManager } from './ObjectManager'; type VisibleObject = { visibility?: DeclarationVisibility }; @@ -67,6 +68,10 @@ export class ClassManager implements ObjectManager { return Container.get(iocSymbols.generatorFactory)(); } + private static get logger(): Logger { + return Container.get(iocSymbols.logger); + } + private ctor: Changeable; private properties: Changeable[] = []; private methods: Changeable[] = []; @@ -76,6 +81,11 @@ export class ClassManager implements ObjectManager { public readonly parsedDocument: File, private readonly managedClass: ClassDeclaration, ) { + ClassManager.logger.debug( + '[%s] create class manager', + ClassManager.name, + { file: document.fileName, class: managedClass.name }, + ); this.ctor = new Changeable(managedClass.ctor); this.properties = managedClass.properties.map(o => new Changeable(o)); this.methods = managedClass.methods.map(o => new Changeable(o)); @@ -147,6 +157,11 @@ export class ClassManager implements ObjectManager { } this.properties.push(new Changeable(declaration, true)); + ClassManager.logger.debug( + '[%s] add property to class', + ClassManager.name, + { property: declaration.name, class: this.managedClass.name }, + ); return this; } @@ -171,6 +186,11 @@ export class ClassManager implements ObjectManager { if (property.isNew) { this.properties.splice(this.properties.indexOf(property), 1); } + ClassManager.logger.debug( + '[%s] remove property from class', + ClassManager.name, + { property: name, class: this.managedClass.name }, + ); return this; } @@ -219,6 +239,11 @@ export class ClassManager implements ObjectManager { } this.methods.push(new Changeable(declaration, true)); + ClassManager.logger.debug( + '[%s] add method to class', + ClassManager.name, + { property: declaration.name, class: this.managedClass.name }, + ); return this; } @@ -243,6 +268,11 @@ export class ClassManager implements ObjectManager { if (method.isNew) { this.methods.splice(this.methods.indexOf(method), 1); } + ClassManager.logger.debug( + '[%s] remove method from class', + ClassManager.name, + { property: name, class: this.managedClass.name }, + ); return this; } @@ -265,6 +295,11 @@ export class ClassManager implements ObjectManager { const workspaceEdit = new WorkspaceEdit(); workspaceEdit.set(this.document.uri, edits); + ClassManager.logger.debug( + '[%s] commit the class', + ClassManager.name, + { class: this.managedClass.name }, + ); return workspace.applyEdit(workspaceEdit); } diff --git a/src/extension/managers/ImportManager.ts b/src/extension/managers/ImportManager.ts index 9562ba7..9ce1622 100644 --- a/src/extension/managers/ImportManager.ts +++ b/src/extension/managers/ImportManager.ts @@ -30,6 +30,7 @@ import { ImportGroup } from '../import-grouping'; import { Container } from '../IoC'; import { iocSymbols } from '../IoCSymbols'; import { importSort, specifierSort } from '../utilities/utilityFunctions'; +import { Logger } from '../utilities/winstonLogger'; import { ObjectManager } from './ObjectManager'; function sameSpecifiers(specs1: SymbolSpecifier[], specs2: SymbolSpecifier[]): boolean { @@ -64,6 +65,10 @@ export class ImportManager implements ObjectManager { return Container.get<() => TypescriptCodeGenerator>(iocSymbols.generatorFactory)(); } + private static get logger(): Logger { + return Container.get(iocSymbols.logger); + } + private importGroups: ImportGroup[]; private imports: Import[] = []; private userImportDecisions: { [usage: string]: DeclarationInfo[] }[] = []; @@ -93,6 +98,11 @@ export class ImportManager implements ObjectManager { public readonly document: TextDocument, private _parsedDocument: File, ) { + ImportManager.logger.debug( + '[%s] create import manager', + ImportManager.name, + { file: document.fileName }, + ); this.reset(); } @@ -134,6 +144,11 @@ export class ImportManager implements ObjectManager { * @memberof ImportManager */ public addDeclarationImport(declarationInfo: DeclarationInfo): this { + ImportManager.logger.debug( + '[%s] add declaration as import', + ImportManager.name, + { file: this.document.fileName, specifier: declarationInfo.declaration.name, library: declarationInfo.from }, + ); // If there is something already imported, it must be a NamedImport const alreadyImported: NamedImport = this.imports.find( o => declarationInfo.from === getAbsolutLibraryName( @@ -185,6 +200,11 @@ export class ImportManager implements ObjectManager { * @memberof ImportManager */ public addMissingImports(index: DeclarationIndex): this { + ImportManager.logger.debug( + '[%s] add all missing imports', + ImportManager.name, + { file: this.document.fileName }, + ); const declarations = getDeclarationsFilteredByImports( index.declarationInfos, this.document.fileName, @@ -216,6 +236,11 @@ export class ImportManager implements ObjectManager { * @memberof ImportManager */ public organizeImports(): this { + ImportManager.logger.debug( + '[%s] organize the imports', + ImportManager.name, + { file: this.document.fileName }, + ); this.organize = true; let keep: Import[] = []; @@ -280,6 +305,12 @@ export class ImportManager implements ObjectManager { workspaceEdit.set(this.document.uri, edits); + ImportManager.logger.debug( + '[%s] commit the file', + ImportManager.name, + { file: this.document.fileName }, + ); + const result = await workspace.applyEdit(workspaceEdit); if (result) { diff --git a/src/extension/utilities/DeclarationIndexMapper.ts b/src/extension/utilities/DeclarationIndexMapper.ts index 122f784..15d51e7 100644 --- a/src/extension/utilities/DeclarationIndexMapper.ts +++ b/src/extension/utilities/DeclarationIndexMapper.ts @@ -14,8 +14,8 @@ import { import { ConfigFactory } from '../../common/factories'; import { findFiles } from '../../common/helpers'; -import { Logger, LoggerFactory } from '../../common/utilities'; import { iocSymbols } from '../../extension/IoCSymbols'; +import { Logger } from './winstonLogger'; interface WorkspaceIndex { index: DeclarationIndex; @@ -36,11 +36,10 @@ export class DeclarationIndexMapper { private _onFinishIndexing: EventEmitter; private _onIndexingError: EventEmitter<{ index: WorkspaceIndex, error: Error }>; - private logger: Logger; private indizes: { [uri: string]: WorkspaceIndex } = {}; constructor( - @inject(iocSymbols.loggerFactory) loggerFactory: LoggerFactory, + @inject(iocSymbols.logger) private logger: Logger, @inject(iocSymbols.extensionContext) private context: ExtensionContext, @inject(iocSymbols.typescriptParser) private parser: TypescriptParser, @inject(iocSymbols.configuration) private config: ConfigFactory, @@ -56,24 +55,28 @@ export class DeclarationIndexMapper { this.context.subscriptions.push(this._onFinishIndexing); this.context.subscriptions.push(this._onIndexingError); this.context.subscriptions.push(this._onStartIndexing); - - this.logger = loggerFactory('DeclarationIndexMapper'); } @postConstruct() public initialize(): void { this.context.subscriptions.push(workspace.onDidChangeWorkspaceFolders(e => this.workspaceChanged(e))); this.logger.info( - `Fired up index mapper, got ${(workspace.workspaceFolders || []).length} workspaces.`, - workspace.workspaceFolders, + '[%s] initializing index mapper for %d workspaces', + DeclarationIndexMapper.name, + (workspace.workspaceFolders || []).length, ); + for (const folder of (workspace.workspaceFolders || []).filter(workspace => workspace.uri.scheme === 'file')) { this.initializeIndex(folder); } - this.logger.info('Initialized'); + this.logger.info('[%s] initialized', DeclarationIndexMapper.name); } public rebuildAll(): void { + this.logger.info( + '[%s] rebuilding all indices', + DeclarationIndexMapper.name, + ); for (const index of Object.values(this.indizes)) { index.watcher.dispose(); index.index.reset(); @@ -87,6 +90,11 @@ export class DeclarationIndexMapper { public getIndexForFile(fileUri: Uri): DeclarationIndex | undefined { const workspaceFolder = workspace.getWorkspaceFolder(fileUri); if (!workspaceFolder || !this.indizes[workspaceFolder.uri.fsPath]) { + this.logger.debug( + '[%s] did not find index for file', + DeclarationIndexMapper.name, + { file: fileUri.fsPath }, + ); return; } @@ -94,16 +102,33 @@ export class DeclarationIndexMapper { } private workspaceChanged(event: WorkspaceFoldersChangeEvent): void { - this.logger.info('Workspaces changed.', event); + this.logger.info( + '[%s] workspaces changed, adjusting indices', + DeclarationIndexMapper.name, + ); for (const add of event.added) { + this.logger.debug( + '[%s] add workspace for "%s"', + DeclarationIndexMapper.name, + add.uri.fsPath, + ); if (this.indizes[add.uri.fsPath]) { - this.logger.warning(`The workspace with the path ${add.uri.fsPath} already exists. Skipping.`); + this.logger.warn( + '[%s] workspace index "%s" already exists, skipping', + DeclarationIndexMapper.name, + add.uri.fsPath, + ); continue; } this.initializeIndex(add); } for (const remove of event.removed) { + this.logger.debug( + '[%s] remove workspace for "%s"', + DeclarationIndexMapper.name, + remove.uri.fsPath, + ); this.indizes[remove.uri.fsPath].index.reset(); this.indizes[remove.uri.fsPath].watcher.dispose(); delete this.indizes[remove.uri.fsPath]; @@ -111,6 +136,12 @@ export class DeclarationIndexMapper { } private async initializeIndex(folder: WorkspaceFolder): Promise { + const profiler = this.logger.startTimer(); + this.logger.debug( + '[%s] initialize index for "%s"', + DeclarationIndexMapper.name, + folder.uri.fsPath, + ); const index = new DeclarationIndex(this.parser, folder.uri.fsPath); const config = this.config(folder.uri); const files = await findFiles(config, folder); @@ -147,9 +178,16 @@ export class DeclarationIndexMapper { timeout = setTimeout( async () => { if (events) { - this.logger.info(`Refreshing index for workspace ${folder.name}.`); + const profiler = this.logger.startTimer(); + this.logger.debug( + '[%s] rebuilding index for index "%s"', + DeclarationIndexMapper.name, + folder.uri.fsPath, + ); await index.reindexForChanges(events); - this.logger.info(`Finished indexing for workspace ${folder.name}.`); + profiler.done({ + message: `[${DeclarationIndexMapper.name}] rebuilt index for workspace "${folder.name}"`, + }); events = undefined; } }, @@ -164,10 +202,17 @@ export class DeclarationIndexMapper { try { await index.buildIndex(files); this.indizes[folder.uri.fsPath] = workspaceIndex; - this.logger.info(`Finished building index for workspace "${folder.name}".`); this._onFinishIndexing.fire(workspaceIndex); + profiler.done({ + message: `[${DeclarationIndexMapper.name}] built index for workspace "${folder.name}"`, + }); } catch (error) { - this.logger.error(`Error during build of index for workspace "${folder.name}"`, error); + this.logger.error( + '[%s] could not build index for workspace "%s", error: %s', + DeclarationIndexMapper.name, + folder.uri.fsPath, + error, + ); this._onIndexingError.fire({ error, index: workspaceIndex }); } } diff --git a/src/extension/utilities/VscodeLogger.ts b/src/extension/utilities/VscodeLogger.ts deleted file mode 100644 index 907d96a..0000000 --- a/src/extension/utilities/VscodeLogger.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { ExtensionConfig } from '../../common/config'; -import { Logger, LogLevel } from '../../common/utilities'; -import { inspect } from 'util'; -import { ExtensionContext, OutputChannel, window } from 'vscode'; - -/** - * Central logger instance of the extension. - * - * @export - * @class VscodeLogger - */ -export class VscodeLogger implements Logger { - private static channel: OutputChannel; - - constructor(context: ExtensionContext, private config: ExtensionConfig, public readonly prefix?: string) { - if (!VscodeLogger.channel) { - VscodeLogger.channel = window.createOutputChannel('TypeScript Hero Extension'); - context.subscriptions.push(VscodeLogger.channel); - } - } - - /** - * Logs an error message. Provided data is logged out after the message. - * - * @param {string} message - * @param {*} [data] - * - * @memberof VscodeLogger - */ - public error(message: string, data?: any): void { - this.log( - LogLevel.Errors, - 'Error', - message, - data, - ); - } - - /** - * Logs a warning message. Provided data is logged out after the message. - * - * @param {string} message - * @param {*} [data] - * - * @memberof VscodeLogger - */ - public warning(message: string, data?: any): void { - this.log( - LogLevel.Warnings, - 'Warn ', - message, - data, - ); - } - - /** - * Logs an info message. Provided data is logged out after the message. - * - * @param {string} message - * @param {*} [data] - * - * @memberof VscodeLogger - */ - public info(message: string, data?: any): void { - this.log( - LogLevel.All, - 'Info ', - message, - data, - ); - } - - /** - * Internal method to actually do the logging. Checks if the output should be done and logs - * the data into the output channel and the console (if debugging). - * - * @private - * @param {LogLevel} level - * @param {string} severity - * @param {string} message - * @param {*} [data] - * - * @memberof VscodeLogger - */ - private log(level: LogLevel, severity: string, message: string, data?: any): void { - if (this.getLogLevel() >= level) { - const msg = `[${severity} - ${this.getDate()}] ${this.prefix ? this.prefix + ' - ' : ''}${message}`; - // tslint:disable - if (data) { - console.log(msg, data); - } else { - console.log(msg); - } - // tslint:enable - VscodeLogger.channel.appendLine(msg); - if (data) { - VscodeLogger.channel.appendLine(`\tData:\t${inspect(data, {})}`); - } - } - } - - /** - * Returns a propper formatted date for logging. - * - * @private - * @returns {string} - * - * @memberof Logger - */ - private getDate(): string { - const date = new Date(); - let hours = date.getHours().toString(); - let minutes = date.getMinutes().toString(); - let seconds = date.getSeconds().toString(); - - if (hours.length < 2) { - hours = `0${hours}`; - } - if (minutes.length < 2) { - minutes = `0${minutes}`; - } - if (seconds.length < 2) { - seconds = `0${seconds}`; - } - return `${hours}:${minutes}:${seconds}`; - } - - /** - * Maps the configuration string to a propper enum value of LogLevel. - * - * @private - * @returns {LogLevel} - * - * @memberof VscodeLogger - */ - private getLogLevel(): LogLevel { - switch (this.config.verbosity) { - case 'Nothing': - return LogLevel.Nothing; - case 'Errors': - return LogLevel.Errors; - case 'All': - return LogLevel.All; - default: - return LogLevel.Warnings; - } - } -} diff --git a/src/extension/utilities/winstonLogger.ts b/src/extension/utilities/winstonLogger.ts new file mode 100644 index 0000000..223bb99 --- /dev/null +++ b/src/extension/utilities/winstonLogger.ts @@ -0,0 +1,150 @@ +import { join } from 'path'; +import { ExtensionContext, OutputChannel, window, workspace } from 'vscode'; + +const { createLogger, exceptions, format, transports } = require('winston'); +const transport = require('winston-transport'); +const { LEVEL, MESSAGE } = require('triple-beam'); + +const { combine, timestamp, printf } = format; +const Transport = transport as { new(...args: any[]): any; }; + +const levels = { + error: 0, + warn: 1, + info: 2, + debug: 3, +}; + +class OutputWindowTransport extends Transport { + constructor(opts: any, private channel: OutputChannel) { + super(opts); + } + + public log(info: any, callback: any): void { + setImmediate(() => { + this.emit('logged', info); + }); + this.channel.appendLine(info[MESSAGE]); + callback(); + } +} + +class ConsoleLogTransport extends Transport { + constructor(opts?: any) { + super(opts); + } + + public log(info: any, callback: any): void { + setImmediate(() => { + this.emit('logged', info); + }); + const level = info[LEVEL]; + + switch (level) { + case 'error': + console.error(info[MESSAGE]); + break; + case 'warn': + console.warn(info[MESSAGE]); + break; + default: + console.log(info[MESSAGE]); + break; + } + callback(); + } +} + +class HandleUncatchedException extends Transport { + constructor(private path: string) { + super(); + } + + public async log(info: any, callback: any): Promise { + setImmediate(() => { + this.emit('logged', info); + }); + + const result = await window.showErrorMessage( + 'There was an uncought exception, do you want to see the logfile?', + { modal: true }, + 'Yes, show me.', + ); + + if (result) { + const doc = await workspace.openTextDocument(join(this.path, 'typescript-hero.log')); + await window.showTextDocument(doc); + } + + callback(); + } +} + +export interface Logger { + error: (message: string, ...data: any[]) => void; + warn: (message: string, ...data: any[]) => void; + info: (message: string, ...data: any[]) => void; + debug: (message: string, ...data: any[]) => void; + profile: (name: string) => void; + startTimer(): { done: (info: { message: string }) => void; }; +} + +const loggerTransports = [ + new ConsoleLogTransport({ + level: !!process.env.CI ? 'error' : 'debug', + }), +]; + +export default function winstonLogger(verbosity: keyof typeof levels, context: ExtensionContext): Logger { + const level = !!process.env.CI ? 'error' : verbosity; + + if (!process.env.CI && !process.env.EXT_DEBUG) { + const channel = window.createOutputChannel('TypeScript Hero'); + context.subscriptions.push(channel); + + const fileHandler = new transports.File({ + exitOnError: false, + filename: 'typescript-hero.log', + dirname: context.extensionPath, + maxsize: 1024 * 1024, + maxFiles: 1, + tailable: true, + }); + const outputHandler = new OutputWindowTransport({ exitOnError: false }, channel); + + loggerTransports.push(fileHandler); + loggerTransports.push(outputHandler); + + exceptions.handle(fileHandler); + exceptions.handle(outputHandler); + exceptions.handle(new HandleUncatchedException(context.extensionPath)); + } + + const logger = createLogger({ + level, + levels, + format: combine( + format.splat(), + timestamp(), + printf((info) => { + const message = `${info.timestamp} - ${info.level}: ${info.message}`; + const data = { + ...info, + level: undefined, + message: undefined, + splat: undefined, + timestamp: undefined, + }; + if (Object.keys(data).filter(key => !!data[key]).length > 0) { + return `${message} ${JSON.stringify(data)}`; + } + return message; + }), + ), + transports: loggerTransports, + }); + + logger.exitOnError = false; + + return logger; +} diff --git a/test/_workspace/.vscode/settings.json b/test/_workspace/.vscode/settings.json index c5f10cc..1705c40 100755 --- a/test/_workspace/.vscode/settings.json +++ b/test/_workspace/.vscode/settings.json @@ -9,7 +9,7 @@ "dist", "resourceParser" ], - "typescriptHero.verbosity": "Warnings", + "typescriptHero.verbosity": "All", "tslint.enable": false, "typescriptHero.codeOutline.enabled": true, "typescriptHero.resolver.organizeOnSave": false, diff --git a/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts b/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts index d5f6b59..25df25f 100644 --- a/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/CodeActionExtension.test.ts @@ -6,7 +6,6 @@ import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import { ExtensionContext, Position, Range, TextDocument, window, workspace } from 'vscode'; import { ConfigFactory } from '../../../../src/common/factories'; -import { LoggerFactory } from '../../../../src/common/utilities'; import { AddImportCodeAction, CodeAction, ImplementPolymorphElements } from '../../../../src/extension/code-actions'; import { MissingImplementationInClassCreator, @@ -16,6 +15,7 @@ import { CodeActionExtension } from '../../../../src/extension/extensions/CodeAc import { Container } from '../../../../src/extension/IoC'; import { iocSymbols } from '../../../../src/extension/IoCSymbols'; import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; +import { Logger } from '../../../../src/extension/utilities/winstonLogger'; chai.should(); chai.use(sinonChai); @@ -36,7 +36,7 @@ describe('CodeActionExtension', () => { before(async () => { const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const parser = Container.get(iocSymbols.typescriptParser); const config = Container.get(iocSymbols.configuration); const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); @@ -66,8 +66,8 @@ describe('CodeActionExtension', () => { fakeMapper.getIndexForFile = sinon.spy(() => index); const creators = [ - new MissingImportCreator(fakeMapper), - new MissingImplementationInClassCreator(parser, fakeMapper), + new MissingImportCreator(fakeMapper, logger), + new MissingImplementationInClassCreator(parser, fakeMapper, logger), ]; extension = new CodeActionExtension(ctx, logger, creators, fakeMapper); @@ -194,7 +194,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'Foobar' implement inherited from class 'CodeFixImplementAbstract'.`, + `non-abstract class 'Foobar' implement inherited from class 'CodeFixImplementAbstract'.`, }, ], }, @@ -261,7 +261,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: `non-abstract class 'Foobar' ` + - `implement inherited from class 'GenericAbstractClass'.`, + `implement inherited from class 'GenericAbstractClass'.`, }, ], }, @@ -317,7 +317,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: `non-abstract class 'AbstractImplement' ` + - `implement inherited from class 'CodeFixImplementAbstract'.`, + `implement inherited from class 'CodeFixImplementAbstract'.`, }, ], }, @@ -365,8 +365,8 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'InternalAbstractImplement' ` + - `implement inherited from class 'InternalAbstract'.`, + `non-abstract class 'InternalAbstractImplement' ` + + `implement inherited from class 'InternalAbstract'.`, }, ], }, @@ -388,7 +388,7 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: `class 'ImplementGenericInterface' incorrectly ` + - `implements 'GenericInterface'.`, + `implements 'GenericInterface'.`, }, ], }, @@ -412,8 +412,8 @@ describe('CodeActionExtension', () => { diagnostics: [ { message: - `non-abstract class 'ImplementGenericAbstract' ` + - `implement inherited from class 'GenericAbstractClass'.`, + `non-abstract class 'ImplementGenericAbstract' ` + + `implement inherited from class 'GenericAbstractClass'.`, }, ], }, diff --git a/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts b/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts index a42c6ed..0580541 100644 --- a/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/CodeCompletionExtension.test.ts @@ -5,12 +5,12 @@ import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; import { ConfigFactory } from '../../../../src/common/factories'; -import { LoggerFactory } from '../../../../src/common/utilities'; +import { VscodeExtensionConfig } from '../../../../src/extension/config/VscodeExtensionConfig'; import { CodeCompletionExtension } from '../../../../src/extension/extensions/CodeCompletionExtension'; import { Container } from '../../../../src/extension/IoC'; import { iocSymbols } from '../../../../src/extension/IoCSymbols'; import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; -import { VscodeExtensionConfig } from '../../../../src/extension/config/VscodeExtensionConfig'; +import { Logger } from '../../../../src/extension/utilities/winstonLogger'; const should = chai.should(); @@ -30,7 +30,7 @@ describe('CodeCompletionExtension', () => { await vscode.window.showTextDocument(document); const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const parser = Container.get(iocSymbols.typescriptParser); const config = Container.get(iocSymbols.configuration); const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); diff --git a/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts b/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts index 9930532..11d5588 100644 --- a/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/DocumentSymbolStructureExtension.test.ts @@ -3,7 +3,6 @@ import { TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; import { ConfigFactory } from '../../../../src/common/factories'; -import { LoggerFactory } from '../../../../src/common/utilities'; import { DocumentSymbolStructureExtension } from '../../../../src/extension/extensions/DocumentSymbolStructureExtension'; import { Container } from '../../../../src/extension/IoC'; import { iocSymbols } from '../../../../src/extension/IoCSymbols'; @@ -20,6 +19,7 @@ import { import { NotParseableStructureTreeItem, } from '../../../../src/extension/provider-items/document-structure/NotParseableStructureTreeItem'; +import { Logger } from '../../../../src/extension/utilities/winstonLogger'; describe('DocumentSymbolStructureExtension', () => { @@ -33,7 +33,7 @@ describe('DocumentSymbolStructureExtension', () => { before(async () => { const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const parser = Container.get(iocSymbols.typescriptParser); const config = Container.get(iocSymbols.configuration); diff --git a/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts b/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts index 906ec3e..7692492 100644 --- a/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts +++ b/test/single-workspace-tests/extension/extensions/ImportResolveExtension.test.ts @@ -5,11 +5,11 @@ import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; import * as vscode from 'vscode'; import { ConfigFactory } from '../../../../src/common/factories'; -import { LoggerFactory } from '../../../../src/common/utilities'; import { ImportResolveExtension } from '../../../../src/extension/extensions/ImportResolveExtension'; import { Container } from '../../../../src/extension/IoC'; import { iocSymbols } from '../../../../src/extension/IoCSymbols'; import { DeclarationIndexMapper } from '../../../../src/extension/utilities/DeclarationIndexMapper'; +import { Logger } from '../../../../src/extension/utilities/winstonLogger'; chai.should(); @@ -29,7 +29,7 @@ describe('TypeScript Mode: ImportResolveExtension', () => { await vscode.window.showTextDocument(document); const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); @@ -241,7 +241,7 @@ describe('JavaScript Mode: ImportResolveExtension', () => { await vscode.window.showTextDocument(document); const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); @@ -340,7 +340,7 @@ describe('Mixed Mode: ImportResolveExtension', () => { await vscode.window.showTextDocument(document); const ctx = Container.get(iocSymbols.extensionContext); - const logger = Container.get(iocSymbols.loggerFactory); + const logger = Container.get(iocSymbols.logger); const config = Container.get(iocSymbols.configuration); const parser = Container.get(iocSymbols.typescriptParser); const fakeMapper = new DeclarationIndexMapper(logger, ctx, parser, config); diff --git a/yarn.lock b/yarn.lock index 8dff7d6..f51c361 100644 --- a/yarn.lock +++ b/yarn.lock @@ -213,7 +213,7 @@ assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" -async@^1.4.0: +async@^1.0.0, async@^1.4.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -444,20 +444,48 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +color-convert@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" + color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: color-name "^1.1.1" -color-name@^1.1.1: +color-name@^1.0.0, color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@0.8.x: + version "0.8.0" + resolved "https://registry.yarnpkg.com/color/-/color-0.8.0.tgz#890c07c3fd4e649537638911cf691e5458b6fca5" + dependencies: + color-convert "^0.5.0" + color-string "^0.3.0" + +colornames@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/colornames/-/colornames-0.0.2.tgz#d811fd6c84f59029499a8ac4436202935b92be31" + colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" +colorspace@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.0.1.tgz#c99c796ed31128b9876a52e1ee5ee03a4a719749" + dependencies: + color "0.8.x" + text-hex "0.0.x" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -634,6 +662,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +date-fns@^1.28.5: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + dateformat@^1.0.11, dateformat@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" @@ -698,6 +730,14 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" +diagnostics@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.0.tgz#e1090900b49523e8527be20f081275205f2ae36a" + dependencies: + colorspace "1.0.x" + enabled "1.0.x" + kuler "0.0.x" + diff@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" @@ -754,12 +794,22 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" +enabled@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" + dependencies: + env-variable "0.0.x" + end-of-stream@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" dependencies: once "^1.4.0" +env-variable@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.3.tgz#b86c1641be5610267d506f18071ea76d707097cb" + error-ex@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" @@ -1619,7 +1669,7 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isstream@~0.1.2: +isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1699,6 +1749,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" +kuler@0.0.x: + version "0.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-0.0.0.tgz#b66bb46b934e550f59d818848e0abba4f7f5553c" + dependencies: + colornames "0.0.2" + latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -1884,6 +1940,13 @@ log-driver@1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" +logform@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-1.2.1.tgz#e707ef7b3f3a9f16c248ae57f1d015074fc66bf5" + dependencies: + colors "^1.1.2" + date-fns "^1.28.5" + lolex@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" @@ -2195,6 +2258,10 @@ once@^1.4.0: dependencies: wrappy "1" +one-time@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" + optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -2828,6 +2895,10 @@ ssri@^4.1.2: dependencies: safe-buffer "^5.1.0" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + stat-mode@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" @@ -2962,6 +3033,10 @@ text-extensions@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.6.0.tgz#771561b26022783a45f5b6c2e78ad6e7de9fe322" +text-hex@0.0.x: + version "0.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-0.0.0.tgz#578fbc85a6a92636e42dd17b41d0218cce9eb2b3" + through2-filter@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" @@ -3032,6 +3107,10 @@ trim-off-newlines@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" +triple-beam@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.1.0.tgz#2ac387c8c4bd04bd26c61df891a6079f8592fe10" + tslib@^1.0.0, tslib@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" @@ -3368,6 +3447,23 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" +winston-transport@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-3.0.1.tgz#8008b15eef5660c4fb3fa094d58ccbd08528c58d" + +winston@^3.0.0-rc1: + version "3.0.0-rc1" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.0.0-rc1.tgz#982bc0ad4ef5c53000ca68036d78a3deaa28cac5" + dependencies: + async "^1.0.0" + diagnostics "^1.0.1" + isstream "0.1.x" + logform "^1.2.1" + one-time "0.0.4" + stack-trace "0.0.x" + triple-beam "^1.0.1" + winston-transport "^3.0.1" + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" From 499b27f8e2911075f76626644e6e4f572f98ca04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Sat, 28 Oct 2017 11:25:51 +0200 Subject: [PATCH 3/9] fix: use correct level for file handler --- src/extension/utilities/winstonLogger.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extension/utilities/winstonLogger.ts b/src/extension/utilities/winstonLogger.ts index 223bb99..d9e7fe5 100644 --- a/src/extension/utilities/winstonLogger.ts +++ b/src/extension/utilities/winstonLogger.ts @@ -103,6 +103,7 @@ export default function winstonLogger(verbosity: keyof typeof levels, context: E context.subscriptions.push(channel); const fileHandler = new transports.File({ + level: ['info', 'debug'].indexOf(level) >= 0 ? level : 'info', exitOnError: false, filename: 'typescript-hero.log', dirname: context.extensionPath, From 1f2c83069528d10adf50f446c0a9c2b897b3cbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Sat, 28 Oct 2017 11:29:35 +0200 Subject: [PATCH 4/9] docs: add settings to correct place --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b751c3b..f8cb776 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,16 @@ All settings are preceeded by `typescriptHero`. These settings do not have a prefix. +| Setting | Description | +| ---------- | --------------------------------------------------------------------------------------- | +| verbosity | The log level that the extension writes its messages to the output channel and the file | + +### Code completion + +The following settings do have the prefix `codeCompletion`. So an example setting could be +`typescriptHero.codeCompletion.completionSortOrder`. + | Setting | Description | -| ------------------- | ----------------------------------------------------------------------------- | -| verbosity | The log level that the extension writes its messages to the output channel | | completionSortOrder | The order of import completions in suggestion list, `bottom` pushes them down | ### Import resolver From c889c4f79bf21282da1364ca9d8201329446f762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Mon, 30 Oct 2017 08:27:36 +0100 Subject: [PATCH 5/9] upgrade deps --- package.json | 20 +- yarn.lock | 741 +++++++++++++++++++++++++++------------------------ 2 files changed, 404 insertions(+), 357 deletions(-) diff --git a/package.json b/package.json index 07dbc19..1138b99 100644 --- a/package.json +++ b/package.json @@ -92,31 +92,31 @@ }, "devDependencies": { "@types/chai": "^4.0.4", - "@types/mocha": "^2.2.43", - "@types/node": "^8.0.31", + "@types/mocha": "^2.2.44", + "@types/node": "^8.0.47", "@types/reflect-metadata": "0.0.5", - "@types/sinon": "^2.3.5", + "@types/sinon": "^2.3.7", "@types/sinon-chai": "^2.7.29", "chai": "^4.1.2", "del-cli": "^1.1.0", "filewalker": "^0.1.3", "mocha-testdata": "^1.2.0", - "semantic-release": "^8.0.3", + "semantic-release": "^8.2.0", "semantic-release-visualstudio-marketplace-version": "^1.0.0", - "sinon": "^4.0.0", + "sinon": "^4.0.2", "sinon-chai": "^2.14.0", - "tslint": "^5.7.0", + "tslint": "^5.8.0", "tslint-config-airbnb": "^5.3.0", - "tsutils": "^2.11.1", - "vscode": "^1.1.5" + "tsutils": "^2.12.1", + "vscode": "^1.1.6" }, "dependencies": { "inversify": "^4.3.0", "inversify-inject-decorators": "^3.0.1", "reflect-metadata": "^0.1.10", - "tslib": "^1.7.1", + "tslib": "^1.8.0", "typescript": "~2.5.3", - "typescript-parser": "^2.0.0", + "typescript-parser": "^2.2.1", "winston": "^3.0.0-rc1" }, "activationEvents": [ diff --git a/yarn.lock b/yarn.lock index f51c361..aff4dd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,48 +3,51 @@ "@semantic-release/commit-analyzer@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-3.0.1.tgz#ef308494dc5716abc0bbdeed88fe47ed096b1d3a" + version "3.0.7" + resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-3.0.7.tgz#dc955444a6d3d2ae9b8e21f90c2c80c4e9142b2f" dependencies: - "@semantic-release/error" "^1.0.0" + "@semantic-release/error" "^2.0.0" conventional-changelog-angular "^1.4.0" conventional-commits-parser "^2.0.0" - import-cwd "^2.1.0" + import-from "^2.1.0" lodash "^4.17.4" pify "^3.0.0" "@semantic-release/condition-travis@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@semantic-release/condition-travis/-/condition-travis-6.0.0.tgz#e4a592bd054720a258cec1477500dc5e494ecb83" + version "6.1.1" + resolved "https://registry.yarnpkg.com/@semantic-release/condition-travis/-/condition-travis-6.1.1.tgz#9a86e843b7d533ecfa5835d7a1534682ee6085a7" dependencies: - "@semantic-release/error" "^1.0.0" + "@semantic-release/error" "^2.0.0" + github "^12.0.0" + parse-github-repo-url "^1.4.1" semver "^5.0.3" - travis-deploy-once "^2.0.1" + travis-deploy-once "^3.0.0" "@semantic-release/error@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-1.0.0.tgz#bb8f8eeedd5c7f8c46f96b37ef39e1b8c376c1cc" "@semantic-release/error@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-2.0.0.tgz#f156ecd509f5288c48bc7425a8abe22f975d1f8b" + version "2.1.0" + resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-2.1.0.tgz#44771f676f5b148da309111285a97901aa95a6e0" "@semantic-release/last-release-npm@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@semantic-release/last-release-npm/-/last-release-npm-2.0.1.tgz#9d9e40b7dfa2778eb08dc995263da3e366542416" + version "2.0.2" + resolved "https://registry.yarnpkg.com/@semantic-release/last-release-npm/-/last-release-npm-2.0.2.tgz#c91b1ccb48b0d7095b107be6ebc2c0c08bd88c27" dependencies: "@semantic-release/error" "^2.0.0" npm-registry-client "^8.4.0" npmlog "^4.0.0" "@semantic-release/release-notes-generator@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-4.0.1.tgz#eb5cb0cbebdd08c61250e4e35ff8423ff2f5f86e" + version "4.0.5" + resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-4.0.5.tgz#46cc2f16bdb60fe9674bbcd616bfe0f8bb35347c" dependencies: - "@semantic-release/error" "^1.0.0" + "@semantic-release/error" "^2.0.0" conventional-changelog-angular "^1.4.0" conventional-changelog-core "^1.9.0" - import-cwd "^2.1.0" + get-stream "^3.0.0" + import-from "^2.1.0" lodash "^4.17.4" pify "^3.0.0" @@ -52,13 +55,13 @@ version "4.0.4" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.0.4.tgz#fe86315d9a66827feeb16f73bc954688ec950e18" -"@types/mocha@^2.2.43": - version "2.2.43" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27" +"@types/mocha@^2.2.44": + version "2.2.44" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.44.tgz#1d4a798e53f35212fd5ad4d04050620171cd5b5e" -"@types/node@^8.0.31": - version "8.0.31" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.31.tgz#d9af61093cf4bfc9f066ca34de0175012cfb0ce9" +"@types/node@^8.0.47": + version "8.0.47" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.47.tgz#968e596f91acd59069054558a00708c445ca30c2" "@types/reflect-metadata@0.0.5": version "0.0.5" @@ -71,13 +74,9 @@ "@types/chai" "*" "@types/sinon" "*" -"@types/sinon@*": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-2.3.4.tgz#2b3aa82dfc791eeff1d970b657a77eafff2899ff" - -"@types/sinon@^2.3.5": - version "2.3.5" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-2.3.5.tgz#68f1e0ac15f2eb6cc682b7af87cd517acc77b589" +"@types/sinon@*", "@types/sinon@^2.3.7": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-2.3.7.tgz#e92c2fed3297eae078d78d1da032b26788b4af86" JSONStream@^1.0.4: version "1.3.1" @@ -87,22 +86,23 @@ JSONStream@^1.0.4: through ">=2.2.7 <3" abbrev@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +agent-base@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.1.tgz#92d8a4fc2524a3b09b3666a33b6c97960f23d6a4" dependencies: - extend "~3.0.0" - semver "~5.0.1" + es6-promisify "^5.0.0" -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" +ajv@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" dependencies: co "^4.6.0" - json-stable-stringify "^1.0.1" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -141,8 +141,8 @@ ansi-styles@^3.1.0: color-convert "^1.9.0" aproba@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" are-we-there-yet@~1.1.2: version "1.1.4" @@ -231,17 +231,14 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws4@^1.2.1: +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -axios@^0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" - dependencies: - follow-redirects "^1.2.3" - is-buffer "^1.1.5" - babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -282,9 +279,21 @@ boom@2.x.x: dependencies: hoek "2.x.x" -boxen@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.2.1.tgz#0f11e7fe344edb9397977fc13ede7f64d956481d" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +boxen@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.2.2.tgz#3f1d4032c30ffea9d4b02c322eaf2ea741dcbce5" dependencies: ansi-align "^2.0.0" camelcase "^4.0.0" @@ -317,7 +326,7 @@ buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" -builtin-modules@^1.0.0: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -384,9 +393,9 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" +chalk@^2.0.1, chalk@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -428,6 +437,10 @@ clone@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" +clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + cloneable-readable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117" @@ -492,13 +505,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - -commander@^2.9.0: +commander@2.11.0, commander@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" @@ -544,15 +551,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" conventional-changelog-angular@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.5.0.tgz#50b2d45008448455fdf67e06ea01972fbd08182a" + version "1.5.1" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.5.1.tgz#974e73aa1c39c392e4364f2952bd9a62904e9ea3" dependencies: compare-func "^1.3.1" q "^1.4.1" conventional-changelog-core@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-1.9.1.tgz#ddf767c405850dfc8df31726c80fa1a6a10bdc7b" + version "1.9.2" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-1.9.2.tgz#a09b6b959161671ff45b93cc9efb0444e7c845c0" dependencies: conventional-changelog-writer "^2.0.1" conventional-commits-parser "^2.0.0" @@ -560,7 +567,7 @@ conventional-changelog-core@^1.9.0: get-pkg-repo "^1.0.0" git-raw-commits "^1.2.0" git-remote-origin-url "^2.0.0" - git-semver-tags "^1.2.1" + git-semver-tags "^1.2.2" lodash "^4.0.0" normalize-package-data "^2.3.5" q "^1.4.1" @@ -640,6 +647,12 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -674,12 +687,18 @@ dateformat@^1.0.11, dateformat@^1.0.12: meow "^3.3.0" dateformat@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17" + version "2.2.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" -debug@2, debug@2.6.8, debug@^2.2.0, debug@^2.4.5: - version "2.6.8" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" +debug@^2.4.1, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" @@ -738,14 +757,14 @@ diagnostics@^1.0.1: enabled "1.0.x" kuler "0.0.x" -diff@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" - -diff@^3.1.0, diff@^3.2.0: +diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" +diff@^3.1.0, diff@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + doctrine@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" @@ -816,6 +835,16 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es6-promise@^4.0.3: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -886,7 +915,7 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" -extend@3, extend@^3.0.0, extend@~3.0.0: +extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -907,6 +936,14 @@ fancy-log@^1.1.0: chalk "^1.1.1" time-stamp "^1.0.0" +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + fd-slicer@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" @@ -950,18 +987,11 @@ first-chunk-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" -follow-redirects@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" - dependencies: - debug "^2.2.0" - stream-consume "^0.1.0" - -follow-redirects@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.4.tgz#355e8f4d16876b43f577b0d5ce2668b9723214ea" +follow-redirects@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.5.tgz#ffd3e14cbdd5eaa72f61b6368c1f68516c2a26cc" dependencies: - debug "^2.4.5" + debug "^2.6.9" for-in@^1.0.1: version "1.0.2" @@ -997,6 +1027,14 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + formatio@1.2.0, formatio@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb" @@ -1114,9 +1152,9 @@ git-remote-origin-url@^2.0.0: gitconfiglocal "^1.0.0" pify "^2.3.0" -git-semver-tags@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-1.2.1.tgz#6ccd2a52e735b736748dc762444fcd9588e27490" +git-semver-tags@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-1.2.2.tgz#a2139be1bf6e337e125f3eb8bb8fc6f5d4d6445f" dependencies: meow "^3.3.0" semver "^5.0.1" @@ -1127,13 +1165,13 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -github@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/github/-/github-11.0.0.tgz#edb32df5efb33cad004ebf0bdd2a4b30bb63a854" +github@^12.0.0: + version "12.0.1" + resolved "https://registry.yarnpkg.com/github/-/github-12.0.1.tgz#4f7467434d8d01152782e669e925b3115aa0b219" dependencies: - follow-redirects "0.0.7" - https-proxy-agent "^1.0.0" - mime "^1.2.11" + follow-redirects "1.2.5" + https-proxy-agent "^2.1.0" + mime "^2.0.3" netrc "^0.1.4" github@~0.1.10: @@ -1173,14 +1211,14 @@ glob-stream@^5.3.2: to-absolute-glob "^0.1.1" unique-stream "^2.0.2" -glob@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" +glob@7.1.2, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.2" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" @@ -1194,16 +1232,11 @@ glob@^5.0.3, glob@~5.0.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +global-dirs@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.0.tgz#10d34039e0df04272e262cf24224f7209434df4f" dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" + ini "^1.3.4" globby@^6.1.0: version "6.1.0" @@ -1241,13 +1274,9 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" gulp-chmod@^2.0.0: version "2.0.0" @@ -1257,7 +1286,7 @@ gulp-chmod@^2.0.0: stat-mode "^0.2.0" through2 "^2.0.0" -gulp-filter@^5.0.0: +gulp-filter@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.0.1.tgz#5d87f662e317e5839ef7650e620e6c9008ff92d0" dependencies: @@ -1265,14 +1294,14 @@ gulp-filter@^5.0.0: multimatch "^2.0.0" streamfilter "^1.0.5" -gulp-gunzip@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-0.0.3.tgz#7b6e07b0f58fd3d42515c48ead5a63df0572f62f" +gulp-gunzip@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz#15b741145e83a9c6f50886241b57cc5871f151a9" dependencies: through2 "~0.6.5" vinyl "~0.4.6" -gulp-remote-src@^0.4.2: +gulp-remote-src@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.3.tgz#5728cfd643433dd4845ddef0969f0f971a2ab4a1" dependencies: @@ -1334,14 +1363,14 @@ gulp-util@^3.0.6, gulp-util@~3.0.8: through2 "^2.0.0" vinyl "^0.5.0" -gulp-vinyl-zip@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-1.4.0.tgz#56382f2ccb57231bb0478c78737ccd572973bee1" +gulp-vinyl-zip@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.0.tgz#24e40685dc05b7149995245099e0590263be8dad" dependencies: event-stream "^3.3.1" - queue "^3.0.10" - through2 "^0.6.3" - vinyl "^0.4.6" + queue "^4.2.1" + through2 "^2.0.3" + vinyl "^2.0.2" vinyl-fs "^2.0.0" yauzl "^2.2.1" yazl "^2.2.1" @@ -1353,8 +1382,8 @@ gulplog@^1.0.0: glogg "^1.0.0" handlebars@^4.0.2: - version "4.0.10" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -1362,9 +1391,9 @@ handlebars@^4.0.2: optionalDependencies: uglify-js "^2.6" -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" har-validator@~2.0.6: version "2.0.6" @@ -1375,12 +1404,12 @@ har-validator@~2.0.6: is-my-json-valid "^2.12.4" pinkie-promise "^2.0.0" -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" + ajv "^5.1.0" + har-schema "^2.0.0" has-ansi@^2.0.0: version "2.0.0" @@ -1388,10 +1417,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" @@ -1415,6 +1440,15 @@ hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" @@ -1423,6 +1457,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + hosted-git-info@^2.1.4, hosted-git-info@^2.4.2: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -1435,19 +1473,20 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" dependencies: - agent-base "2" - debug "2" - extend "3" + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" -import-cwd@^2.1.0: +https-proxy-agent@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.0.tgz#1391bee7fd66aeabc0df2a1fa90f58954f43e443" dependencies: - import-from "^2.1.0" + agent-base "^4.1.0" + debug "^2.4.1" import-from@^2.1.0: version "2.1.0" @@ -1497,8 +1536,8 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" @@ -1556,6 +1595,13 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + is-my-json-valid@^2.12.4: version "2.16.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" @@ -1688,11 +1734,15 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: @@ -1702,10 +1752,6 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json3@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -1733,9 +1779,9 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -just-extend@^1.1.22: - version "1.1.22" - resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-1.1.22.tgz#3330af756cab6a542700c64b2e4e4aa062d52fff" +just-extend@^1.1.26: + version "1.1.26" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-1.1.26.tgz#dba4ad2786d319f1d10afab106e004b5a0851ac2" kind-of@^3.0.2: version "3.2.2" @@ -1796,10 +1842,6 @@ lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" -lodash._basecreate@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" - lodash._basetostring@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" @@ -1852,14 +1894,6 @@ lodash.assign@^3.0.0: lodash._createassigner "^3.0.0" lodash.keys "^3.0.0" -lodash.create@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" - dependencies: - lodash._baseassign "^3.0.0" - lodash._basecreate "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" @@ -1951,9 +1985,9 @@ lolex@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" -lolex@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.1.2.tgz#2694b953c9ea4d013e5b8bfba891c991025b2629" +lolex@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.1.3.tgz#53f893bbe88c80378156240e127126b905c83087" longest@^1.0.1: version "1.0.1" @@ -1978,10 +2012,10 @@ lru-cache@^4.0.1: yallist "^2.1.2" make-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + version "1.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" dependencies: - pify "^2.3.0" + pify "^3.0.0" map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" @@ -2034,23 +2068,23 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.7: +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" -mime@^1.2.11: - version "1.4.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343" +mime@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.0.3.tgz#4353337854747c48ea498330dc034f9f4bbbcc0b" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" -minimist@0.0.8, minimist@~0.0.1: +minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -2058,6 +2092,10 @@ minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -2068,22 +2106,20 @@ mocha-testdata@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mocha-testdata/-/mocha-testdata-1.2.0.tgz#6cc0d41820e9bb66903334524e5ae420de77ecea" -mocha@^3.2.0: - version "3.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" +mocha@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.0.1.tgz#0aee5a95cf69a4618820f5e51fa31717117daf1b" dependencies: browser-stdout "1.3.0" - commander "2.9.0" - debug "2.6.8" - diff "3.2.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" escape-string-regexp "1.0.5" - glob "7.1.1" - growl "1.9.2" + glob "7.1.2" + growl "1.10.3" he "1.1.1" - json3 "3.3.2" - lodash.create "3.1.1" mkdirp "0.5.1" - supports-color "3.1.2" + supports-color "4.4.0" modify-values@^1.0.0: version "1.0.0" @@ -2108,10 +2144,6 @@ multipipe@^0.1.2: dependencies: duplexer2 "0.0.2" -native-promise-only@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" - nerf-dart@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" @@ -2120,12 +2152,12 @@ netrc@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/netrc/-/netrc-0.1.4.tgz#6be94fcaca8d77ade0a9670dc460914c94472444" -nise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nise/-/nise-1.1.0.tgz#37e41b9bf0041ccb83d1bf03e79440bbc0db10ad" +nise@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.2.0.tgz#079d6cadbbcb12ba30e38f1c999f36ad4d6baa53" dependencies: formatio "^1.2.0" - just-extend "^1.1.22" + just-extend "^1.1.26" lolex "^1.6.0" path-to-regexp "^1.7.0" text-encoding "^0.6.4" @@ -2227,7 +2259,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -2246,15 +2278,15 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3, once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" +once@^1.3.0, once@^1.3.3, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" -once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" +once@~1.3.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" dependencies: wrappy "1" @@ -2303,6 +2335,12 @@ p-reduce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" +p-retry@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-1.0.0.tgz#3927332a4b7d70269b535515117fc547da1a6968" + dependencies: + retry "^0.10.0" + p-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-series/-/p-series-1.0.0.tgz#7ec9e7b4406cc32066298a6f9860e55e91b36e07" @@ -2318,7 +2356,7 @@ package-json@^4.0.0: registry-url "^3.0.3" semver "^5.1.0" -parse-github-repo-url@^1.3.0: +parse-github-repo-url@^1.3.0, parse-github-repo-url@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" @@ -2398,9 +2436,9 @@ pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" pify@^2.0.0, pify@^2.3.0: version "2.3.0" @@ -2445,8 +2483,8 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.4.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" qs@~6.2.0: version "6.2.3" @@ -2456,20 +2494,26 @@ qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" querystringify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" -queue@^3.0.10, queue@^3.1.0: +queue@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" dependencies: inherits "~2.0.0" +queue@^4.2.1: + version "4.4.2" + resolved "https://registry.yarnpkg.com/queue/-/queue-4.4.2.tgz#5a9733d9a8b8bd1b36e934bc9c55ab89b28e29c7" + dependencies: + inherits "~2.0.0" + randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -2478,8 +2522,8 @@ randomatic@^1.1.3: kind-of "^4.0.0" rc@^1.0.1, rc@^1.1.6: - version "1.2.1" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" dependencies: deep-extend "~0.4.0" ini "~1.3.0" @@ -2623,32 +2667,32 @@ request@2.79.0, request@~2.79.0: tunnel-agent "~0.4.1" uuid "^3.0.0" -request@^2.74.0, request@^2.79.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" +request@^2.74.0, request@^2.79.0, request@^2.83.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" + aws-sign2 "~0.7.0" + aws4 "^1.6.0" caseless "~0.12.0" combined-stream "~1.0.5" - extend "~3.0.0" + extend "~3.0.1" forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" tunnel-agent "^0.6.0" - uuid "^3.0.0" + uuid "^3.1.0" request@~2.74.0: version "2.74.0" @@ -2689,8 +2733,8 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" resolve@^1.3.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" @@ -2710,13 +2754,13 @@ rimraf@2, rimraf@^2.2.8: dependencies: glob "^7.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -samsam@1.x, samsam@^1.1.3: - version "1.2.1" - resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.2.1.tgz#edd39093a3184370cb859243b2bdf255e7d8ea67" +samsam@1.x: + version "1.3.0" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" semantic-release-visualstudio-marketplace-version@^1.0.0: version "1.0.0" @@ -2726,9 +2770,9 @@ semantic-release-visualstudio-marketplace-version@^1.0.0: lodash.get "^4.4.2" request "^2.79.0" -semantic-release@^8.0.3: - version "8.1.0" - resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-8.1.0.tgz#67483049656664ce54787c8c51a4b9a86b81c6ec" +semantic-release@^8.2.0: + version "8.2.3" + resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-8.2.3.tgz#a746a0a588be1c24aa8c212ee8dc3bda9ec85d46" dependencies: "@semantic-release/commit-analyzer" "^3.0.1" "@semantic-release/condition-travis" "^6.0.0" @@ -2738,7 +2782,7 @@ semantic-release@^8.0.3: execa "^0.8.0" fs-extra "^4.0.2" git-head "^1.2.1" - github "^11.0.0" + github "^12.0.0" lodash "^4.0.0" nerf-dart "^1.0.0" nopt "^4.0.0" @@ -2764,10 +2808,6 @@ semver-diff@^2.0.0: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -2790,19 +2830,16 @@ sinon-chai@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d" -sinon@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.0.0.tgz#a54a5f0237aa1dd2215e5e81c89b42b50c4fdb6b" +sinon@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.0.2.tgz#c81f62456d37986c84e9f522ddb9ce413bda49d2" dependencies: diff "^3.1.0" formatio "1.2.0" lodash.get "^4.4.2" - lolex "^2.1.2" - native-promise-only "^0.8.1" - nise "^1.1.0" - path-to-regexp "^1.7.0" - samsam "^1.1.3" - text-encoding "0.6.4" + lolex "^2.1.3" + nise "^1.2.0" + supports-color "^4.4.0" type-detect "^4.0.0" slash@^1.0.0: @@ -2819,11 +2856,17 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -source-map-support@^0.4.11: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +source-map-support@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab" dependencies: - source-map "^0.5.6" + source-map "^0.6.0" source-map@^0.4.4: version "0.4.4" @@ -2831,7 +2874,11 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.6, source-map@~0.5.1: +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -2854,8 +2901,8 @@ spdx-license-ids@^1.0.2: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" split2@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/split2/-/split2-2.1.1.tgz#7a1f551e176a90ecd3345f7246a0cfe175ef4fd0" + version "2.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" dependencies: through2 "^2.0.2" @@ -2909,10 +2956,6 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" -stream-consume@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" - stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" @@ -2952,7 +2995,7 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -2995,19 +3038,19 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" -supports-color@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" dependencies: - has-flag "^1.0.0" + has-flag "^2.0.0" supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^4.0.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" +supports-color@^4.0.0, supports-color@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" dependencies: has-flag "^2.0.0" @@ -3025,13 +3068,13 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -text-encoding@0.6.4, text-encoding@^0.6.4: +text-encoding@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" text-extensions@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.6.0.tgz#771561b26022783a45f5b6c2e78ad6e7de9fe322" + version "1.7.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39" text-hex@0.0.x: version "0.0.0" @@ -3044,14 +3087,14 @@ through2-filter@^2.0.0: through2 "~2.0.0" xtend "~4.0.0" -through2@^0.6.0, through2@^0.6.1, through2@^0.6.3, through2@~0.6.5: +through2@^0.6.0, through2@^0.6.1, through2@~0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" dependencies: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" -through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@~2.0.0, through2@~2.0.3: +through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" dependencies: @@ -3076,9 +3119,9 @@ to-absolute-glob@^0.1.1: dependencies: extend-shallow "^2.0.1" -tough-cookie@~2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" +tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" @@ -3091,11 +3134,12 @@ travis-ci@^2.1.1: request "~2.74.0" underscore.string "~2.2.0rc" -travis-deploy-once@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/travis-deploy-once/-/travis-deploy-once-2.0.1.tgz#6a60a3d15a6e19f00b979b4bc5e56990c8f2d593" +travis-deploy-once@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/travis-deploy-once/-/travis-deploy-once-3.0.0.tgz#079f7c2d56472ef8e87d540c9b108bed9d9e1fdd" dependencies: - axios "^0.16.2" + chalk "^2.1.0" + p-retry "^1.0.0" semver "^5.4.1" travis-ci "^2.1.1" @@ -3111,9 +3155,9 @@ triple-beam@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.1.0.tgz#2ac387c8c4bd04bd26c61df891a6079f8592fe10" -tslib@^1.0.0, tslib@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" +tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.0.tgz#dc604ebad64bcbf696d613da6c954aa0e7ea1eb6" tslint-config-airbnb@^5.3.0: version "5.3.0" @@ -3125,11 +3169,11 @@ tslint-config-airbnb@^5.3.0: vrsource-tslint-rules "^5.1.0" tslint-consistent-codestyle@^1.4.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.6.0.tgz#e42f5fd1d5bd4ffa697386ec8a41ed2cb6812aaf" + version "1.8.0" + resolved "https://registry.yarnpkg.com/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.8.0.tgz#ede0b5ec6777f8ff4426d9838bc9bf18e8174480" dependencies: tslib "^1.7.1" - tsutils "^2.6.1" + tsutils "^2.12.0" tslint-eslint-rules@^4.1.1: version "4.1.1" @@ -3145,12 +3189,13 @@ tslint-microsoft-contrib@^5.0.0: dependencies: tsutils "^1.4.0" -tslint@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.7.0.tgz#c25e0d0c92fa1201c2bc30e844e08e682b4f3552" +tslint@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13" dependencies: babel-code-frame "^6.22.0" - colors "^1.1.2" + builtin-modules "^1.1.1" + chalk "^2.1.0" commander "^2.9.0" diff "^3.2.0" glob "^7.1.1" @@ -3158,7 +3203,7 @@ tslint@^5.7.0: resolve "^1.3.2" semver "^5.3.0" tslib "^1.7.1" - tsutils "^2.8.1" + tsutils "^2.12.1" tslint@~5.1.0: version "5.1.0" @@ -3178,15 +3223,9 @@ tsutils@^1.4.0: version "1.9.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" -tsutils@^2.11.1: - version "2.11.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.11.1.tgz#103dff3fa508aff5649c16dc4e6dd45dc41dbc62" - dependencies: - tslib "^1.7.1" - -tsutils@^2.6.1, tsutils@^2.8.1: - version "2.8.2" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.2.tgz#2c1486ba431260845b0ac6f902afd9d708a8ea6a" +tsutils@^2.12.0, tsutils@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.1.tgz#f4d95ce3391c8971e46e54c4cf0edb0a21dd5b24" dependencies: tslib "^1.7.1" @@ -3212,20 +3251,16 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript-parser@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/typescript-parser/-/typescript-parser-2.0.1.tgz#ee6bc35b7e0cea47e0ab2f828e3ff6c16b6e3115" +typescript-parser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/typescript-parser/-/typescript-parser-2.2.1.tgz#2b8927105788de63a12159031c62120ca70be9e0" dependencies: coveralls "^2.13.3" lodash "^4.17.4" tslib "^1.7.1" - typescript "2.4.2" - -typescript@2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.2.tgz#f8395f85d459276067c988aa41837a8f82870844" + typescript "^2.5.3" -typescript@~2.5.3: +typescript@^2.5.3, typescript@~2.5.3: version "2.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d" @@ -3272,13 +3307,14 @@ unzip-response@^2.0.1: resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" update-notifier@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.2.0.tgz#1b5837cf90c0736d88627732b661c138f86de72f" + version "2.3.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.3.0.tgz#4e8827a6bb915140ab093559d7014e3ebb837451" dependencies: - boxen "^1.0.0" - chalk "^1.0.0" + boxen "^1.2.1" + chalk "^2.0.1" configstore "^3.0.0" import-lazy "^2.1.0" + is-installed-globally "^0.1.0" is-npm "^1.0.0" latest-version "^3.0.0" semver-diff "^2.0.0" @@ -3301,7 +3337,7 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -uuid@^3.0.0: +uuid@^3.0.0, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -3359,7 +3395,7 @@ vinyl-source-stream@^1.1.0: through2 "^0.6.1" vinyl "^0.4.3" -vinyl@^0.4.3, vinyl@^0.4.6, vinyl@~0.4.6: +vinyl@^0.4.3, vinyl@~0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" dependencies: @@ -3382,6 +3418,17 @@ vinyl@^1.0.0: clone-stats "^0.0.1" replace-ext "0.0.1" +vinyl@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + vinyl@~2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c" @@ -3400,22 +3447,22 @@ vrsource-tslint-rules@^5.1.0: dependencies: tslint "~5.1.0" -vscode@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.5.tgz#10eb104001840c3dd0813815fd4a05f8fc882d14" +vscode@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.6.tgz#46ed1afa2c1b9d689f6394c8f16bd1d7190f75fb" dependencies: - glob "^7.1.1" + glob "^7.1.2" gulp-chmod "^2.0.0" - gulp-filter "^5.0.0" - gulp-gunzip "0.0.3" - gulp-remote-src "^0.4.2" + gulp-filter "^5.0.1" + gulp-gunzip "1.0.0" + gulp-remote-src "^0.4.3" gulp-symdest "^1.1.0" gulp-untar "^0.0.6" - gulp-vinyl-zip "^1.4.0" - mocha "^3.2.0" - request "^2.79.0" - semver "^5.3.0" - source-map-support "^0.4.11" + gulp-vinyl-zip "^2.1.0" + mocha "^4.0.1" + request "^2.83.0" + semver "^5.4.1" + source-map-support "^0.5.0" url-parse "^1.1.9" vinyl-source-stream "^1.1.0" @@ -3506,8 +3553,8 @@ yargs@~3.10.0: window-size "0.1.0" yauzl@^2.2.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.8.0.tgz#79450aff22b2a9c5a41ef54e02db907ccfbf9ee2" + version "2.9.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.0.tgz#927aa84392eed053124496b6ea8fc1f52dae5b52" dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" From 8ccf292b62fcf0c4a72493cf601212e343b94e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Mon, 30 Oct 2017 08:32:02 +0100 Subject: [PATCH 6/9] change settings for new logging --- test/_workspace/.vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/_workspace/.vscode/settings.json b/test/_workspace/.vscode/settings.json index 1705c40..de48826 100755 --- a/test/_workspace/.vscode/settings.json +++ b/test/_workspace/.vscode/settings.json @@ -9,7 +9,7 @@ "dist", "resourceParser" ], - "typescriptHero.verbosity": "All", + "typescriptHero.verbosity": "warn", "tslint.enable": false, "typescriptHero.codeOutline.enabled": true, "typescriptHero.resolver.organizeOnSave": false, From dfe8b2a90daa1305c08373ba44cf8f0d675195e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Mon, 30 Oct 2017 17:54:40 +0100 Subject: [PATCH 7/9] fix: not removing default exports and indexer properties when used (#328) --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index aff4dd3..b3318d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3252,8 +3252,8 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" typescript-parser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/typescript-parser/-/typescript-parser-2.2.1.tgz#2b8927105788de63a12159031c62120ca70be9e0" + version "2.2.2" + resolved "https://registry.yarnpkg.com/typescript-parser/-/typescript-parser-2.2.2.tgz#c8f0adeca61c2a8718c32bd00e628f8cc06b6bb4" dependencies: coveralls "^2.13.3" lodash "^4.17.4" @@ -3553,8 +3553,8 @@ yargs@~3.10.0: window-size "0.1.0" yauzl@^2.2.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.0.tgz#927aa84392eed053124496b6ea8fc1f52dae5b52" + version "2.9.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" From b8f57409a4d097883a4060efd181025cd19d202d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Mon, 30 Oct 2017 22:56:45 +0100 Subject: [PATCH 8/9] chore: windows building and testing (#329) This adds appveyor as a windows build engine. The used variables are defined in appveyor.yml and in the travis ci yml file. For local testing, this shouldn't be necessary. --- .appveyor.yml | 18 ++++++++++++++++++ .travis.yml | 6 ++++++ README.md | 1 + etc/test_install.js | 8 ++++++++ package.json | 7 +++---- src/common/helpers/DeclarationIndexHelpers.ts | 7 ++++--- test/_workspace/.vscode/settings.json | 1 + yarn.lock | 13 ++++++++++++- 8 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 .appveyor.yml create mode 100644 etc/test_install.js diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..1bfe3b9 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,18 @@ +version: "{build} - {branch}" +skip_tags: true +skip_branch_with_pr: true + +environment: + nodejs_version: "8" + CODE_TESTS_WORKSPACE: "$(APPVEYOR_BUILD_FOLDER)/test/_workspace" + CODE_TESTS_PATH: "$(APPVEYOR_BUILD_FOLDER)/out/test/single-workspace-tests" + +install: + - ps: Install-Product node $env:nodejs_version + - npm install -g yarn + - yarn install + +test_script: + - yarn test + +build: off diff --git a/.travis.yml b/.travis.yml index 8d5f6f3..a7933b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,12 @@ notifications: os: - linux +env: + - CODE_TESTS_WORKSPACE=$TRAVIS_BUILD_DIR/test/_workspace CODE_TESTS_PATH=$TRAVIS_BUILD_DIR/out/test/single-workspace-tests + +# add as soon as multi root workspaces are available: +#- CODE_TESTS_WORKSPACE=$TRAVIS_BUILD_DIR/test/multi-root.code-workspace CODE_TESTS_PATH=$TRAVIS_BUILD_DIR/out/test/multi-root-workspace-tests + addons: apt: sources: diff --git a/README.md b/README.md index f8cb776..9c2a401 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ in the future and there are many features in the pipeline that will enhance the work with typescript. [![Travis build](https://img.shields.io/travis/buehler/typescript-hero.svg)](https://travis-ci.org/buehler/typescript-hero) +[![Build status](https://ci.appveyor.com/api/projects/status/p1vbbyh69j4s0rbh?svg=true)](https://ci.appveyor.com/project/buehler/typescript-hero) [![Marketplace](https://vsmarketplacebadge.apphb.com/version-short/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) [![Installs](https://vsmarketplacebadge.apphb.com/installs/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) [![GitHub issues](https://img.shields.io/github/issues/buehler/typescript-hero.svg)](https://github.com/buehler/typescript-hero/issues) diff --git a/etc/test_install.js b/etc/test_install.js new file mode 100644 index 0000000..e383b80 --- /dev/null +++ b/etc/test_install.js @@ -0,0 +1,8 @@ +const { existsSync } = require('fs'); +const { join } = require('path'); + +if (existsSync(join(__dirname, '..', 'node_modules', 'vscode', 'bin', 'install'))) { + process.exit(0); + return; +} +process.exit(1); diff --git a/package.json b/package.json index 1138b99..1c129b4 100644 --- a/package.json +++ b/package.json @@ -79,12 +79,10 @@ "vscode:prepublish": "yarn install --production", "predevelop": "del-cli ./out", "develop": "tsc", - "postinstall": "test -f ./node_modules/vscode/bin/install && node ./node_modules/vscode/bin/install || echo 'vscode/bin/install not found'", + "postinstall": "node ./etc/test_install.js && node ./node_modules/vscode/bin/install || echo 'vscode/bin/install not found'", "lint": "tslint -c tslint.json --project ./config/tsconfig.build.json", "pretest": "del-cli ./out && tsc -p ./config/tsconfig.test.json && yarn lint", - "test": "yarn test:single-workspace", - "test:single-workspace": "CODE_TESTS_WORKSPACE=$(pwd)/test/_workspace CODE_TESTS_PATH=$(pwd)/out/test/single-workspace-tests node ./node_modules/vscode/bin/test", - "test:multi-workspace": "CODE_TESTS_WORKSPACE=$(pwd)/test/multi-root.code-workspace CODE_TESTS_PATH=$(pwd)/out/test/multi-root-workspace-tests node ./node_modules/vscode/bin/test", + "test": "node ./node_modules/vscode/bin/test", "build": "del-cli ./out && tsc -p ./config/tsconfig.build.json", "package": "yarn build && del-cli './*.vsix' && vsce package", "semantic-release-pre": "semantic-release pre", @@ -98,6 +96,7 @@ "@types/sinon": "^2.3.7", "@types/sinon-chai": "^2.7.29", "chai": "^4.1.2", + "cross-env": "^5.1.1", "del-cli": "^1.1.0", "filewalker": "^0.1.3", "mocha-testdata": "^1.2.0", diff --git a/src/common/helpers/DeclarationIndexHelpers.ts b/src/common/helpers/DeclarationIndexHelpers.ts index fd27adc..491c383 100644 --- a/src/common/helpers/DeclarationIndexHelpers.ts +++ b/src/common/helpers/DeclarationIndexHelpers.ts @@ -1,6 +1,7 @@ import { existsSync } from 'fs'; import { join, normalize, parse, relative } from 'path'; import { DeclarationInfo, ExternalModuleImport, Import, NamedImport, NamespaceImport } from 'typescript-parser'; +import { toPosix } from 'typescript-parser/utilities/PathHelpers'; import { RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode'; import { ExtensionConfig } from '../config'; @@ -56,10 +57,10 @@ export function getAbsolutLibraryName(library: string, actualFilePath: string, r if (!library.startsWith('.') || !rootPath) { return library; } - return '/' + relative( + return '/' + toPosix(relative( rootPath, normalize(join(parse(actualFilePath).dir, library)), - ).replace(/[/]$/g, ''); + )).replace(/[/]$/g, ''); } /** @@ -86,7 +87,7 @@ export function getRelativeLibraryName(library: string, actualFilePath: string, } else if (relativePath === '..') { relativePath += '/'; } - return relativePath.replace(/\\/g, '/'); + return toPosix(relativePath); } /** diff --git a/test/_workspace/.vscode/settings.json b/test/_workspace/.vscode/settings.json index de48826..5b32623 100755 --- a/test/_workspace/.vscode/settings.json +++ b/test/_workspace/.vscode/settings.json @@ -9,6 +9,7 @@ "dist", "resourceParser" ], + "files.eol": "\n", "typescriptHero.verbosity": "warn", "tslint.enable": false, "typescriptHero.codeOutline.enabled": true, diff --git a/yarn.lock b/yarn.lock index b3318d4..ba8dcb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -633,7 +633,14 @@ create-error-class@^3.0.0: dependencies: capture-stack-trace "^1.0.0" -cross-spawn@^5.0.1: +cross-env@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.1.tgz#b6d8ab97f304c0f71dae7277b75fe424c08dfa74" + dependencies: + cross-spawn "^5.1.0" + is-windows "^1.0.0" + +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1693,6 +1700,10 @@ is-valid-glob@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" +is-windows@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" + is@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" From 38c6b31b56337871381ebfa88b04889ad1c9089e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Tue, 31 Oct 2017 08:46:47 +0100 Subject: [PATCH 9/9] docs: badges --- README.md | 2 +- package.json | 26 +++----------------------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 9c2a401..e9fdf94 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ in the future and there are many features in the pipeline that will enhance the work with typescript. [![Travis build](https://img.shields.io/travis/buehler/typescript-hero.svg)](https://travis-ci.org/buehler/typescript-hero) -[![Build status](https://ci.appveyor.com/api/projects/status/p1vbbyh69j4s0rbh?svg=true)](https://ci.appveyor.com/project/buehler/typescript-hero) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/p1vbbyh69j4s0rbh?svg=true)](https://ci.appveyor.com/project/buehler/typescript-hero) [![Marketplace](https://vsmarketplacebadge.apphb.com/version-short/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) [![Installs](https://vsmarketplacebadge.apphb.com/installs/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) [![GitHub issues](https://img.shields.io/github/issues/buehler/typescript-hero.svg)](https://github.com/buehler/typescript-hero/issues) diff --git a/package.json b/package.json index 1c129b4..37f412b 100644 --- a/package.json +++ b/package.json @@ -32,14 +32,9 @@ "description": "Travis build" }, { - "url": "https://vsmarketplacebadge.apphb.com/version-short/rbbit.typescript-hero.svg", - "href": "https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero", - "description": "Marketplace" - }, - { - "url": "https://vsmarketplacebadge.apphb.com/installs/rbbit.typescript-hero.svg", - "href": "https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero", - "description": "Installs" + "url": "https://ci.appveyor.com/api/projects/status/p1vbbyh69j4s0rbh?svg=true", + "href": "https://ci.appveyor.com/project/buehler/typescript-hero", + "description": "AppVeyor build" }, { "url": "https://img.shields.io/github/issues/buehler/typescript-hero.svg", @@ -50,21 +45,6 @@ "url": "https://img.shields.io/github/issues-pr/buehler/typescript-hero.svg", "href": "https://github.com/buehler/typescript-hero/pulls", "description": "GitHub pull requests" - }, - { - "url": "https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg", - "href": "https://github.com/semantic-release/semantic-release", - "description": "Semantic release" - }, - { - "url": "https://badges.greenkeeper.io/buehler/typescript-hero.svg", - "href": "https://greenkeeper.io/", - "description": "Greenkeeper" - }, - { - "url": "https://img.shields.io/github/license/buehler/typescript-hero.svg", - "href": "https://github.com/buehler/typescript-hero/blob/master/LICENSE", - "description": "License" } ], "repository": {