From 8b3aeb8c43b24ee0210a602a9a716277a83ffb0c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 6 Jun 2016 12:38:54 -0700 Subject: [PATCH 01/49] Functional extension loading & lint passes --- Jakefile.js | 5 +- src/compiler/checker.ts | 4 + src/compiler/commandLineParser.ts | 6 + src/compiler/core.ts | 20 ++ src/compiler/diagnosticMessages.json | 15 +- src/compiler/program.ts | 219 ++++++++++++- src/compiler/sys.ts | 4 + src/compiler/tsc.ts | 18 +- src/compiler/types.ts | 69 +++- src/compiler/utilities.ts | 13 + src/services/shims.ts | 4 +- tests/cases/unittests/extensionAPI.ts | 455 ++++++++++++++++++++++++++ 12 files changed, 806 insertions(+), 26 deletions(-) create mode 100644 tests/cases/unittests/extensionAPI.ts diff --git a/Jakefile.js b/Jakefile.js index f11d1bf423d2b..9679199807b76 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -157,7 +157,8 @@ var harnessSources = harnessCoreSources.concat([ "convertCompilerOptionsFromJson.ts", "convertTypingOptionsFromJson.ts", "tsserverProjectSystem.ts", - "matchFiles.ts" + "matchFiles.ts", + "extensionAPI.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ @@ -527,7 +528,7 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca // Node package definition file to be distributed without the package. Created by replacing // 'ts' namespace with '"typescript"' as a module. - var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'); + var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts {/g, 'declare module "typescript" {\n import * as ts from "typescript";'); fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents); }); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac8a47a991379..49d8a98e49b8d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17258,6 +17258,10 @@ namespace ts { return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true); } + if (node.kind === SyntaxKind.SourceFile) { + return unknownType; + } + if (isInRightSideOfImportOrExportAssignment(node)) { const symbol = getSymbolAtLocation(node); const declaredType = symbol && getDeclaredTypeOfSymbol(symbol); diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 2e0bfa8290a22..3d32316491fd1 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -268,6 +268,12 @@ namespace ts { experimental: true, description: Diagnostics.Enables_experimental_support_for_emitting_type_metadata_for_decorators }, + { + name: "extensions", + type: "object", + isTSConfigOnly: true, + description: Diagnostics.List_of_compiler_extensions_to_require + }, { name: "moduleResolution", type: { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index ed171b720d0a2..165baca488ff8 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -176,6 +176,26 @@ namespace ts { return array1.concat(array2); } + export function flatten(array1: T[][]): T[] { + if (!array1 || !array1.length) return array1; + return [].concat(...array1); + } + + export function groupBy(array: T[], classifier: (item: T) => string): {[index: string]: T[]}; + export function groupBy(array: T[], classifier: (item: T) => number): {[index: number]: T[]}; + export function groupBy(array: T[], classifier: (item: T) => (string | number)): {[index: string]: T[], [index: number]: T[]} { + if (!array || !array.length) return undefined; + const ret: {[index: string]: T[], [index: number]: T[]} = {}; + for (let i = 0, len = array.length; i < len; i++) { + const result = classifier(array[i]); + if (!ret[result]) { + ret[result] = []; + } + ret[result].push(array[i]); + } + return ret; + } + export function deduplicate(array: T[], areEqual?: (a: T, b: T) => boolean): T[] { let result: T[]; if (array) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d3ecb1715a910..1b0d456351ffb 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2656,7 +2656,7 @@ "category": "Message", "code": 6099 }, - "'package.json' does not have 'types' field.": { + "'package.json' does not have '{0}' field.": { "category": "Message", "code": 6100 }, @@ -2789,6 +2789,19 @@ "code": 6132 }, + "List of compiler extensions to require.": { + "category": "Message", + "code": 6150 + }, + "Extension loading failed with error '{0}'.": { + "category": "Error", + "code": 6151 + }, + "Extension '{0}' exported member '{1}' has extension kind '{2}', but was type '{3}' when type '{4}' was expected.": { + "category": "Error", + "code": 6152 + }, + "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index a01f3a4c5b240..2a4bfa7fa2214 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -176,6 +176,39 @@ namespace ts { return undefined; } + function tryReadMainSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { + let jsonContent: { main?: string }; + try { + const jsonText = state.host.readFile(packageJsonPath); + jsonContent = jsonText ? <{ main?: string }>JSON.parse(jsonText) : {}; + } + catch (e) { + // gracefully handle if readFile fails or returns not JSON + jsonContent = {}; + } + + let mainFile: string; + + if (jsonContent.main) { + if (typeof jsonContent.main === "string") { + mainFile = jsonContent.main; + } + else { + if (state.traceEnabled) { + trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "main", typeof jsonContent.main); + } + } + } + if (mainFile) { + const mainFilePath = normalizePath(combinePaths(baseDirectory, mainFile)); + if (state.traceEnabled) { + trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, "main", mainFile, mainFilePath); + } + return mainFilePath; + } + return undefined; + } + const typeReferenceExtensions = [".d.ts"]; function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) { @@ -282,7 +315,7 @@ namespace ts { }; } - export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { + export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, loadJs?: boolean): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (traceEnabled) { trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile); @@ -304,7 +337,7 @@ namespace ts { let result: ResolvedModuleWithFailedLookupLocations; switch (moduleResolution) { case ModuleResolutionKind.NodeJs: - result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host); + result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, loadJs); break; case ModuleResolutionKind.Classic: result = classicNameResolver(moduleName, containingFile, compilerOptions, host); @@ -599,7 +632,7 @@ namespace ts { }; } - export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { + export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, loadJs?: boolean): ResolvedModuleWithFailedLookupLocations { const containingDirectory = getDirectoryPath(containingFile); const supportedExtensions = getSupportedExtensions(compilerOptions); const traceEnabled = isTraceEnabled(compilerOptions, host); @@ -615,7 +648,7 @@ namespace ts { if (traceEnabled) { trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName); } - resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state); + resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state, loadJs); isExternalLibraryImport = resolvedFileName !== undefined; } else { @@ -705,14 +738,14 @@ namespace ts { } } - function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string { + function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState, loadJS?: boolean): string { const packageJsonPath = combinePaths(candidate, "package.json"); const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host); if (directoryExists && state.host.fileExists(packageJsonPath)) { if (state.traceEnabled) { trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath); } - const typesFile = tryReadTypesSection(packageJsonPath, candidate, state); + const typesFile = loadJS ? tryReadMainSection(packageJsonPath, candidate, state) : tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state); if (result) { @@ -721,7 +754,7 @@ namespace ts { } else { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_does_not_have_types_field); + trace(state.host, Diagnostics.package_json_does_not_have_0_field, loadJS ? "main" : "types"); } } } @@ -736,29 +769,30 @@ namespace ts { return loadModuleFromFile(combinePaths(candidate, "index"), extensions, failedLookupLocation, !directoryExists, state); } - function loadModuleFromNodeModulesFolder(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState): string { + function loadModuleFromNodeModulesFolder(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState, loadJS?: boolean): string { const nodeModulesFolder = combinePaths(directory, "node_modules"); const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host); const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName)); // Load only typescript files irrespective of allowJs option if loading from node modules - let result = loadModuleFromFile(candidate, supportedTypeScriptExtensions, failedLookupLocations, !nodeModulesFolderExists, state); + const extensionsSearched = loadJS ? supportedJavascriptExtensions : supportedTypeScriptExtensions; + let result = loadModuleFromFile(candidate, extensionsSearched, failedLookupLocations, !nodeModulesFolderExists, state); if (result) { return result; } - result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state); + result = loadNodeModuleFromDirectory(extensionsSearched, candidate, failedLookupLocations, !nodeModulesFolderExists, state, loadJS); if (result) { return result; } } - function loadModuleFromNodeModules(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState): string { + function loadModuleFromNodeModules(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState, loadJS?: boolean): string { directory = normalizeSlashes(directory); while (true) { const baseName = getBaseFileName(directory); if (baseName !== "node_modules") { const result = // first: try to load module as-is - loadModuleFromNodeModulesFolder(moduleName, directory, failedLookupLocations, state) || + loadModuleFromNodeModulesFolder(moduleName, directory, failedLookupLocations, state, loadJS) || // second: try to load module from the scope '@types' loadModuleFromNodeModulesFolder(combinePaths("@types", moduleName), directory, failedLookupLocations, state); if (result) { @@ -935,6 +969,12 @@ namespace ts { return getDirectoryPath(normalizePath(sys.getExecutingFilePath())); } + function loadExtension(name: string): any { + if (sys.loadExtension) { + return sys.loadExtension(name); + } + } + const newLine = getNewLineCharacter(options); const realpath = sys.realpath && ((path: string) => sys.realpath(path)); @@ -952,7 +992,8 @@ namespace ts { trace: (s: string) => sys.write(s + newLine), directoryExists: directoryName => sys.directoryExists(directoryName), getDirectories: (path: string) => sys.getDirectories(path), - realpath + realpath, + loadExtension }; } @@ -1129,6 +1170,8 @@ namespace ts { // unconditionally set oldProgram to undefined to prevent it from being captured in closure oldProgram = undefined; + const compilerExtensions = collectCompilerExtensions(); + program = { getRootFileNames: () => rootNames, getSourceFile, @@ -1151,7 +1194,10 @@ namespace ts { getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(), getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(), getFileProcessingDiagnostics: () => fileProcessingDiagnostics, - getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives + getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives, + getCompilerExtensions() { + return compilerExtensions; + } }; verifyCompilerOptions(); @@ -1160,6 +1206,76 @@ namespace ts { return program; + function collectCompilerExtensions(): ExtensionCollectionMap { + const extOptions = options.extensions; + const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); + return groupBy(flatten(map(filter(map(extensionNames, name => { + let result: any; + let error: any; + if (host.loadExtension) { + // TODO (weswig): @ts is taken on npm. Aquire it or use @tsc? + const resolved = resolveModuleName(combinePaths("@ts", name), combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; + if (resolved) { + try { + result = host.loadExtension(resolved.resolvedFileName); + } + catch (e) { + error = e; + } + } + else { + error = new Error(`Host could not locate extension '${name}'.`); + } + } + else { + error = new Error("Extension loading not implemented in compiler host."); + } + if (error) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Extension_loading_failed_with_error_0, error.stack ? `${error} + Stack trace: + ${error.stack}` : error)); + } + return {name, result, error}; + }), res => !res.error), res => { + if (res.result) { + return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: any, key: string) => { + if (!potentialExtension) { + return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) + } + const annotatedKind = potentialExtension.__tsCompilerExtensionKind; + if (typeof annotatedKind === "string") { + const ext: ExtensionBase = { + name: key !== "default" ? `${res.name}[${key}]` : res.name, + args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], + kind: annotatedKind as ExtensionKind + }; + switch (ext.kind) { + case ExtensionKind.SemanticLint: + case ExtensionKind.SyntacticLint: + if (typeof potentialExtension !== "function") { + programDiagnostics.add(createCompilerDiagnostic( + Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, + res.name, + key, + (ts as any).ExtensionKind[annotatedKind], + typeof potentialExtension, + "function" + )); + return; + } + (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension; + } + aggregate.push(ext as Extension); + } + return aggregate; + }, []); + } + else { + return []; + } + })), elem => elem.kind) || {}; + } + function getCommonSourceDirectory() { if (typeof commonSourceDirectory === "undefined") { if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) { @@ -1454,7 +1570,79 @@ namespace ts { } } + /** + * ExtensionKind.SyntacticLint or ExtensionKind.SemanticLint only + */ + function performLintPassOnFile(sourceFile: SourceFile, kind: ExtensionKind): Diagnostic[] | undefined { + const lints = compilerExtensions[kind]; + if (!lints || !lints.length) { + return; + } + type UniqueLint = {name: string, walker: LintWalker, accepted: boolean}; + const initializedLints = new Array(lints.length); + const diagnostics: Diagnostic[] = []; + let activeLint: UniqueLint; + let parent: Node | undefined = undefined; + for (let i = 0; i < lints.length; i++) { + if (kind === ExtensionKind.SemanticLint) { + initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)(ts, getTypeChecker(), lints[i].args), accepted: true}; + } + else if (kind === ExtensionKind.SyntacticLint) { + initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)(ts, lints[i].args), accepted: true}; + } + } + + visitNode(sourceFile); + + return diagnostics; + + function visitNode(node: Node) { + let oneAccepted = false; + const oldParent = parent; + const needsReset: boolean[] = new Array(initializedLints.length); + for (let i = 0; i < initializedLints.length; i++) { + if (initializedLints[i].accepted) { + activeLint = initializedLints[i]; + activeLint.accepted = false; + node.parent = parent; + activeLint.walker.visit(node, accept, error); + if (activeLint.accepted) { + oneAccepted = true; + } + else { + needsReset[i] = true; + } + } + } + parent = node; + if (oneAccepted) { + forEachChild(node, visitNode); + } + parent = oldParent; + for (let i = 0; i < initializedLints.length; i++) { + if (needsReset[i]) { + initializedLints[i].accepted = true; + needsReset[i] = false; + } + } + } + + function accept() { + activeLint.accepted = true; + } + + function error(err: string, node: Node) { + diagnostics.push(createExtensionDiagnosticForNode(node, activeLint.name, err)); + } + } + function getSyntacticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + if (!(sourceFile.isDeclarationFile || sourceFile.externalModuleIndicator)) { + const lintDiagnostics = performLintPassOnFile(sourceFile, ExtensionKind.SyntacticLint); + if (lintDiagnostics && lintDiagnostics.length) { + return sourceFile.parseDiagnostics.concat(lintDiagnostics); + } + } return sourceFile.parseDiagnostics; } @@ -1495,8 +1683,9 @@ namespace ts { typeChecker.getDiagnostics(sourceFile, cancellationToken); const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName); const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName); + const lintDiagnostics = (!(sourceFile.isDeclarationFile || sourceFile.externalModuleIndicator)) ? (performLintPassOnFile(sourceFile, ExtensionKind.SemanticLint) || []) : []; - return bindDiagnostics.concat(checkDiagnostics).concat(fileProcessingDiagnosticsInFile).concat(programDiagnosticsInFile); + return bindDiagnostics.concat(checkDiagnostics).concat(fileProcessingDiagnosticsInFile).concat(programDiagnosticsInFile).concat(lintDiagnostics); }); } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 338b6de1e635f..8ffd48bcf99dc 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -32,6 +32,7 @@ namespace ts { getMemoryUsage?(): number; exit(exitCode?: number): void; realpath?(path: string): string; + loadExtension?(name: string): any; } export interface FileWatcher { @@ -547,6 +548,9 @@ namespace ts { }, realpath(path: string): string { return _fs.realpathSync(path); + }, + loadExtension(name) { + return require(name); } }; } diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index e25ae37e21fa9..e1f2543db98bc 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -115,7 +115,12 @@ namespace ts { } const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; + if (diagnostic.category === DiagnosticCategory.Extension) { + output += `${ category } ${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; + } + else { + output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; + } sys.write(output); } @@ -604,13 +609,16 @@ namespace ts { // First get and report any syntactic errors. diagnostics = program.getSyntacticDiagnostics(); + // Count extension diagnostics and ignore them for determining continued error reporting + const extensionDiagnostics = filter(diagnostics, d => d.category === DiagnosticCategory.Extension).length; + // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. - if (diagnostics.length === 0) { - diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics()); + if (diagnostics.length === extensionDiagnostics) { + diagnostics = diagnostics.concat(program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics())); - if (diagnostics.length === 0) { - diagnostics = program.getSemanticDiagnostics(); + if (diagnostics.length === extensionDiagnostics) { + diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f3549aa381530..0c2740ead64f7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1736,6 +1736,11 @@ namespace ts { */ getTypeChecker(): TypeChecker; + /** + * Gets a map of loaded compiler extensions + */ + getCompilerExtensions(): ExtensionCollectionMap; + /* @internal */ getCommonSourceDirectory(): string; // For testing purposes only. Should not be used by any other consumers (including the @@ -1812,6 +1817,7 @@ namespace ts { getSourceFiles(): SourceFile[]; getSourceFile(fileName: string): SourceFile; getResolvedTypeReferenceDirectives(): Map; + getCompilerExtensions(): ExtensionCollectionMap; } export interface TypeChecker { @@ -2496,13 +2502,14 @@ namespace ts { length: number; messageText: string | DiagnosticMessageChain; category: DiagnosticCategory; - code: number; + code: number | string; } export enum DiagnosticCategory { Warning, Error, Message, + Extension, } export enum ModuleResolutionKind { @@ -2586,6 +2593,7 @@ namespace ts { typesSearchPaths?: string[]; /*@internal*/ version?: boolean; /*@internal*/ watch?: boolean; + extensions?: string[] | Map; [option: string]: CompilerOptionsValue | undefined; } @@ -2893,6 +2901,57 @@ namespace ts { failedLookupLocations: string[]; } + export type LintErrorMethod = (err: string, span: Node) => void; + export type LintAcceptMethod = () => void; + + /* + * Walkers call accept to decend into the node's children + * Walkers call error to add errors to the output. + */ + export interface LintWalker { + visit(node: Node, accept: LintAcceptMethod, error: LintErrorMethod): void; + } + + export interface SyntacticLintProviderStatic { + new (typescript: typeof ts, args: any): LintWalker; + } + + export interface SemanticLintProviderStatic { + new (typescript: typeof ts, checker: TypeChecker, args: any): LintWalker; + } + + export namespace ExtensionKind { + export const SemanticLint: "semantic-lint" = "semantic-lint"; + export type SemanticLint = "semantic-lint"; + export const SyntacticLint: "syntactic-lint" = "syntactic-lint"; + export type SyntacticLint = "syntactic-lint"; + } + export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint; + + export interface ExtensionCollectionMap { + "syntactic-lint"?: SyntacticLintExtension[]; + "semantic-lint"?: SemanticLintExtension[]; + [index: string]: Extension[] | undefined; + } + + export interface ExtensionBase { + name: string; + args: any; + kind: ExtensionKind; + } + + // @kind(ExtensionKind.SyntacticLint) + export interface SyntacticLintExtension extends ExtensionBase { + ctor: SyntacticLintProviderStatic; + } + + // @kind(ExtensionKind.SemanticLint) + export interface SemanticLintExtension extends ExtensionBase { + ctor: SemanticLintProviderStatic; + } + + export type Extension = SyntacticLintExtension | SemanticLintExtension; + export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; @@ -2919,6 +2978,14 @@ namespace ts { * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; + + /** + * Delegates the loading of compiler extensions to the compiler host. + * The function should return the result of executing the code of an extension + * - its exported members. These members will be searched for objects who have been decorated with + * specific flags. + */ + loadExtension?(extension: string): any; } export interface TextSpan { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b4ef62c6c3e22..303d2d61f16c7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -453,6 +453,19 @@ namespace ts { return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2); } + export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string): Diagnostic { + const sourceFile = getSourceFileOfNode(node); + const span = getErrorSpanForNode(sourceFile, node); + return { + file: sourceFile, + messageText: message, + code: extension, + start: span.start, + length: span.length, + category: DiagnosticCategory.Extension + }; + } + export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic { const sourceFile = getSourceFileOfNode(node); const span = getErrorSpanForNode(sourceFile, node); diff --git a/src/services/shims.ts b/src/services/shims.ts index ac74ee0975019..73c516ca19d65 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -541,11 +541,11 @@ namespace ts { } } - export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number; }[] { + export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number | string; }[] { return diagnostics.map(d => realizeDiagnostic(d, newLine)); } - function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number; } { + function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number | string; } { return { message: flattenDiagnosticMessageText(diagnostic.messageText, newLine), start: diagnostic.start, diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts new file mode 100644 index 0000000000000..535b24a15adff --- /dev/null +++ b/tests/cases/unittests/extensionAPI.ts @@ -0,0 +1,455 @@ +/// + +namespace ts { + describe("Extension API", () => { + + function prettyPrintDiagnostic(diagnostic: Diagnostic): string { + const message = flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + if (diagnostic.file) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; + } + else { + return `!!!${message}`; + } + } + + function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: (number | string)[]) { + if (!expectedDiagnosticCodes) { + return; + } + + for (let i = 0; i < expectedDiagnosticCodes.length; i++) { + assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); + } + if (expectedDiagnosticCodes.length === 0 && diagnostics.length) { + throw new Error(`Unexpected diagnostic (${diagnostics.length - 1} more): ${prettyPrintDiagnostic(diagnostics[0])}`); + } + assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); + } + + interface ExtensionTestOptions { + compilerOptions: CompilerOptions; + availableExtensions: string[]; + expectedDiagnostics: (number | string)[]; + } + + const {content: libContent} = Harness.getDefaultLibraryFile(Harness.IO); + const tsLibContents = Harness.IO.readFile("built/local/typescript_standalone.d.ts"); + const virtualLib: Map = { + "/lib/lib.d.ts": libContent, + "/lib/typescript.d.ts": tsLibContents + }; + + let virtualFs: Map = {}; + + const getCanonicalFileName = createGetCanonicalFileName(true); + + function loadSetIntoFsAt(set: Map, prefix: string) { + forEachKey(set, key => void (virtualFs[getCanonicalFileName(combinePaths(prefix, key))] = set[key])); + } + + function loadSetIntoFs(set: Map) { + forEachKey(set, key => void (virtualFs[getCanonicalFileName(key)] = set[key])); + } + + const mockHost: CompilerHost = { + useCaseSensitiveFileNames() { return true; }, + getNewLine() { return "\n"; }, + readFile(path) { return virtualFs[this.getCanonicalFileName(path)]; }, + writeFile(path, content, foo, bar, baz) { + virtualFs[this.getCanonicalFileName(path)] = content; + }, + fileExists(path) { + return !!virtualFs[this.getCanonicalFileName(path)]; + }, + directoryExists(path) { + const fullPath = this.getCanonicalFileName(path); + return forEach(getKeys(virtualFs), key => startsWith(key, fullPath)); + }, + getCurrentDirectory(): string { return "/"; }, + getSourceFile(path, languageVersion, onError): SourceFile { + const fullPath = this.getCanonicalFileName(path); + return createSourceFile(fullPath, virtualFs[fullPath], languageVersion); + }, + getDefaultLibLocation() { + return "/lib/"; + }, + getDefaultLibFileName(options) { + return combinePaths(this.getDefaultLibLocation(), getDefaultLibFileName(options)); + }, + getCanonicalFileName, + getDirectories(path) { + path = this.getCanonicalFileName(path); + return filter(map(filter(getKeys(virtualFs), + fullpath => startsWith(fullpath, path) && fullpath.substr(path.length, 1) === "/"), + fullpath => fullpath.substr(path.length + 1).indexOf("/") >= 0 ? fullpath.substr(0, 1 + path.length + fullpath.substr(path.length + 1).indexOf("/")) : fullpath), + fullpath => fullpath.lastIndexOf(".") === -1); + }, + loadExtension(path) { + const fullPath = this.getCanonicalFileName(path); + const m = {exports: {}}; + ((module, exports, require) => { eval(virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return this.loadExtension( + this.getCanonicalFileName( + ts.resolveModuleName(name, fullPath, {module: ts.ModuleKind.CommonJS}, this, true).resolvedModule.resolvedFileName + ) + ); + } + ); + return m.exports; + }, + trace(s) { + console.log(s); + } + }; + + const extensionAPI: Map = { + "package.json": `{ + "name": "typescript-plugin-api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "", + "types": "index.d.ts" +}`, + "index.ts": ` +import * as tsi from "typescript"; + +export abstract class SyntacticLintWalker implements tsi.LintWalker { + private static __tsCompilerExtensionKind: tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; + constructor(protected ts: typeof tsi, protected args: any) {} + abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void; +} + +export abstract class SemanticLintWalker implements tsi.LintWalker { + private static __tsCompilerExtensionKind: tsi.ExtensionKind.SemanticLint = "semantic-lint"; + constructor(protected ts: typeof tsi, protected checker: tsi.TypeChecker, protected args: any) {} + abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void; +} +` + }; + // Compile extension API once (generating .d.ts and .js) + + function compile(fileset: Map, options: ts.CompilerOptions): Diagnostic[] { + loadSetIntoFs(virtualLib); + loadSetIntoFs(fileset); + + const program = createProgram(filter(getKeys(fileset), name => name != "package.json"), options, mockHost); + program.emit(); + + return ts.getPreEmitDiagnostics(program); + } + + function buildMap(map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean): Diagnostic[] { + const diagnostics = compile(map, compilerOptions ? compilerOptions : {module: ModuleKind.CommonJS, declaration: true}); + if (shouldError && diagnostics && diagnostics.length) { + for (let i = 0; i < diagnostics.length; i++) { + console.log(prettyPrintDiagnostic(diagnostics[i])); + } + throw new Error("Compiling test harness extension API code resulted in errors."); + } + copyMap(virtualFs, out); + virtualFs = {}; + return diagnostics; + } + buildMap(extensionAPI, extensionAPI, {module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: {"typescript": ["/lib/typescript.d.ts"]}}, /*shouldError*/true); + + const extensions: Map> = { + "test-syntactic-lint": { + "package.json": `{ + "name": "@ts/test-syntactic-lint", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {SyntacticLintWalker} from "typescript-plugin-api"; + +export default class IsNamedFoo extends SyntacticLintWalker { + constructor(ts, args) { super(ts, args); } + visit(node, accept, error) { + if (node.kind === this.ts.SyntaxKind.Identifier) { + if (node.text.toLowerCase() === "foo") { + error("Identifier 'foo' is forbidden.", node); + } + } + accept(); + } +} +`, + }, + "test-semantic-lint": { + "package.json": `{ + "name": "@ts/test-semantic-lint", + "version": "1.0.0", + "description": "", + "main": "main.js", + "author": "" +}`, + "main.ts": ` +import {SemanticLintWalker} from "typescript-plugin-api"; + +export default class IsValueFoo extends SemanticLintWalker { + constructor(ts, checker, args) { super(ts, checker, args); } + visit(node, accept, error) { + const type = this.checker.getTypeAtLocation(node); + if (type.flags & this.ts.TypeFlags.StringLiteral) { + if (node.text === "foo") { + error("String literal type 'foo' is forbidden.", node); + } + } + accept(); + } +} +`, + }, + "test-extension-arguments": { + "package.json": `{ + "name": "@ts/test-extension-arguments", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {SyntacticLintWalker} from "typescript-plugin-api"; + +export default class IsNamedX extends SyntacticLintWalker { + constructor(ts, args) { super(ts, args); } + visit(node, accept, error) { + if (node.kind === this.ts.SyntaxKind.Identifier) { + for (let i = 0; i { + loadSetIntoFsAt(extensionAPI, "/node_modules/typescript-plugin-api"); + buildMap(extensions[extName], extensions[extName], {module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: {"typescript": ["lib/typescript.d.ts"]}}, /*shouldError*/true); + }); + + /** + * Setup a new test, where all extensions specified in the options hash are available in a node_modules folder, alongside the extension API + */ + function test(sources: Map, options: ExtensionTestOptions) { + forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/@ts/${ext}`)); + const diagnostics = buildMap(sources, sources, options.compilerOptions); + checkDiagnostics(diagnostics, options.expectedDiagnostics); + } + + it("can load syntactic lint extensions", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }); + }); + + it("can load semantic lint extensions", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + }); + + it("can load semantic & syntactic lint extensions simultaneously", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + + test({ + "main.ts": `interface Foo {a; b;} + const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint", "test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + }); + + it("can pass arguments to lint rules", () => { + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-extension-arguments"], + expectedDiagnostics: ["test-extension-arguments", "test-extension-arguments"], + compilerOptions: { + extensions: { + "test-extension-arguments": ["a", "b"] + }, + module: ModuleKind.CommonJS, + } + }); + }); + + it("can load multiple rules from a single extension", () => { + test({ + "main.ts": `interface Foo {b;} + interface Bar {a;} + const f: "foo" = "foo"; + let b: "bar" = "bar";`, + }, { + availableExtensions: ["test-multi-extension"], + expectedDiagnostics: ["test-multi-extension[IsNamedFoo]", "test-multi-extension[IsNamedBar]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueBar]", "test-multi-extension[IsValueBar]"], + compilerOptions: { + extensions: ["test-multi-extension"], + module: ModuleKind.CommonJS, + } + }); + }); + + it("can error when it fails to load a lint rule", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: [], + expectedDiagnostics: [6151, 6151], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }); + }); + }); +} From 8583037686b18d33cdd87d9d0cfadb8f3f136ed3 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 20 Jun 2016 17:36:00 -0700 Subject: [PATCH 02/49] Dont look for extensions in a namespace --- src/compiler/program.ts | 3 +-- tests/cases/unittests/extensionAPI.ts | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 2a4bfa7fa2214..9d9204c3dfbfb 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1213,8 +1213,7 @@ namespace ts { let result: any; let error: any; if (host.loadExtension) { - // TODO (weswig): @ts is taken on npm. Aquire it or use @tsc? - const resolved = resolveModuleName(combinePaths("@ts", name), combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; + const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; if (resolved) { try { result = host.loadExtension(resolved.resolvedFileName); diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 535b24a15adff..b18168a4c724d 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -161,7 +161,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { const extensions: Map> = { "test-syntactic-lint": { "package.json": `{ - "name": "@ts/test-syntactic-lint", + "name": "test-syntactic-lint", "version": "1.0.0", "description": "", "main": "index.js", @@ -185,7 +185,7 @@ export default class IsNamedFoo extends SyntacticLintWalker { }, "test-semantic-lint": { "package.json": `{ - "name": "@ts/test-semantic-lint", + "name": "test-semantic-lint", "version": "1.0.0", "description": "", "main": "main.js", @@ -210,7 +210,7 @@ export default class IsValueFoo extends SemanticLintWalker { }, "test-extension-arguments": { "package.json": `{ - "name": "@ts/test-extension-arguments", + "name": "test-extension-arguments", "version": "1.0.0", "description": "", "main": "index.js", @@ -236,7 +236,7 @@ export default class IsNamedX extends SyntacticLintWalker { }, "test-multi-extension": { "package.json": `{ - "name": "@ts/test-multi-extension", + "name": "test-multi-extension", "version": "1.0.0", "description": "", "main": "index.js", @@ -308,7 +308,7 @@ export class IsValueBar extends SemanticLintWalker { * Setup a new test, where all extensions specified in the options hash are available in a node_modules folder, alongside the extension API */ function test(sources: Map, options: ExtensionTestOptions) { - forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/@ts/${ext}`)); + forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/${ext}`)); const diagnostics = buildMap(sources, sources, options.compilerOptions); checkDiagnostics(diagnostics, options.expectedDiagnostics); } From a7ae427d02ac4423bd7e6090a30dd6ee3e209cc1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 6 Jun 2016 12:38:54 -0700 Subject: [PATCH 03/49] Language service extensions and tests --- src/compiler/program.ts | 9 +- src/compiler/types.ts | 21 +- src/harness/external/chai.d.ts | 1 + src/harness/harnessLanguageService.ts | 3 + src/server/client.ts | 4 + src/server/editorServices.ts | 2 +- src/services/services.ts | 160 +++++- src/services/shims.ts | 10 + tests/cases/unittests/extensionAPI.ts | 763 +++++++++++++++++++++++++- 9 files changed, 950 insertions(+), 23 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9d9204c3dfbfb..3aa9b498888f6 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1251,6 +1251,7 @@ namespace ts { switch (ext.kind) { case ExtensionKind.SemanticLint: case ExtensionKind.SyntacticLint: + case ExtensionKind.LanguageService: if (typeof potentialExtension !== "function") { programDiagnostics.add(createCompilerDiagnostic( Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, @@ -1262,7 +1263,13 @@ namespace ts { )); return; } - (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension; + (ext as (SemanticLintExtension | SyntacticLintExtension | LanguageServiceExtension)).ctor = potentialExtension; + break; + default: + // Include a default case which just puts the extension unchecked onto the base extension + // This can allow language service extensions to query for custom extension kinds + (ext as any).__extension = potentialExtension; + break; } aggregate.push(ext as Extension); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0c2740ead64f7..2b6856cd798e6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2920,17 +2920,29 @@ namespace ts { new (typescript: typeof ts, checker: TypeChecker, args: any): LintWalker; } + export interface LanguageServiceHost {} // The members for these interfaces are provided in the services layer + export interface LanguageService {} + export interface LanguageServiceProvider {} + export interface DocumentRegistry {} + + export interface LanguageServiceProviderStatic { + new (typescript: typeof ts, host: LanguageServiceHost, service: LanguageService, registry: DocumentRegistry, args: any): LanguageServiceProvider; + } + export namespace ExtensionKind { export const SemanticLint: "semantic-lint" = "semantic-lint"; export type SemanticLint = "semantic-lint"; export const SyntacticLint: "syntactic-lint" = "syntactic-lint"; export type SyntacticLint = "syntactic-lint"; + export const LanguageService: "language-service" = "language-service"; + export type LanguageService = "language-service"; } - export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint; + export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint | ExtensionKind.LanguageService; export interface ExtensionCollectionMap { "syntactic-lint"?: SyntacticLintExtension[]; "semantic-lint"?: SemanticLintExtension[]; + "language-service"?: LanguageServiceExtension[]; [index: string]: Extension[] | undefined; } @@ -2950,7 +2962,12 @@ namespace ts { ctor: SemanticLintProviderStatic; } - export type Extension = SyntacticLintExtension | SemanticLintExtension; + // @kind(ExtensionKind.LanguageService) + export interface LanguageServiceExtension extends ExtensionBase { + ctor: LanguageServiceProviderStatic; + } + + export type Extension = SyntacticLintExtension | SemanticLintExtension | LanguageServiceExtension; export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; diff --git a/src/harness/external/chai.d.ts b/src/harness/external/chai.d.ts index 5e4e6e7d00010..ccd1de1bfb59f 100644 --- a/src/harness/external/chai.d.ts +++ b/src/harness/external/chai.d.ts @@ -175,5 +175,6 @@ declare module chai { function isOk(actual: any, message?: string): void; function isUndefined(value: any, message?: string): void; function isDefined(value: any, message?: string): void; + function deepEqual(actual: any, expected: any, message?: string): void; } } \ No newline at end of file diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 8567a9109de45..cf0083505e35c 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -366,6 +366,9 @@ namespace Harness.LanguageService { getCompilerOptionsDiagnostics(): ts.Diagnostic[] { return unwrapJSONCallResult(this.shim.getCompilerOptionsDiagnostics()); } + getProgramDiagnostics(): ts.Diagnostic[] { + return unwrapJSONCallResult(this.shim.getProgramDiagnostics()); + } getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } diff --git a/src/server/client.ts b/src/server/client.ts index 09cfa2ac739fc..b64048df34756 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -395,6 +395,10 @@ namespace ts.server { } getCompilerOptionsDiagnostics(): Diagnostic[] { + return this.getProgramDiagnostics(); + } + + getProgramDiagnostics(): Diagnostic[] { throw new Error("Not Implemented Yet."); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 9c0662e5534a5..fc88af2b4ab45 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1147,7 +1147,7 @@ namespace ts.server { info.setFormatOptions(this.getFormatCodeOptions()); this.filenameToScriptInfo[fileName] = info; if (!info.isOpen) { - info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); + info.fileWatcher = this.host.watchFile && this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); } } } diff --git a/src/services/services.ts b/src/services/services.ts index fd72fd40eee7c..8c29d5d8097b3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1079,6 +1079,8 @@ namespace ts { resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; directoryExists?(directoryName: string): boolean; getDirectories?(directoryName: string): string[]; + + loadExtension?(path: string): any; } // @@ -1091,10 +1093,13 @@ namespace ts { getSyntacticDiagnostics(fileName: string): Diagnostic[]; getSemanticDiagnostics(fileName: string): Diagnostic[]; - // TODO: Rename this to getProgramDiagnostics to better indicate that these are any - // diagnostics present for the program level, and not just 'options' diagnostics. + /** + * @deprecated Use getProgramDiagnostics instead. + */ getCompilerOptionsDiagnostics(): Diagnostic[]; + getProgramDiagnostics(): Diagnostic[]; + /** * @deprecated Use getEncodedSyntacticClassifications instead. */ @@ -1158,6 +1163,86 @@ namespace ts { dispose(): void; } + export interface LanguageServiceProvider { + // Overrides + + // A plugin can implement one of the override methods to replace the results that would + // be returned by the TypeScript language service. If a plugin returns a defined results + // (that is, is not undefined) then that result is used instead of invoking the + // corresponding TypeScript method. If multiple plugins are registered, they are + // consulted in the order they are returned from the host. The first defined result + // returned by a plugin is used and no other plugin overrides are consulted. + + getProgramDiagnostics?(): Diagnostic[]; + getSyntacticDiagnostics?(fileName: string): Diagnostic[]; + getSemanticDiagnostics?(fileName: string): Diagnostic[]; + getEncodedSyntacticClassifications?(fileName: string, span: TextSpan): Classifications; + getEncodedSemanticClassifications?(fileName: string, span: TextSpan): Classifications; + getCompletionsAtPosition?(fileName: string, position: number): CompletionInfo; + getCompletionEntryDetails?(fileName: string, position: number, entryName: string): CompletionEntryDetails; + getQuickInfoAtPosition?(fileName: string, position: number): QuickInfo; + getNameOrDottedNameSpan?(fileName: string, startPos: number, endPos: number): TextSpan; + getBreakpointStatementAtPosition?(fileName: string, position: number): TextSpan; + getSignatureHelpItems?(fileName: string, position: number): SignatureHelpItems; + getRenameInfo?(fileName: string, position: number): RenameInfo; + findRenameLocations?(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; + getDefinitionAtPosition?(fileName: string, position: number): DefinitionInfo[]; + getTypeDefinitionAtPosition?(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition?(fileName: string, position: number): ReferenceEntry[]; + findReferences?(fileName: string, position: number): ReferencedSymbol[]; + getDocumentHighlights?(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[]; + getNavigateToItems?(searchValue: string, maxResultCount: number): NavigateToItem[]; + getNavigationBarItems?(fileName: string): NavigationBarItem[]; + getOutliningSpans?(fileName: string): OutliningSpan[]; + getTodoComments?(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[]; + getBraceMatchingAtPosition?(fileName: string, position: number): TextSpan[]; + getIndentationAtPosition?(fileName: string, position: number, options: EditorOptions): number; + getFormattingEditsForRange?(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[]; + getFormattingEditsForDocument?(fileName: string, options: FormatCodeOptions): TextChange[]; + getFormattingEditsAfterKeystroke?(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[]; + getDocCommentTemplateAtPosition?(fileName: string, position: number): TextInsertion; + + // Filters + + // A plugin can implement one of the filter methods to augment, extend or modify a result + // prior to the host receiving it. The TypeScript language service is invoked and the + // result is passed to the plugin as the value of the previous parameter. If more than one + // plugin is registered, the plugins are consulted in the order they are returned from the + // host. The value passed in as previous is the result returned by the prior plugin. If a + // plugin returns undefined, the result passed in as previous is used and the undefined + // result is ignored. All plugins are consulted before the result is returned to the host. + // If a plugin overrides behavior of the method, no filter methods are consulted. + + getProgramDiagnosticsFilter?(previous: Diagnostic[]): Diagnostic[]; + getSyntacticDiagnosticsFilter?(fileName: string, previous: Diagnostic[]): Diagnostic[]; + getSemanticDiagnosticsFilter?(fileName: string, previous: Diagnostic[]): Diagnostic[]; + getEncodedSyntacticClassificationsFilter?(fileName: string, span: TextSpan, previous: Classifications): Classifications; + getEncodedSemanticClassificationsFilter?(fileName: string, span: TextSpan, previous: Classifications): Classifications; + getCompletionsAtPositionFilter?(fileName: string, position: number, previous: CompletionInfo): CompletionInfo; + getCompletionEntryDetailsFilter?(fileName: string, position: number, entryName: string, previous: CompletionEntryDetails): CompletionEntryDetails; + getQuickInfoAtPositionFilter?(fileName: string, position: number, previous: QuickInfo): QuickInfo; + getNameOrDottedNameSpanFilter?(fileName: string, startPos: number, endPos: number, previous: TextSpan): TextSpan; + getBreakpointStatementAtPositionFilter?(fileName: string, position: number, previous: TextSpan): TextSpan; + getSignatureHelpItemsFilter?(fileName: string, position: number, previous: SignatureHelpItems): SignatureHelpItems; + getRenameInfoFilter?(fileName: string, position: number, previous: RenameInfo): RenameInfo; + findRenameLocationsFilter?(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, previous: RenameLocation[]): RenameLocation[]; + getDefinitionAtPositionFilter?(fileName: string, position: number, previous: DefinitionInfo[]): DefinitionInfo[]; + getTypeDefinitionAtPositionFilter?(fileName: string, position: number, previous: DefinitionInfo[]): DefinitionInfo[]; + getReferencesAtPositionFilter?(fileName: string, position: number, previous: ReferenceEntry[]): ReferenceEntry[]; + findReferencesFilter?(fileName: string, position: number, previous: ReferencedSymbol[]): ReferencedSymbol[]; + getDocumentHighlightsFilter?(fileName: string, position: number, filesToSearch: string[], previous: DocumentHighlights[]): DocumentHighlights[]; + getNavigateToItemsFilter?(searchValue: string, maxResultCount: number, previous: NavigateToItem[]): NavigateToItem[]; + getNavigationBarItemsFilter?(fileName: string, previous: NavigationBarItem[]): NavigationBarItem[]; + getOutliningSpansFilter?(fileName: string, previous: OutliningSpan[]): OutliningSpan[]; + getTodoCommentsFilter?(fileName: string, descriptors: TodoCommentDescriptor[], previous: TodoComment[]): TodoComment[]; + getBraceMatchingAtPositionFilter?(fileName: string, position: number, previous: TextSpan[]): TextSpan[]; + getIndentationAtPositionFilter?(fileName: string, position: number, options: EditorOptions, previous: number): number; + getFormattingEditsForRangeFilter?(fileName: string, start: number, end: number, options: FormatCodeOptions, previous: TextChange[]): TextChange[]; + getFormattingEditsForDocumentFilter?(fileName: string, options: FormatCodeOptions, previous: TextChange[]): TextChange[]; + getFormattingEditsAfterKeystrokeFilter?(fileName: string, position: number, key: string, options: FormatCodeOptions, previous: TextChange[]): TextChange[]; + getDocCommentTemplateAtPositionFilter?(fileName: string, position: number, previous: TextInsertion): TextInsertion; + } + export interface Classifications { spans: number[]; endOfLineState: EndOfLineState; @@ -2914,6 +2999,69 @@ namespace ts { } export function createLanguageService(host: LanguageServiceHost, + documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService { + const baseService = createUnextendedLanguageService(host, documentRegistry); + const extensions = baseService.getProgram().getCompilerExtensions()["language-service"]; + const instantiatedExtensions = map(extensions, extension => new extension.ctor(ts, host, baseService, documentRegistry, extension.args)); + + function wrap(key: string): Function { + return (...args: any[]) => { + if (instantiatedExtensions && instantiatedExtensions.length) { + for (let i = 0; i < instantiatedExtensions.length; i++) { + const extension = instantiatedExtensions[i]; + if ((extension as any)[key]) { + return (extension as any)[key](...args); + } + } + let result: any = (baseService as any)[key](...args); + const filterKey = `${key}Filter`; + for (let i = 0; i < instantiatedExtensions.length; i++) { + const extension = instantiatedExtensions[i]; + if ((extension as any)[filterKey]) { + result = (extension as any)[filterKey](...args, result); + } + } + return result; + } + return (baseService as any)[key](...args); + }; + } + + function buildWrappedService(underlyingMembers: Map, wrappedMembers: string[]): LanguageService { + // Add wrapped members to map + forEach(wrappedMembers, member => { + underlyingMembers[member] = wrap(member); + }); + // Map getProgramDiagnostics to deprecated getCompilerOptionsDiagnostics + underlyingMembers["getCompilerOptionsDiagnostics"] = underlyingMembers["getProgramDiagnostics"]; + return underlyingMembers as LanguageService; + } + + return buildWrappedService({ + cleanupSemanticCache: () => baseService.cleanupSemanticCache(), + getSyntacticClassifications: (fileName: string, span: TextSpan) => baseService.getSyntacticClassifications(fileName, span), + getSemanticClassifications: (fileName: string, span: TextSpan) => baseService.getSemanticClassifications(fileName, span), + getOccurrencesAtPosition: (fileName: string, position: number) => baseService.getOccurrencesAtPosition(fileName, position), + isValidBraceCompletionAtPostion: (fileName: string, pos: number, openingBrace: number) => baseService.isValidBraceCompletionAtPostion(fileName, pos, openingBrace), + getEmitOutput: (fileName: string) => baseService.getEmitOutput(fileName), + getProgram: () => baseService.getProgram(), + getNonBoundSourceFile: (fileName: string) => baseService.getNonBoundSourceFile(fileName), + dispose: () => baseService.dispose(), + }, [ + "getSyntacticDiagnostics", "getSemanticDiagnostics", "getProgramDiagnostics", + "getEncodedSyntacticClassifications", "getEncodedSemanticClassifications", "getCompletionsAtPosition", + "getCompletionEntryDetails", "getQuickInfoAtPosition", "getNameOrDottedNameSpan", + "getBreakpointStatementAtPosition", "getSignatureHelpItems", "getRenameInfo", + "findRenameLocations", "getDefinitionAtPosition", "getTypeDefinitionAtPosition", + "getReferencesAtPosition", "findReferences", "getDocumentHighlights", + "getNavigateToItems", "getNavigationBarItems", "getOutliningSpans", + "getTodoComments", "getBraceMatchingAtPosition", "getIndentationAtPosition", + "getFormattingEditsForRange", "getFormattingEditsForDocument", "getFormattingEditsAfterKeystroke", + "getDocCommentTemplateAtPosition" + ]); + } + + export function createUnextendedLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService { const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); @@ -3020,6 +3168,9 @@ namespace ts { }, getDirectories: path => { return host.getDirectories ? host.getDirectories(path) : []; + }, + loadExtension: path => { + return host.loadExtension ? host.loadExtension(path) : undefined; } }; if (host.trace) { @@ -3197,7 +3348,7 @@ namespace ts { return concatenate(semanticDiagnostics, declarationDiagnostics); } - function getCompilerOptionsDiagnostics() { + function getProgramDiagnostics() { synchronizeHostData(); return program.getOptionsDiagnostics(cancellationToken).concat( program.getGlobalDiagnostics(cancellationToken)); @@ -8108,7 +8259,8 @@ namespace ts { cleanupSemanticCache, getSyntacticDiagnostics, getSemanticDiagnostics, - getCompilerOptionsDiagnostics, + getCompilerOptionsDiagnostics: getProgramDiagnostics, + getProgramDiagnostics, getSyntacticClassifications, getSemanticClassifications, getEncodedSyntacticClassifications, diff --git a/src/services/shims.ts b/src/services/shims.ts index 73c516ca19d65..9ffa37b36c9b0 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -119,6 +119,7 @@ namespace ts { getSyntacticDiagnostics(fileName: string): string; getSemanticDiagnostics(fileName: string): string; getCompilerOptionsDiagnostics(): string; + getProgramDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; getSemanticClassifications(fileName: string, start: number, length: number): string; @@ -678,6 +679,15 @@ namespace ts { }); } + public getProgramDiagnostics(): string { + return this.forwardJSONCall( + "getProgramDiagnostics()", + () => { + const diagnostics = this.languageService.getProgramDiagnostics(); + return this.realizeDiagnostics(diagnostics); + }); + } + /// QUICKINFO /** diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index b18168a4c724d..2583e855e0a29 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -20,10 +20,10 @@ namespace ts { } for (let i = 0; i < expectedDiagnosticCodes.length; i++) { - assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); + assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic: (expected) [${expectedDiagnosticCodes.toString()}] vs (actual) [${map(diagnostics, d => d.code).toString()}]. First diagnostic: ${prettyPrintDiagnostic(diagnostics[0])}`); } if (expectedDiagnosticCodes.length === 0 && diagnostics.length) { - throw new Error(`Unexpected diagnostic (${diagnostics.length - 1} more): ${prettyPrintDiagnostic(diagnostics[0])}`); + throw new Error(`Unexpected diagnostic (${map(diagnostics, d => d.code).toString()}): ${prettyPrintDiagnostic(diagnostics[0])}`); } assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); } @@ -43,10 +43,12 @@ namespace ts { let virtualFs: Map = {}; - const getCanonicalFileName = createGetCanonicalFileName(true); + const innerCanonicalName = createGetCanonicalFileName(true); + const getCanonicalFileName = (fileName: string) => toPath(fileName, "/", innerCanonicalName); function loadSetIntoFsAt(set: Map, prefix: string) { - forEachKey(set, key => void (virtualFs[getCanonicalFileName(combinePaths(prefix, key))] = set[key])); + // Load a fileset at the given location, but exclude the /lib/ dir from the added set + forEachKey(set, key => startsWith(key, "/lib/") ? void 0 : void (virtualFs[getCanonicalFileName(prefix + key)] = set[key])); } function loadSetIntoFs(set: Map) { @@ -95,7 +97,7 @@ namespace ts { (name: string) => { return this.loadExtension( this.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, {module: ts.ModuleKind.CommonJS}, this, true).resolvedModule.resolvedFileName + resolveModuleName(name, fullPath, {module: ModuleKind.CommonJS}, this, true).resolvedModule.resolvedFileName ) ); } @@ -107,6 +109,47 @@ namespace ts { } }; + function makeMockLSHost(files: string[], options: CompilerOptions): LanguageServiceHost { + files = filter(files, file => !endsWith(file, ".json")); + return { + getCompilationSettings: () => options, + getScriptFileNames: () => files, + getScriptVersion(fileName) { + return "1"; + }, + getScriptSnapshot(fileName): IScriptSnapshot { + const fileContents = virtualFs[getCanonicalFileName(fileName)]; + if (!fileContents) return; + return ScriptSnapshot.fromString(fileContents); + }, + getCurrentDirectory() { + return ""; + }, + getDefaultLibFileName() { + return "/lib/lib.d.ts"; + }, + loadExtension(path) { + const fullPath = getCanonicalFileName(path); + const m = {exports: {}}; + ((module, exports, require) => { eval(virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return this.loadExtension( + getCanonicalFileName( + resolveModuleName(name, fullPath, {module: ModuleKind.CommonJS}, mockHost, true).resolvedModule.resolvedFileName + ) + ); + } + ); + return m.exports; + }, + trace(s) { + console.log(s); + } + }; + }; + const extensionAPI: Map = { "package.json": `{ "name": "typescript-plugin-api", @@ -130,22 +173,51 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { constructor(protected ts: typeof tsi, protected checker: tsi.TypeChecker, protected args: any) {} abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void; } + +export abstract class LanguageServiceProvider implements tsi.LanguageServiceProvider { + private static __tsCompilerExtensionKind: tsi.ExtensionKind.LanguageService = "language-service"; + constructor(protected ts: typeof tsi, protected host: tsi.LanguageServiceHost, protected service: tsi.LanguageService, protected registry: tsi.DocumentRegistry, args: any) {} +} ` }; // Compile extension API once (generating .d.ts and .js) - function compile(fileset: Map, options: ts.CompilerOptions): Diagnostic[] { - loadSetIntoFs(virtualLib); - loadSetIntoFs(fileset); + function languageServiceCompile(typescriptFiles: string[], options: CompilerOptions, additionalVerifiers?: (service: LanguageService) => void): Diagnostic[] { + options.allowJs = true; + options.noEmit = true; + const service = createLanguageService(makeMockLSHost(getKeys(virtualFs), options)); + + if (additionalVerifiers) { + additionalVerifiers(service); + } + + const diagnostics = concatenate(concatenate( + service.getProgramDiagnostics(), + flatten(map(typescriptFiles, fileName => service.getSyntacticDiagnostics(getCanonicalFileName(fileName))))), + flatten(map(typescriptFiles, fileName => service.getSemanticDiagnostics(getCanonicalFileName(fileName))))); - const program = createProgram(filter(getKeys(fileset), name => name != "package.json"), options, mockHost); + return sortAndDeduplicateDiagnostics(diagnostics); + } + + type VirtualCompilationFunction = (files: string[], options: CompilerOptions, additionalVerifiers?: () => void) => Diagnostic[]; + + function programCompile(typescriptFiles: string[], options: CompilerOptions): Diagnostic[] { + const program = createProgram(typescriptFiles, options, mockHost); program.emit(); return ts.getPreEmitDiagnostics(program); } - function buildMap(map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean): Diagnostic[] { - const diagnostics = compile(map, compilerOptions ? compilerOptions : {module: ModuleKind.CommonJS, declaration: true}); + function compile(fileset: Map, options: ts.CompilerOptions, compileFunc: VirtualCompilationFunction, additionalVerifiers?: () => void): Diagnostic[] { + loadSetIntoFs(virtualLib); + loadSetIntoFs(fileset); + + const typescriptFiles = filter(getKeys(fileset), name => endsWith(name, ".ts")); + return compileFunc(typescriptFiles, options, additionalVerifiers); + } + + function buildMap(compileFunc: VirtualCompilationFunction, map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean, additionalVerifiers?: () => void): Diagnostic[] { + const diagnostics = compile(map, compilerOptions ? compilerOptions : {module: ModuleKind.CommonJS, declaration: true}, compileFunc, additionalVerifiers); if (shouldError && diagnostics && diagnostics.length) { for (let i = 0; i < diagnostics.length; i++) { console.log(prettyPrintDiagnostic(diagnostics[i])); @@ -156,7 +228,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { virtualFs = {}; return diagnostics; } - buildMap(extensionAPI, extensionAPI, {module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: {"typescript": ["/lib/typescript.d.ts"]}}, /*shouldError*/true); + buildMap(programCompile, extensionAPI, extensionAPI, {module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: {"typescript": ["/lib/typescript.d.ts"]}}, /*shouldError*/true); const extensions: Map> = { "test-syntactic-lint": { @@ -294,6 +366,417 @@ export class IsValueBar extends SemanticLintWalker { accept(); } } +` + }, + "test-language-service": { + "package.json": `{ + "name": "test-language-service", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {LanguageServiceProvider} from "typescript-plugin-api"; + +export default class extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnosticsFilter(previous) { + previous.push({ + file: undefined, + start: undefined, + length: undefined, + messageText: "Test language service plugin loaded!", + category: 2, + code: "test-plugin-loaded", + }); + return previous; + } +} +` + }, + "test-service-overrides": { + "package.json": `{ + "name": "test-service-overrides", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {LanguageServiceProvider} from "typescript-plugin-api"; +import * as ts from "typescript"; + +export default class extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnostics() { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Program diagnostics replaced!", + category: 2, + code: "program-diagnostics-replaced", + }]; + } + getSyntacticDiagnostics(fileName) { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Syntactic diagnostics replaced!", + category: 2, + code: "syntactic-diagnostics-replaced", + }]; + } + getSemanticDiagnostics(fileName) { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Semantic diagnostics replaced!", + category: 2, + code: "semantic-diagnostics-replaced", + }]; + } + getEncodedSyntacticClassifications(fileName, span) { + return { + spans: [span.start, span.length, this.ts.endsWith(fileName, "atotc.ts") ? this.ts.ClassificationType.text : this.ts.ClassificationType.comment], + endOfLineState: this.ts.EndOfLineState.None + }; + } + getEncodedSemanticClassifications(fileName, span) { + return { + spans: [span.start, span.length, this.ts.endsWith(fileName, "atotc.ts") ? this.ts.ClassificationType.moduleName : this.ts.ClassificationType.comment], + endOfLineState: this.ts.EndOfLineState.None + }; + } + getCompletionsAtPosition(fileName, position) { + return { + isMemberCompletion: false, + isNewIdentifierLocation: false, + entries: [{name: fileName, kind: 0, kindModifiers: 0, sortText: fileName}] + }; + } + getCompletionEntryDetails(fileName, position, entryName) { + return { + name: fileName, + kind: position.toString(), + kindModifiers: entryName, + displayParts: [], + documentation: [], + }; + } + getQuickInfoAtPosition(fileName, position) { + return {}; + } + getNameOrDottedNameSpan(fileName, startPos, endPos) { + return {}; + } + getBreakpointStatementAtPosition(fileName, position) { + return {}; + } + getSignatureHelpItems(fileName, position) { + return {}; + } + getRenameInfo(fileName, position) { + return {}; + } + findRenameLocations(fileName, position, findInStrings, findInComments) { + return {}; + } + getDefinitionAtPosition(fileName, position) { + return {}; + } + getTypeDefinitionAtPosition(fileName, position) { + return {}; + } + getReferencesAtPosition(fileName, position) { + return {}; + } + findReferences(fileName, position) { + return {}; + } + getDocumentHighlights(fileName, position, filesToSearch) { + return {}; + } + getNavigateToItems(searchValue, maxResultCount) { + return {}; + } + getNavigationBarItems(fileName) { + return {}; + } + getOutliningSpans(fileName) { + return {}; + } + getTodoComments(fileName, descriptors) { + return {}; + } + getBraceMatchingAtPosition(fileName, position) { + return {}; + } + getIndentationAtPosition(fileName, position, options) { + return {}; + } + getFormattingEditsForRange(fileName, start, end, options) { + return {}; + } + getFormattingEditsForDocument(fileName, options) { + return {}; + } + getFormattingEditsAfterKeystroke(fileName, position, key, options) { + return {}; + } + getDocCommentTemplateAtPosition(fileName, position) { + return {}; + } +} +` + }, + "test-service-filters": { + "package.json": `{ + "name": "test-service-filters", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {LanguageServiceProvider} from "typescript-plugin-api"; + +import * as ts from "typescript"; + +export default class extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnosticsFilter(previous) { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Program diagnostics replaced!", + category: 2, + code: "program-diagnostics-replaced", + }]; + } + getSyntacticDiagnosticsFilter(fileName, previous) { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Syntactic diagnostics replaced!", + category: 2, + code: "syntactic-diagnostics-replaced", + }]; + } + getSemanticDiagnosticsFilter(fileName, previous) { + return [{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Semantic diagnostics replaced!", + category: 2, + code: "semantic-diagnostics-replaced", + }]; + } + getEncodedSyntacticClassificationsFilter(fileName, span, previous) { + return { + spans: [span.start, span.length, this.ts.endsWith(fileName, "atotc.ts") ? this.ts.ClassificationType.text : this.ts.ClassificationType.comment], + endOfLineState: this.ts.EndOfLineState.None + }; + } + getEncodedSemanticClassificationsFilter(fileName, span, previous) { + return { + spans: [span.start, span.length, this.ts.endsWith(fileName, "atotc.ts") ? this.ts.ClassificationType.moduleName : this.ts.ClassificationType.comment], + endOfLineState: this.ts.EndOfLineState.None + }; + } + getCompletionsAtPositionFilter(fileName, position, previous) { + return { + isMemberCompletion: false, + isNewIdentifierLocation: false, + entries: [{name: fileName, kind: 0, kindModifiers: 0, sortText: fileName}] + }; + } + getCompletionEntryDetailsFilter(fileName, position, entryName, previous) { + return { + name: fileName, + kind: position.toString(), + kindModifiers: entryName, + displayParts: [], + documentation: [], + }; + } + getQuickInfoAtPositionFilter(fileName, position, previous) { + return {}; + } + getNameOrDottedNameSpanFilter(fileName, startPos, endPos, previous) { + return {}; + } + getBreakpointStatementAtPositionFilter(fileName, position, previous) { + return {}; + } + getSignatureHelpItemsFilter(fileName, position, previous) { + return {}; + } + getRenameInfoFilter(fileName, position, previous) { + return {}; + } + findRenameLocationsFilter(fileName, position, findInStrings, findInComments, previous) { + return {}; + } + getDefinitionAtPositionFilter(fileName, position, previous) { + return {}; + } + getTypeDefinitionAtPositionFilter(fileName, position, previous) { + return {}; + } + getReferencesAtPositionFilter(fileName, position, previous) { + return {}; + } + findReferencesFilter(fileName, position, previous) { + return {}; + } + getDocumentHighlightsFilter(fileName, position, filesToSearch, previous) { + return {}; + } + getNavigateToItemsFilter(searchValue, maxResultCount, previous) { + return {}; + } + getNavigationBarItemsFilter(fileName, previous) { + return {}; + } + getOutliningSpansFilter(fileName, previous) { + return {}; + } + getTodoCommentsFilter(fileName, descriptors, previous) { + return {}; + } + getBraceMatchingAtPositionFilter(fileName, position, previous) { + return {}; + } + getIndentationAtPositionFilter(fileName, position, options, previous) { + return {}; + } + getFormattingEditsForRangeFilter(fileName, start, end, options, previous) { + return {}; + } + getFormattingEditsForDocumentFilter(fileName, options, previous) { + return {}; + } + getFormattingEditsAfterKeystrokeFilter(fileName, position, key, options, previous) { + return {}; + } + getDocCommentTemplateAtPositionFilter(fileName, position, previous) { + return {}; + } +} +` + }, + "test-service-passthru": { + "package.json": `{ + "name": "test-service-passthru", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {LanguageServiceProvider} from "typescript-plugin-api"; + +export default class extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnosticsFilter(previous) { + return previous; + } + getSyntacticDiagnosticsFilter(fileName, previous) { + return previous; + } + getSemanticDiagnosticsFilter(fileName, previous) { + return previous; + } +} +` + }, + "test-service-chain": { + "package.json": `{ + "name": "test-service-chain", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {LanguageServiceProvider} from "typescript-plugin-api"; + +export class AddsDiagnostics extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnosticsFilter(previous) { + return previous.concat([{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Program diagnostics amended!", + category: 2, + code: "program-diagnostics-amended", + }]); + } + getSyntacticDiagnosticsFilter(fileName, previous) { + return previous.concat([{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Syntactic diagnostics amended!", + category: 2, + code: "syntactic-diagnostics-amended", + }]); + } + getSemanticDiagnosticsFilter(fileName, previous) { + return previous.concat([{ + file: undefined, + start: undefined, + length: undefined, + messageText: "Semantic diagnostics amended!", + category: 2, + code: "semantic-diagnostics-amended", + }]); + } +} + +// Since this is exported second, it should be second in the chain. Probably. +// This is honestly dependent on js host key ordering +export class MutatesAddedDiagnostics extends LanguageServiceProvider { + constructor(ts, host, service, registry, args) { super(ts, host, service, registry, args); } + getProgramDiagnosticsFilter(previous) { + return previous.map(prev => prev.code === "program-diagnostics-amended" ? { + file: undefined, + start: undefined, + length: undefined, + messageText: "Program diagnostics mutated!", + category: 2, + code: "program-diagnostics-mutated", + } : prev); + } + getSyntacticDiagnosticsFilter(fileName, previous) { + return previous.map(prev => prev.code === "syntactic-diagnostics-amended" ? { + file: undefined, + start: undefined, + length: undefined, + messageText: "Syntactic diagnostics mutated!", + category: 2, + code: "syntactic-diagnostics-mutated", + } : prev); + } + getSemanticDiagnosticsFilter(fileName, previous) { + return previous.map(prev => prev.code === "semantic-diagnostics-amended" ? { + file: undefined, + start: undefined, + length: undefined, + messageText: "Semantic diagnostics mutated!", + category: 2, + code: "semantic-diagnostics-mutated", + } : prev); + } +} ` } }; @@ -301,15 +784,15 @@ export class IsValueBar extends SemanticLintWalker { // Compile each extension once with the extension API in its node_modules folder (also generating .d.ts and .js) forEachKey(extensions, extName => { loadSetIntoFsAt(extensionAPI, "/node_modules/typescript-plugin-api"); - buildMap(extensions[extName], extensions[extName], {module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: {"typescript": ["lib/typescript.d.ts"]}}, /*shouldError*/true); + buildMap(programCompile, extensions[extName], extensions[extName], {module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: {"typescript": ["lib/typescript.d.ts"]}}, /*shouldError*/true); }); /** * Setup a new test, where all extensions specified in the options hash are available in a node_modules folder, alongside the extension API */ - function test(sources: Map, options: ExtensionTestOptions) { + function test(sources: Map, options: ExtensionTestOptions, compileFunc: VirtualCompilationFunction = programCompile, additionalVerifiers?: (...args: any[]) => void) { forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/${ext}`)); - const diagnostics = buildMap(sources, sources, options.compilerOptions); + const diagnostics = buildMap(compileFunc, sources, sources, options.compilerOptions, /*shouldError*/false, additionalVerifiers); checkDiagnostics(diagnostics, options.expectedDiagnostics); } @@ -451,5 +934,255 @@ export class IsValueBar extends SemanticLintWalker { } }); }); + + it("can load language service rules and add program diagnostics", () => { + test({ + "main.ts": "console.log('Did you know? The empty string is falsey.')" + }, { + availableExtensions: ["test-language-service"], + expectedDiagnostics: ["test-plugin-loaded"], + compilerOptions: { + extensions: ["test-language-service"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + }); + + const atotcFile = getCanonicalFileName("atotc.ts"); + const atotcText = ` +It was the best of times, it was the worst of times, +it was the age of wisdom, it was the age of foolishness, +it was the epoch of belief, it was the epoch of incredulity, +it was the season of Light, it was the season of Darkness, +it was the spring of hope, it was the winter of despair, +we had everything before us, we had nothing before us, +we were all going direct to Heaven, we were all going direct +the other way--in short, the period was so far like the present +period, that some of its noisiest authorities insisted on its +being received, for good or for evil, in the superlative degree +of comparison only. +`; + const testDummyLS = (service: LanguageService) => { + assert.deepEqual(service.getEncodedSyntacticClassifications(atotcFile, {start: 0, length: 24}), + {spans: [0, 24, ClassificationType.text], endOfLineState: EndOfLineState.None}, + "Syntactic classifications did not match!"); + assert.deepEqual(service.getEncodedSemanticClassifications(atotcFile, {start: 24, length: 42}), + {spans: [24, 42, ClassificationType.moduleName], endOfLineState: EndOfLineState.None}, + "Semantic classifications did not match!"); + assert.deepEqual(service.getCompletionsAtPosition(atotcFile, 0), { + isMemberCompletion: false, + isNewIdentifierLocation: false, + entries: [{name: atotcFile, kind: 0, kindModifiers: 0, sortText: atotcFile}] + }, "Completions did not match!"); + assert.deepEqual(service.getCompletionEntryDetails(atotcFile, 0, "first"), { + name: atotcFile, + kind: (0).toString(), + kindModifiers: "first", + displayParts: [], + documentation: [], + }, "Completion details did not match!"); + assert.deepEqual(service.getQuickInfoAtPosition(atotcFile, 0), {}, "Quick info did not match!"); + assert.deepEqual(service.getNameOrDottedNameSpan(atotcFile, 0, 0), {}, "Name or dotted span info did not match!"); + assert.deepEqual(service.getBreakpointStatementAtPosition(atotcFile, 0), {}, "Breakpoint statement info did not match!"); + assert.deepEqual(service.getSignatureHelpItems(atotcFile, 0), {}, "Signature help items did not match!"); + assert.deepEqual(service.getRenameInfo(atotcFile, 0), {}, "Rename info did not match!"); + assert.deepEqual(service.findRenameLocations(atotcFile, 0, false, false), {}, "Rename locations did not match!"); + assert.deepEqual(service.getDefinitionAtPosition(atotcFile, 0), {}, "Definition info did not match!"); + assert.deepEqual(service.getTypeDefinitionAtPosition(atotcFile, 0), {}, "Type definition info did not match!"); + assert.deepEqual(service.getReferencesAtPosition(atotcFile, 0), {}, "References did not match!"); + assert.deepEqual(service.findReferences(atotcFile, 0), {}, "Find references did not match!"); + assert.deepEqual(service.getDocumentHighlights(atotcFile, 0, []), {}, "Document highlights did not match!"); + assert.deepEqual(service.getNavigateToItems(atotcFile), {}, "NavTo items did not match!"); + assert.deepEqual(service.getNavigationBarItems(atotcFile), {}, "NavBar items did not match!"); + assert.deepEqual(service.getOutliningSpans(atotcFile), {}, "Outlining spans did not match!"); + assert.deepEqual(service.getTodoComments(atotcFile, []), {}, "Todo comments did not match!"); + assert.deepEqual(service.getBraceMatchingAtPosition(atotcFile, 0), {}, "Brace positions did not match!"); + assert.deepEqual(service.getIndentationAtPosition(atotcFile, 0, {} as EditorOptions), {}, "Indentation positions did not match!"); + assert.deepEqual(service.getFormattingEditsForRange(atotcFile, 0, 1, {} as FormatCodeOptions), {}, "Range edits did not match!"); + assert.deepEqual(service.getFormattingEditsForDocument(atotcFile, {} as FormatCodeOptions), {}, "Document edits did not match!"); + assert.deepEqual(service.getFormattingEditsAfterKeystroke(atotcFile, 0, "q", {} as FormatCodeOptions), {}, "Keystroke edits did not match!"); + assert.deepEqual(service.getDocCommentTemplateAtPosition(atotcFile, 0), {}, "Doc comment template did not match!"); + }; + + it("can override all language service functionality", () => { + test({ + [atotcFile]: atotcText + }, { + availableExtensions: ["test-service-overrides"], + expectedDiagnostics: ["program-diagnostics-replaced", "semantic-diagnostics-replaced", "syntactic-diagnostics-replaced"], + compilerOptions: { + extensions: ["test-service-overrides"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile, testDummyLS); + }); + + it("can filter all language service functionality", () => { + test({ + [atotcFile]: atotcText + }, { + availableExtensions: ["test-service-filters"], + expectedDiagnostics: ["program-diagnostics-replaced", "semantic-diagnostics-replaced", "syntactic-diagnostics-replaced"], + compilerOptions: { + extensions: ["test-service-filters"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile, testDummyLS); + }); + + it("can filter without altering functionality", () => { + test({ + ["main.ts"]: "console.log('Hello, test.') -" + }, { + availableExtensions: ["test-service-passthru"], + expectedDiagnostics: [2362, 1109], + compilerOptions: { + extensions: ["test-service-passthru"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + }); + + it("can filter and mutate while chaining plugins", () => { + test({ + ["main.ts"]: "console.log('Hello, test.') -" + }, { + availableExtensions: ["test-service-chain"], + expectedDiagnostics: ["program-diagnostics-mutated", "semantic-diagnostics-mutated", "syntactic-diagnostics-mutated", 2362, 1109], + compilerOptions: { + extensions: ["test-service-chain"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + }); + + it("can run all lint plugins in the language service", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;} + const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint", "test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-extension-arguments"], + expectedDiagnostics: ["test-extension-arguments", "test-extension-arguments"], + compilerOptions: { + extensions: { + "test-extension-arguments": ["a", "b"] + }, + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {b;} + interface Bar {a;} + const f: "foo" = "foo"; + let b: "bar" = "bar";`, + }, { + availableExtensions: ["test-multi-extension"], + expectedDiagnostics: ["test-multi-extension[IsNamedFoo]", "test-multi-extension[IsNamedBar]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueBar]", "test-multi-extension[IsValueBar]"], + compilerOptions: { + extensions: ["test-multi-extension"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: [], + expectedDiagnostics: [6151, 6151], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + }); }); } From a03e4650d583aa8a079c876437efc17b02041030 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 20 Jun 2016 18:31:12 -0700 Subject: [PATCH 04/49] Fix comments - make behavior align with comments --- src/services/services.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 8c29d5d8097b3..bd9ac34c271a6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1170,7 +1170,7 @@ namespace ts { // be returned by the TypeScript language service. If a plugin returns a defined results // (that is, is not undefined) then that result is used instead of invoking the // corresponding TypeScript method. If multiple plugins are registered, they are - // consulted in the order they are returned from the host. The first defined result + // consulted in the order they are returned from the program. The first defined result // returned by a plugin is used and no other plugin overrides are consulted. getProgramDiagnostics?(): Diagnostic[]; @@ -1208,7 +1208,7 @@ namespace ts { // prior to the host receiving it. The TypeScript language service is invoked and the // result is passed to the plugin as the value of the previous parameter. If more than one // plugin is registered, the plugins are consulted in the order they are returned from the - // host. The value passed in as previous is the result returned by the prior plugin. If a + // program. The value passed in as previous is the result returned by the prior plugin. If a // plugin returns undefined, the result passed in as previous is used and the undefined // result is ignored. All plugins are consulted before the result is returned to the host. // If a plugin overrides behavior of the method, no filter methods are consulted. @@ -3003,28 +3003,35 @@ namespace ts { const baseService = createUnextendedLanguageService(host, documentRegistry); const extensions = baseService.getProgram().getCompilerExtensions()["language-service"]; const instantiatedExtensions = map(extensions, extension => new extension.ctor(ts, host, baseService, documentRegistry, extension.args)); + const extensionCount = instantiatedExtensions && instantiatedExtensions.length; function wrap(key: string): Function { - return (...args: any[]) => { - if (instantiatedExtensions && instantiatedExtensions.length) { - for (let i = 0; i < instantiatedExtensions.length; i++) { + if (extensionCount) { + return (...args: any[]) => { + for (let i = 0; i < extensionCount; i++) { const extension = instantiatedExtensions[i]; if ((extension as any)[key]) { - return (extension as any)[key](...args); + const temp = (extension as any)[key](...args); + if (temp !== undefined) { + return temp; + } } } let result: any = (baseService as any)[key](...args); const filterKey = `${key}Filter`; - for (let i = 0; i < instantiatedExtensions.length; i++) { + for (let i = 0; i < extensionCount; i++) { const extension = instantiatedExtensions[i]; if ((extension as any)[filterKey]) { - result = (extension as any)[filterKey](...args, result); + const temp = (extension as any)[filterKey](...args, result); + if (temp !== undefined) { + result = temp; + } } } return result; - } - return (baseService as any)[key](...args); - }; + }; + } + return (baseService as any)[key]; } function buildWrappedService(underlyingMembers: Map, wrappedMembers: string[]): LanguageService { From 4eee39d147f306ecce335bdca7a069cb4530e791 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 22 Jun 2016 10:54:34 -0700 Subject: [PATCH 05/49] accept -> stop, add more overloads to error --- src/compiler/program.ts | 24 +++++++++++++++++------- src/compiler/types.ts | 12 ++++++++---- src/compiler/utilities.ts | 10 +++++++--- tests/cases/unittests/extensionAPI.ts | 25 +++++++++---------------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9d9204c3dfbfb..4b056e32d98bf 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1598,13 +1598,12 @@ namespace ts { function visitNode(node: Node) { let oneAccepted = false; const oldParent = parent; - const needsReset: boolean[] = new Array(initializedLints.length); + const needsReset: Map = {}; for (let i = 0; i < initializedLints.length; i++) { if (initializedLints[i].accepted) { activeLint = initializedLints[i]; - activeLint.accepted = false; node.parent = parent; - activeLint.walker.visit(node, accept, error); + activeLint.walker.visit(node, stop, error); if (activeLint.accepted) { oneAccepted = true; } @@ -1626,12 +1625,23 @@ namespace ts { } } - function accept() { - activeLint.accepted = true; + function stop() { + activeLint.accepted = false; } - function error(err: string, node: Node) { - diagnostics.push(createExtensionDiagnosticForNode(node, activeLint.name, err)); + function error(err: string): void; + function error(err: string, node: Node): void; + function error(err: string, start: number, length: number): void; + function error(err: string, nodeOrStart?: Node | number, length?: number): void { + if (typeof nodeOrStart === "undefined") { + diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile)); + } + else if (typeof nodeOrStart === "number") { + diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile, nodeOrStart, length)); + } + else { + diagnostics.push(createExtensionDiagnosticForNode(nodeOrStart, activeLint.name, err)); + } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0c2740ead64f7..39429c86f7468 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2901,15 +2901,19 @@ namespace ts { failedLookupLocations: string[]; } - export type LintErrorMethod = (err: string, span: Node) => void; - export type LintAcceptMethod = () => void; + export type LintErrorMethod = { + (err: string): void; + (err: string, span: Node): void; + (err: string, start: number, length: number): void; + }; + export type LintStopMethod = () => void; /* - * Walkers call accept to decend into the node's children + * Walkers call stop to halt recursion into the node's children * Walkers call error to add errors to the output. */ export interface LintWalker { - visit(node: Node, accept: LintAcceptMethod, error: LintErrorMethod): void; + visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void; } export interface SyntacticLintProviderStatic { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 303d2d61f16c7..ebc2b75f5124f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -456,12 +456,16 @@ namespace ts { export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string): Diagnostic { const sourceFile = getSourceFileOfNode(node); const span = getErrorSpanForNode(sourceFile, node); + return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length); + } + + export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number): Diagnostic { return { - file: sourceFile, + file: file, messageText: message, code: extension, - start: span.start, - length: span.length, + start: start, + length: length, category: DiagnosticCategory.Extension }; } diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index b18168a4c724d..59c6581025d6b 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -122,13 +122,13 @@ import * as tsi from "typescript"; export abstract class SyntacticLintWalker implements tsi.LintWalker { private static __tsCompilerExtensionKind: tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; constructor(protected ts: typeof tsi, protected args: any) {} - abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void; + abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; } export abstract class SemanticLintWalker implements tsi.LintWalker { private static __tsCompilerExtensionKind: tsi.ExtensionKind.SemanticLint = "semantic-lint"; constructor(protected ts: typeof tsi, protected checker: tsi.TypeChecker, protected args: any) {} - abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void; + abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; } ` }; @@ -172,13 +172,12 @@ import {SyntacticLintWalker} from "typescript-plugin-api"; export default class IsNamedFoo extends SyntacticLintWalker { constructor(ts, args) { super(ts, args); } - visit(node, accept, error) { + visit(node, stop, error) { if (node.kind === this.ts.SyntaxKind.Identifier) { if (node.text.toLowerCase() === "foo") { error("Identifier 'foo' is forbidden.", node); } } - accept(); } } `, @@ -196,14 +195,13 @@ import {SemanticLintWalker} from "typescript-plugin-api"; export default class IsValueFoo extends SemanticLintWalker { constructor(ts, checker, args) { super(ts, checker, args); } - visit(node, accept, error) { + visit(node, stop, error) { const type = this.checker.getTypeAtLocation(node); if (type.flags & this.ts.TypeFlags.StringLiteral) { if (node.text === "foo") { error("String literal type 'foo' is forbidden.", node); } } - accept(); } } `, @@ -221,7 +219,7 @@ import {SyntacticLintWalker} from "typescript-plugin-api"; export default class IsNamedX extends SyntacticLintWalker { constructor(ts, args) { super(ts, args); } - visit(node, accept, error) { + visit(node, stop, error) { if (node.kind === this.ts.SyntaxKind.Identifier) { for (let i = 0; i Date: Mon, 27 Jun 2016 15:32:13 -0700 Subject: [PATCH 06/49] address @rbuckton and @mhegazy PR comments --- src/compiler/checker.ts | 8 +--- src/compiler/program.ts | 97 ++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 49d8a98e49b8d..565ae0ca1a05b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17249,19 +17249,15 @@ namespace ts { return getTypeOfSymbol(symbol); } - if (isDeclarationName(node)) { + if (isDeclarationName(node) || node.kind === SyntaxKind.SourceFile) { const symbol = getSymbolAtLocation(node); - return symbol && getTypeOfSymbol(symbol); + return symbol && getTypeOfSymbol(symbol) || unknownType; } if (isBindingPattern(node)) { return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true); } - if (node.kind === SyntaxKind.SourceFile) { - return unknownType; - } - if (isInRightSideOfImportOrExportAssignment(node)) { const symbol = getSymbolAtLocation(node); const declaredType = symbol && getDeclaredTypeOfSymbol(symbol); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 4b056e32d98bf..67745d1ae6c6a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -129,58 +129,25 @@ namespace ts { skipTsx: boolean; } - function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { - let jsonContent: { typings?: string, types?: string }; - try { - const jsonText = state.host.readFile(packageJsonPath); - jsonContent = jsonText ? <{ typings?: string, types?: string }>JSON.parse(jsonText) : {}; - } - catch (e) { - // gracefully handle if readFile fails or returns not JSON - jsonContent = {}; - } - - let typesFile: string; - let fieldName: string; - // first try to read content of 'typings' section (backward compatibility) - if (jsonContent.typings) { - if (typeof jsonContent.typings === "string") { - fieldName = "typings"; - typesFile = jsonContent.typings; + function tryFetchField(content: any, section: string, state: ModuleResolutionState): string { + const field = content[section]; + if (field) { + if (typeof field === "string") { + return field; } else { if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "typings", typeof jsonContent.typings); + trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, section, typeof field); } } } - // then read 'types' - if (!typesFile && jsonContent.types) { - if (typeof jsonContent.types === "string") { - fieldName = "types"; - typesFile = jsonContent.types; - } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "types", typeof jsonContent.types); - } - } - } - if (typesFile) { - const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile)); - if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath); - } - return typesFilePath; - } - return undefined; } - function tryReadMainSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { - let jsonContent: { main?: string }; + function tryReadPathFromConfigSection(packageJsonPath: string, sections: string | string[], baseDirectory: string, state: ModuleResolutionState): string { + let jsonContent: any; try { const jsonText = state.host.readFile(packageJsonPath); - jsonContent = jsonText ? <{ main?: string }>JSON.parse(jsonText) : {}; + jsonContent = jsonText ? JSON.parse(jsonText) : {}; } catch (e) { // gracefully handle if readFile fails or returns not JSON @@ -188,27 +155,39 @@ namespace ts { } let mainFile: string; + let utilizedSection: string; - if (jsonContent.main) { - if (typeof jsonContent.main === "string") { - mainFile = jsonContent.main; - } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "main", typeof jsonContent.main); + if (typeof sections === "string") { + mainFile = tryFetchField(jsonContent, sections, state); + utilizedSection = sections; + } + else { + for (const section of sections) { + mainFile = tryFetchField(jsonContent, section, state); + if (typeof mainFile === "string") { + utilizedSection = section; + break; } } } if (mainFile) { const mainFilePath = normalizePath(combinePaths(baseDirectory, mainFile)); if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, "main", mainFile, mainFilePath); + trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, utilizedSection, mainFile, mainFilePath); } return mainFilePath; } return undefined; } + function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { + return tryReadPathFromConfigSection(packageJsonPath, ["typings", "types"], baseDirectory, state); + } + + function tryReadMainSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { + return tryReadPathFromConfigSection(packageJsonPath, "main", baseDirectory, state); + } + const typeReferenceExtensions = [".d.ts"]; function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) { @@ -794,7 +773,7 @@ namespace ts { // first: try to load module as-is loadModuleFromNodeModulesFolder(moduleName, directory, failedLookupLocations, state, loadJS) || // second: try to load module from the scope '@types' - loadModuleFromNodeModulesFolder(combinePaths("@types", moduleName), directory, failedLookupLocations, state); + !loadJS && loadModuleFromNodeModulesFolder(combinePaths("@types", moduleName), directory, failedLookupLocations, state); if (result) { return result; } @@ -969,14 +948,9 @@ namespace ts { return getDirectoryPath(normalizePath(sys.getExecutingFilePath())); } - function loadExtension(name: string): any { - if (sys.loadExtension) { - return sys.loadExtension(name); - } - } - const newLine = getNewLineCharacter(options); const realpath = sys.realpath && ((path: string) => sys.realpath(path)); + const loadExtension = sys.loadExtension && ((name: string) => sys.loadExtension(name)); return { getSourceFile, @@ -1209,7 +1183,7 @@ namespace ts { function collectCompilerExtensions(): ExtensionCollectionMap { const extOptions = options.extensions; const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); - return groupBy(flatten(map(filter(map(extensionNames, name => { + const extensionLoadResults = map(extensionNames, name => { let result: any; let error: any; if (host.loadExtension) { @@ -1235,7 +1209,9 @@ namespace ts { ${error.stack}` : error)); } return {name, result, error}; - }), res => !res.error), res => { + }); + const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); + const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { if (res.result) { return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: any, key: string) => { if (!potentialExtension) { @@ -1272,7 +1248,8 @@ namespace ts { else { return []; } - })), elem => elem.kind) || {}; + }); + return groupBy(flatten(preparedExtensionObjects), elem => elem.kind) || {}; } function getCommonSourceDirectory() { From b874ad9ee03b2d6df28c827d95176962f3452842 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 27 Jun 2016 16:04:58 -0700 Subject: [PATCH 07/49] Use friendlier field name, pass options in property bag --- src/compiler/program.ts | 16 +++++----- src/compiler/types.ts | 15 +++++++--- tests/cases/unittests/extensionAPI.ts | 42 ++++++++++++++++++++------- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 67745d1ae6c6a..cffc8eb2d083a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1213,16 +1213,16 @@ namespace ts { const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { if (res.result) { - return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: any, key: string) => { + return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: BaseProviderStatic, key: string) => { if (!potentialExtension) { return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) } - const annotatedKind = potentialExtension.__tsCompilerExtensionKind; + const annotatedKind = potentialExtension["extension-kind"]; if (typeof annotatedKind === "string") { const ext: ExtensionBase = { name: key !== "default" ? `${res.name}[${key}]` : res.name, args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], - kind: annotatedKind as ExtensionKind + kind: annotatedKind }; switch (ext.kind) { case ExtensionKind.SemanticLint: @@ -1238,7 +1238,7 @@ namespace ts { )); return; } - (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension; + (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic); } aggregate.push(ext as Extension); } @@ -1561,10 +1561,10 @@ namespace ts { let parent: Node | undefined = undefined; for (let i = 0; i < lints.length; i++) { if (kind === ExtensionKind.SemanticLint) { - initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)(ts, getTypeChecker(), lints[i].args), accepted: true}; + initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ts, checker: getTypeChecker(), args: lints[i].args, host, program}), accepted: true}; } else if (kind === ExtensionKind.SyntacticLint) { - initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)(ts, lints[i].args), accepted: true}; + initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ts, args: lints[i].args, host, program}), accepted: true}; } } @@ -1623,7 +1623,7 @@ namespace ts { } function getSyntacticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { - if (!(sourceFile.isDeclarationFile || sourceFile.externalModuleIndicator)) { + if (!sourceFile.isDeclarationFile) { const lintDiagnostics = performLintPassOnFile(sourceFile, ExtensionKind.SyntacticLint); if (lintDiagnostics && lintDiagnostics.length) { return sourceFile.parseDiagnostics.concat(lintDiagnostics); @@ -1669,7 +1669,7 @@ namespace ts { typeChecker.getDiagnostics(sourceFile, cancellationToken); const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName); const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName); - const lintDiagnostics = (!(sourceFile.isDeclarationFile || sourceFile.externalModuleIndicator)) ? (performLintPassOnFile(sourceFile, ExtensionKind.SemanticLint) || []) : []; + const lintDiagnostics = (!sourceFile.isDeclarationFile) ? (performLintPassOnFile(sourceFile, ExtensionKind.SemanticLint) || []) : []; return bindDiagnostics.concat(checkDiagnostics).concat(fileProcessingDiagnosticsInFile).concat(programDiagnosticsInFile).concat(lintDiagnostics); }); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 39429c86f7468..30eb3389b0f06 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2916,12 +2916,19 @@ namespace ts { visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void; } - export interface SyntacticLintProviderStatic { - new (typescript: typeof ts, args: any): LintWalker; + export interface BaseProviderStatic { + ["extension-kind"]: ExtensionKind; + new (state: {ts: typeof ts, args: any}): any; } - export interface SemanticLintProviderStatic { - new (typescript: typeof ts, checker: TypeChecker, args: any): LintWalker; + export interface SyntacticLintProviderStatic extends BaseProviderStatic { + ["extension-kind"]: ExtensionKind.SyntacticLint; + new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program}): LintWalker; + } + + export interface SemanticLintProviderStatic extends BaseProviderStatic { + ["extension-kind"]: ExtensionKind.SemanticLint; + new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program, checker: TypeChecker}): LintWalker; } export namespace ExtensionKind { diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 59c6581025d6b..6c91756e4ef1d 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -120,14 +120,34 @@ namespace ts { import * as tsi from "typescript"; export abstract class SyntacticLintWalker implements tsi.LintWalker { - private static __tsCompilerExtensionKind: tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; - constructor(protected ts: typeof tsi, protected args: any) {} + static "extension-kind": tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; + protected ts: typeof tsi; + protected args: any; + protected host: tsi.CompilerHost; + protected program: tsi.Program; + constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program}) { + this.ts = state.ts; + this.args = state.args; + this.host = state.host; + this.program = state.program; + } abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; } export abstract class SemanticLintWalker implements tsi.LintWalker { - private static __tsCompilerExtensionKind: tsi.ExtensionKind.SemanticLint = "semantic-lint"; - constructor(protected ts: typeof tsi, protected checker: tsi.TypeChecker, protected args: any) {} + static "extension-kind": tsi.ExtensionKind.SemanticLint = "semantic-lint"; + protected ts: typeof tsi; + protected args: any; + protected host: tsi.CompilerHost; + protected program: tsi.Program; + protected checker: tsi.TypeChecker; + constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program, checker: tsi.TypeChecker}) { + this.ts = state.ts; + this.args = state.args; + this.host = state.host; + this.program = state.program; + this.checker = state.checker; + } abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; } ` @@ -171,7 +191,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { import {SyntacticLintWalker} from "typescript-plugin-api"; export default class IsNamedFoo extends SyntacticLintWalker { - constructor(ts, args) { super(ts, args); } + constructor(state) { super(state); } visit(node, stop, error) { if (node.kind === this.ts.SyntaxKind.Identifier) { if (node.text.toLowerCase() === "foo") { @@ -194,7 +214,7 @@ export default class IsNamedFoo extends SyntacticLintWalker { import {SemanticLintWalker} from "typescript-plugin-api"; export default class IsValueFoo extends SemanticLintWalker { - constructor(ts, checker, args) { super(ts, checker, args); } + constructor(state) { super(state); } visit(node, stop, error) { const type = this.checker.getTypeAtLocation(node); if (type.flags & this.ts.TypeFlags.StringLiteral) { @@ -218,7 +238,7 @@ export default class IsValueFoo extends SemanticLintWalker { import {SyntacticLintWalker} from "typescript-plugin-api"; export default class IsNamedX extends SyntacticLintWalker { - constructor(ts, args) { super(ts, args); } + constructor(state) { super(state); } visit(node, stop, error) { if (node.kind === this.ts.SyntaxKind.Identifier) { for (let i = 0; i Date: Mon, 27 Jun 2016 16:31:37 -0700 Subject: [PATCH 08/49] Add readonly modifier --- src/compiler/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 30eb3389b0f06..b62f8f218c7d8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2917,17 +2917,17 @@ namespace ts { } export interface BaseProviderStatic { - ["extension-kind"]: ExtensionKind; + readonly ["extension-kind"]: ExtensionKind; new (state: {ts: typeof ts, args: any}): any; } export interface SyntacticLintProviderStatic extends BaseProviderStatic { - ["extension-kind"]: ExtensionKind.SyntacticLint; + readonly ["extension-kind"]: ExtensionKind.SyntacticLint; new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program}): LintWalker; } export interface SemanticLintProviderStatic extends BaseProviderStatic { - ["extension-kind"]: ExtensionKind.SemanticLint; + readonly ["extension-kind"]: ExtensionKind.SemanticLint; new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program, checker: TypeChecker}): LintWalker; } From 0f9a81627e4f601e02f0f7acabeca0c951ebda5a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 27 Jun 2016 16:37:30 -0700 Subject: [PATCH 09/49] Fix new lints --- Gulpfile.ts | 1 + src/compiler/program.ts | 6 +++--- tests/cases/unittests/extensionAPI.ts | 10 +++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 74113b4b0c70c..32df9fc54b477 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -158,6 +158,7 @@ const harnessSources = harnessCoreSources.concat([ "convertTypingOptionsFromJson.ts", "tsserverProjectSystem.ts", "matchFiles.ts", + "extensionAPI.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/src/compiler/program.ts b/src/compiler/program.ts index bea9f1915e8ce..7e0bd24fe9b0e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1208,7 +1208,7 @@ namespace ts { Stack trace: ${error.stack}` : error)); } - return {name, result, error}; + return { name, result, error }; }); const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { @@ -1561,10 +1561,10 @@ namespace ts { let parent: Node | undefined = undefined; for (let i = 0; i < lints.length; i++) { if (kind === ExtensionKind.SemanticLint) { - initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ts, checker: getTypeChecker(), args: lints[i].args, host, program}), accepted: true}; + initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ ts, checker: getTypeChecker(), args: lints[i].args, host, program }), accepted: true }; } else if (kind === ExtensionKind.SyntacticLint) { - initializedLints[i] = {name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ts, args: lints[i].args, host, program}), accepted: true}; + initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ ts, args: lints[i].args, host, program }), accepted: true }; } } diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 6c91756e4ef1d..ecc550951b6b6 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -88,14 +88,14 @@ namespace ts { }, loadExtension(path) { const fullPath = this.getCanonicalFileName(path); - const m = {exports: {}}; + const m = { exports: {} }; ((module, exports, require) => { eval(virtualFs[fullPath]); })( m, m.exports, (name: string) => { return this.loadExtension( this.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, {module: ts.ModuleKind.CommonJS}, this, true).resolvedModule.resolvedFileName + ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, this, true).resolvedModule.resolvedFileName ) ); } @@ -165,7 +165,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { } function buildMap(map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean): Diagnostic[] { - const diagnostics = compile(map, compilerOptions ? compilerOptions : {module: ModuleKind.CommonJS, declaration: true}); + const diagnostics = compile(map, compilerOptions ? compilerOptions : { module: ModuleKind.CommonJS, declaration: true }); if (shouldError && diagnostics && diagnostics.length) { for (let i = 0; i < diagnostics.length; i++) { console.log(prettyPrintDiagnostic(diagnostics[i])); @@ -176,7 +176,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { virtualFs = {}; return diagnostics; } - buildMap(extensionAPI, extensionAPI, {module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: {"typescript": ["/lib/typescript.d.ts"]}}, /*shouldError*/true); + buildMap(extensionAPI, extensionAPI, { module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: { "typescript": ["/lib/typescript.d.ts"] } }, /*shouldError*/true); const extensions: Map> = { "test-syntactic-lint": { @@ -314,7 +314,7 @@ export class IsValueBar extends SemanticLintWalker { // Compile each extension once with the extension API in its node_modules folder (also generating .d.ts and .js) forEachKey(extensions, extName => { loadSetIntoFsAt(extensionAPI, "/node_modules/typescript-plugin-api"); - buildMap(extensions[extName], extensions[extName], {module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: {"typescript": ["lib/typescript.d.ts"]}}, /*shouldError*/true); + buildMap(extensions[extName], extensions[extName], { module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: { "typescript": ["lib/typescript.d.ts"] } }, /*shouldError*/true); }); /** From 0e9650c65267ec1e91b658d01bb59737c003686f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 27 Jun 2016 17:13:43 -0700 Subject: [PATCH 10/49] Implement field access per @rbuckton --- Gulpfile.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/program.ts | 76 +++++++------------ .../reference/library-reference-12.trace.json | 1 + .../reference/library-reference-2.trace.json | 2 + 5 files changed, 32 insertions(+), 51 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 32df9fc54b477..3c2702781b1ac 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -473,7 +473,7 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => { completedDts.pipe(clone()) .pipe(insert.transform((content, file) => { file.path = nodeStandaloneDefinitionsFile; - return content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'); + return content.replace(/declare (namespace|module) ts {/g, 'declare module "typescript" {\n import * as ts from "typescript";'); })) ]).pipe(gulp.dest(builtLocalDirectory)); }); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 91ae475b8ee1d..20a7f2f1253fd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2680,7 +2680,7 @@ "category": "Message", "code": 6104 }, - "Expected type of '{0}' field in 'package.json' to be 'string', got '{1}'.": { + "Expected type of '{0}' field in 'package.json' to be '{1}', got '{2}'.": { "category": "Message", "code": 6105 }, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 7e0bd24fe9b0e..66595bf6f776b 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -129,63 +129,41 @@ namespace ts { skipTsx: boolean; } - function tryFetchField(content: any, section: string, state: ModuleResolutionState): string { - const field = content[section]; - if (field) { - if (typeof field === "string") { - return field; - } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, section, typeof field); - } - } + function getPackageEntry(packageJson: any, key: string, tag: string, state: ModuleResolutionState) { + const value = packageJson[key]; + if (typeof value === tag) { + return value; + } + if (state.traceEnabled) { + trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, key, tag, typeof value); } + return undefined; } - function tryReadPathFromConfigSection(packageJsonPath: string, sections: string | string[], baseDirectory: string, state: ModuleResolutionState): string { - let jsonContent: any; - try { - const jsonText = state.host.readFile(packageJsonPath); - jsonContent = jsonText ? JSON.parse(jsonText) : {}; - } - catch (e) { - // gracefully handle if readFile fails or returns not JSON - jsonContent = {}; + function getPackageEntryAsPath(packageJson: any, packageJsonPath: string, key: string, state: ModuleResolutionState) { + const value = getPackageEntry(packageJson, key, "string", state); + const path = value ? normalizePath(combinePaths(getDirectoryPath(packageJsonPath), value)) : undefined; + if (path && state.traceEnabled) { + trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, key, value, path); } + return path; + } - let mainFile: string; - let utilizedSection: string; - - if (typeof sections === "string") { - mainFile = tryFetchField(jsonContent, sections, state); - utilizedSection = sections; - } - else { - for (const section of sections) { - mainFile = tryFetchField(jsonContent, section, state); - if (typeof mainFile === "string") { - utilizedSection = section; - break; - } - } - } - if (mainFile) { - const mainFilePath = normalizePath(combinePaths(baseDirectory, mainFile)); - if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, utilizedSection, mainFile, mainFilePath); - } - return mainFilePath; + function getPackageTypes(packageJsonPath: string, state: ModuleResolutionState) { + const { config } = readConfigFile(packageJsonPath, state.host.readFile); + if (config) { + return getPackageEntryAsPath(config, packageJsonPath, "typings", state) + || getPackageEntryAsPath(config, packageJsonPath, "types", state); } return undefined; } - function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { - return tryReadPathFromConfigSection(packageJsonPath, ["typings", "types"], baseDirectory, state); - } - - function tryReadMainSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { - return tryReadPathFromConfigSection(packageJsonPath, "main", baseDirectory, state); + function getPackageMain(packageJsonPath: string, state: ModuleResolutionState) { + const { config } = readConfigFile(packageJsonPath, state.host.readFile); + if (config) { + return getPackageEntryAsPath(config, packageJsonPath, "main", state); + } + return undefined; } const typeReferenceExtensions = [".d.ts"]; @@ -724,7 +702,7 @@ namespace ts { if (state.traceEnabled) { trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath); } - const typesFile = loadJS ? tryReadMainSection(packageJsonPath, candidate, state) : tryReadTypesSection(packageJsonPath, candidate, state); + const typesFile = loadJS ? getPackageMain(packageJsonPath, state) : getPackageTypes(packageJsonPath, state); if (typesFile) { const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state); if (result) { diff --git a/tests/baselines/reference/library-reference-12.trace.json b/tests/baselines/reference/library-reference-12.trace.json index 84144f82729c6..25fb7f618cd70 100644 --- a/tests/baselines/reference/library-reference-12.trace.json +++ b/tests/baselines/reference/library-reference-12.trace.json @@ -17,6 +17,7 @@ "File '/a/node_modules/jquery.ts' does not exist.", "File '/a/node_modules/jquery.d.ts' does not exist.", "Found 'package.json' at '/a/node_modules/jquery/package.json'.", + "Expected type of 'typings' field in 'package.json' to be 'string', got 'undefined'.", "'package.json' has 'types' field 'dist/jquery.d.ts' that references '/a/node_modules/jquery/dist/jquery.d.ts'.", "File '/a/node_modules/jquery/dist/jquery.d.ts' exist - use it as a name resolution result.", "======== Type reference directive 'jquery' was successfully resolved to '/a/node_modules/jquery/dist/jquery.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/library-reference-2.trace.json b/tests/baselines/reference/library-reference-2.trace.json index c26f7d2763d7f..0cdb8e98c48e5 100644 --- a/tests/baselines/reference/library-reference-2.trace.json +++ b/tests/baselines/reference/library-reference-2.trace.json @@ -2,12 +2,14 @@ "======== Resolving type reference directive 'jquery', containing file '/consumer.ts', root directory '/types'. ========", "Resolving with primary search path '/types'", "Found 'package.json' at '/types/jquery/package.json'.", + "Expected type of 'typings' field in 'package.json' to be 'string', got 'undefined'.", "'package.json' has 'types' field 'jquery.d.ts' that references '/types/jquery/jquery.d.ts'.", "File '/types/jquery/jquery.d.ts' exist - use it as a name resolution result.", "======== Type reference directive 'jquery' was successfully resolved to '/types/jquery/jquery.d.ts', primary: true. ========", "======== Resolving type reference directive 'jquery', containing file '/__inferred type names__.ts', root directory '/types'. ========", "Resolving with primary search path '/types'", "Found 'package.json' at '/types/jquery/package.json'.", + "Expected type of 'typings' field in 'package.json' to be 'string', got 'undefined'.", "'package.json' has 'types' field 'jquery.d.ts' that references '/types/jquery/jquery.d.ts'.", "File '/types/jquery/jquery.d.ts' exist - use it as a name resolution result.", "======== Type reference directive 'jquery' was successfully resolved to '/types/jquery/jquery.d.ts', primary: true. ========" From dec0bf88e1d169bd4026a72aaca1204688bbddfa Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 27 Jun 2016 17:23:09 -0700 Subject: [PATCH 11/49] Fix mock host --- src/compiler/program.ts | 15 ++++++++++----- tests/cases/unittests/extensionAPI.ts | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 66595bf6f776b..3c6ff070577c5 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -155,6 +155,11 @@ namespace ts { return getPackageEntryAsPath(config, packageJsonPath, "typings", state) || getPackageEntryAsPath(config, packageJsonPath, "types", state); } + else { + if (state.traceEnabled) { + trace(state.host, Diagnostics.package_json_does_not_have_0_field, "types"); + } + } return undefined; } @@ -163,6 +168,11 @@ namespace ts { if (config) { return getPackageEntryAsPath(config, packageJsonPath, "main", state); } + else { + if (state.traceEnabled) { + trace(state.host, Diagnostics.package_json_does_not_have_0_field, "main"); + } + } return undefined; } @@ -709,11 +719,6 @@ namespace ts { return result; } } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_does_not_have_0_field, loadJS ? "main" : "types"); - } - } } else { if (state.traceEnabled) { diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index ecc550951b6b6..1d9911e9cb7a5 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -56,46 +56,46 @@ namespace ts { const mockHost: CompilerHost = { useCaseSensitiveFileNames() { return true; }, getNewLine() { return "\n"; }, - readFile(path) { return virtualFs[this.getCanonicalFileName(path)]; }, + readFile(path) { return virtualFs[mockHost.getCanonicalFileName(path)]; }, writeFile(path, content, foo, bar, baz) { - virtualFs[this.getCanonicalFileName(path)] = content; + virtualFs[mockHost.getCanonicalFileName(path)] = content; }, fileExists(path) { - return !!virtualFs[this.getCanonicalFileName(path)]; + return !!virtualFs[mockHost.getCanonicalFileName(path)]; }, directoryExists(path) { - const fullPath = this.getCanonicalFileName(path); + const fullPath = mockHost.getCanonicalFileName(path); return forEach(getKeys(virtualFs), key => startsWith(key, fullPath)); }, getCurrentDirectory(): string { return "/"; }, getSourceFile(path, languageVersion, onError): SourceFile { - const fullPath = this.getCanonicalFileName(path); + const fullPath = mockHost.getCanonicalFileName(path); return createSourceFile(fullPath, virtualFs[fullPath], languageVersion); }, getDefaultLibLocation() { return "/lib/"; }, getDefaultLibFileName(options) { - return combinePaths(this.getDefaultLibLocation(), getDefaultLibFileName(options)); + return combinePaths(mockHost.getDefaultLibLocation(), getDefaultLibFileName(options)); }, getCanonicalFileName, getDirectories(path) { - path = this.getCanonicalFileName(path); + path = mockHost.getCanonicalFileName(path); return filter(map(filter(getKeys(virtualFs), fullpath => startsWith(fullpath, path) && fullpath.substr(path.length, 1) === "/"), fullpath => fullpath.substr(path.length + 1).indexOf("/") >= 0 ? fullpath.substr(0, 1 + path.length + fullpath.substr(path.length + 1).indexOf("/")) : fullpath), fullpath => fullpath.lastIndexOf(".") === -1); }, loadExtension(path) { - const fullPath = this.getCanonicalFileName(path); + const fullPath = mockHost.getCanonicalFileName(path); const m = { exports: {} }; ((module, exports, require) => { eval(virtualFs[fullPath]); })( m, m.exports, (name: string) => { - return this.loadExtension( - this.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, this, true).resolvedModule.resolvedFileName + return mockHost.loadExtension( + mockHost.getCanonicalFileName( + ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName ) ); } From 67f6e26bb3e18d3ce86c0b0410617bbe2a2c4338 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 28 Jun 2016 15:05:38 -0700 Subject: [PATCH 12/49] Add overloads supporting additional shortnames to lint errors --- src/compiler/program.ts | 68 ++++++++++++-- src/compiler/types.ts | 3 + tests/cases/unittests/extensionAPI.ts | 130 ++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 7 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index d81cd23f9f664..0cb4647322d78 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1614,15 +1614,69 @@ namespace ts { function error(err: string): void; function error(err: string, node: Node): void; function error(err: string, start: number, length: number): void; - function error(err: string, nodeOrStart?: Node | number, length?: number): void { - if (typeof nodeOrStart === "undefined") { - diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile)); - } - else if (typeof nodeOrStart === "number") { - diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile, nodeOrStart, length)); + function error(shortname: string, err: string): void; + function error(shortname: string, err: string, span: Node): void; + function error(shortname: string, err: string, start: number, length: number): void; + function error(errOrShortname: string, errOrNodeOrStart?: string | Node | number, lengthOrNodeOrStart?: Node | number, length?: number): void { + if (typeof length === "undefined") { + // 3 or fewer arguments + if (typeof lengthOrNodeOrStart === "undefined") { + // 2 or fewer arguments + if (typeof errOrNodeOrStart === "undefined") { + // 1 argument + // (err: string) + return void diagnostics.push(createExtensionDiagnostic(activeLint.name, errOrShortname)); + } + else { + // Exactly 2 arguments + if (typeof errOrNodeOrStart === "number") { + // No corresponding overloads + } + else if (typeof errOrNodeOrStart === "string") { + // (shortname: string, err: string) + return void diagnostics.push(createExtensionDiagnostic(`${activeLint.name}(${errOrShortname})`, errOrNodeOrStart)); + } + else { + // (err: string, node: Node) + return void diagnostics.push(createExtensionDiagnosticForNode(errOrNodeOrStart, activeLint.name, errOrShortname)); + } + } + } + else { + // Exactly 3 arguments + if (typeof lengthOrNodeOrStart === "number") { + if (typeof errOrNodeOrStart !== "number") { + // No corresponding overloads + } + else { + // (err: string, start: number, length: number) + return void diagnostics.push(createExtensionDiagnostic(activeLint.name, errOrShortname, sourceFile, errOrNodeOrStart, lengthOrNodeOrStart)); + } + } + else { + if (typeof errOrNodeOrStart !== "string") { + // No corresponding overloads + } + else { + // (shortname: string, err: string, span: Node) + return void diagnostics.push(createExtensionDiagnosticForNode(lengthOrNodeOrStart, `${activeLint.name}(${errOrShortname})`, errOrNodeOrStart)); + } + } + } } else { - diagnostics.push(createExtensionDiagnosticForNode(nodeOrStart, activeLint.name, err)); + if (typeof errOrNodeOrStart !== "string") { + // No corresponding overloads + } + else { + if (typeof lengthOrNodeOrStart !== "number") { + // No corresponding overloads + } + else { + // (shortname: string, err: string, start: number, length: number) + return void diagnostics.push(createExtensionDiagnostic(`${activeLint.name}(${errOrShortname})`, errOrNodeOrStart, sourceFile, lengthOrNodeOrStart, length)); + } + } } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4a05351d67f9e..1b903ae503a76 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2912,6 +2912,9 @@ namespace ts { (err: string): void; (err: string, span: Node): void; (err: string, start: number, length: number): void; + (shortname: string, err: string): void; + (shortname: string, err: string, span: Node): void; + (shortname: string, err: string, start: number, length: number): void; }; export type LintStopMethod = () => void; diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 1d9911e9cb7a5..eb298254ffcab 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -308,7 +308,107 @@ export class IsValueBar extends SemanticLintWalker { } } ` + }, + "test-multierrors": { + "package.json": `{ + "name": "test-multierrors", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {SyntacticLintWalker} from "typescript-plugin-api"; + +export default class IsNamedFooOrBar extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + if (node.kind === this.ts.SyntaxKind.Identifier) { + if (node.text.toLowerCase() === "foo") { + error("FOO", "Identifier 'foo' is forbidden.", node); + } + if (node.text.toLowerCase() === "bar") { + error("BAR", "Identifier 'bar' is forbidden.", node); + } + } + } +} + +export class NoShortNames extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + if (node.kind === this.ts.SyntaxKind.Identifier) { + if (node.text.length == 1) { + error("SINGLE", "Single character identifiers are forbidden", node); + } + else if (node.text.length <= 3) { + error("SHORT", "Short identifiers are forbidden.", node); } + } + } +} +`, + }, + "test-errors": { + "package.json": `{ + "name": "test-errors", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +}`, + "index.ts": ` +import {SyntacticLintWalker} from "typescript-plugin-api"; + +export default class Throws extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed."); + stop(); + } +} + +export class Throws2 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS2", "Not allowed."); + stop(); + } +} + +export class Throws3 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS3", "Not allowed.", node); + stop(); + } +} + +export class Throws4 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS4", "Not allowed.", 0, 10); + stop(); + } +} + +export class Throws5 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed.", node); + stop(); + } +} + +export class Throws6 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed.", 0, 10); + stop(); + } +} +`, + }, }; // Compile each extension once with the extension API in its node_modules folder (also generating .d.ts and .js) @@ -464,5 +564,35 @@ export class IsValueBar extends SemanticLintWalker { } }); }); + + it("can handle multiple diagnostics from a single rule", () => { + test({ + "main.ts": ` +const foo = 3; +const bar = 4; +const x = 3 * 4; + `, + }, { + availableExtensions: ["test-multierrors"], + expectedDiagnostics: ["test-multierrors(FOO)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors(BAR)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors[NoShortNames](SINGLE)",], + compilerOptions: { + extensions: ["test-multierrors"], + module: ModuleKind.CommonJS, + } + }); + }); + + it("sucessfully handles all six avalable error method overloads", () => { + test({ + "main.ts": `console.log('Hello, world!')`, + }, { + availableExtensions: ["test-errors"], + expectedDiagnostics: ["test-errors", "test-errors[Throws2](THROWS2)", "test-errors[Throws3](THROWS3)", "test-errors[Throws5]", "test-errors[Throws4](THROWS4)", "test-errors[Throws6]"], + compilerOptions: { + extensions: ["test-errors"], + module: ModuleKind.CommonJS, + } + }); + }); }); } From 2c15bb3335315de5735f3d4e3b3649fb2d4df96e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 28 Jun 2016 16:29:44 -0700 Subject: [PATCH 13/49] Extract extension cache into new file (so it can be shared/persisted) --- Jakefile.js | 1 + src/compiler/extensions.ts | 169 ++++++++++++++++++++++++++ src/compiler/program.ts | 87 ++----------- src/compiler/tsconfig.json | 1 + src/compiler/types.ts | 70 +---------- src/services/tsconfig.json | 1 + tests/cases/unittests/extensionAPI.ts | 2 +- 7 files changed, 188 insertions(+), 143 deletions(-) create mode 100644 src/compiler/extensions.ts diff --git a/Jakefile.js b/Jakefile.js index f36b92a9ee540..78fadf4f34023 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -45,6 +45,7 @@ var compilerSources = [ "declarationEmitter.ts", "emitter.ts", "program.ts", + "extensions.ts", "commandLineParser.ts", "tsc.ts", "diagnosticInformationMap.generated.ts" diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts new file mode 100644 index 0000000000000..7143a129a9557 --- /dev/null +++ b/src/compiler/extensions.ts @@ -0,0 +1,169 @@ +namespace ts { + export type LintErrorMethod = { + (err: string): void; + (err: string, span: Node): void; + (err: string, start: number, length: number): void; + (shortname: string, err: string): void; + (shortname: string, err: string, span: Node): void; + (shortname: string, err: string, start: number, length: number): void; + }; + export type LintStopMethod = () => void; + + /* + * Walkers call stop to halt recursion into the node's children + * Walkers call error to add errors to the output. + */ + export interface LintWalker { + visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void; + } + + export interface BaseProviderStatic { + readonly ["extension-kind"]: ExtensionKind; + new (state: {ts: typeof ts, args: any}): any; + } + + export interface SyntacticLintProviderStatic extends BaseProviderStatic { + readonly ["extension-kind"]: ExtensionKind.SyntacticLint; + new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program}): LintWalker; + } + + export interface SemanticLintProviderStatic extends BaseProviderStatic { + readonly ["extension-kind"]: ExtensionKind.SemanticLint; + new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program, checker: TypeChecker}): LintWalker; + } + + export namespace ExtensionKind { + export const SemanticLint: "semantic-lint" = "semantic-lint"; + export type SemanticLint = "semantic-lint"; + export const SyntacticLint: "syntactic-lint" = "syntactic-lint"; + export type SyntacticLint = "syntactic-lint"; + } + export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint; + + export interface ExtensionCollectionMap { + "syntactic-lint"?: SyntacticLintExtension[]; + "semantic-lint"?: SemanticLintExtension[]; + [index: string]: Extension[] | undefined; + } + + export interface ExtensionBase { + name: string; + args: any; + kind: ExtensionKind; + } + + // @kind(ExtensionKind.SyntacticLint) + export interface SyntacticLintExtension extends ExtensionBase { + ctor: SyntacticLintProviderStatic; + } + + // @kind(ExtensionKind.SemanticLint) + export interface SemanticLintExtension extends ExtensionBase { + ctor: SemanticLintProviderStatic; + } + + export type Extension = SyntacticLintExtension | SemanticLintExtension; + + export interface ExtensionCache { + getCompilerExtensions(): ExtensionCollectionMap; + getExtensionLoadingDiagnostics(): Diagnostic[]; + } + + export interface ExtensionHost extends ModuleResolutionHost { + loadExtension?(name: string): any; + } + + export function createExtensionCache(options: CompilerOptions, host: ExtensionHost): ExtensionCache { + + const diagnostics: Diagnostic[] = []; + let extensions: ExtensionCollectionMap; + + const cache: ExtensionCache = { + getCompilerExtensions: () => { + if (!extensions) { + extensions = collectCompilerExtensions(); + } + return extensions; + }, + getExtensionLoadingDiagnostics: () => { + // To get extension loading diagnostics, we need to make sure we've actually loaded them + cache.getCompilerExtensions(); + return diagnostics; + }, + }; + return cache; + + function collectCompilerExtensions(): ExtensionCollectionMap { + const extOptions = options.extensions; + const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); + const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ""; + const extensionLoadResults = map(extensionNames, name => { + let result: any; + let error: any; + if (host.loadExtension) { + const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; + if (resolved) { + try { + result = host.loadExtension(resolved.resolvedFileName); + } + catch (e) { + error = e; + } + } + else { + error = new Error(`Host could not locate extension '${name}'.`); + } + } + else { + error = new Error("Extension loading not implemented in host!"); + } + if (error) { + diagnostics.push(createCompilerDiagnostic(Diagnostics.Extension_loading_failed_with_error_0, error.stack ? `${error} + Stack trace: + ${error.stack}` : error)); + } + return { name, result, error }; + }); + const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); + const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { + if (res.result) { + return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: BaseProviderStatic, key: string) => { + if (!potentialExtension) { + return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) + } + const annotatedKind = potentialExtension["extension-kind"]; + if (typeof annotatedKind === "string") { + const ext: ExtensionBase = { + name: key !== "default" ? `${res.name}[${key}]` : res.name, + args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], + kind: annotatedKind + }; + switch (ext.kind) { + case ExtensionKind.SemanticLint: + case ExtensionKind.SyntacticLint: + if (typeof potentialExtension !== "function") { + diagnostics.push(createCompilerDiagnostic( + Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, + res.name, + key, + (ts as any).ExtensionKind[annotatedKind], + typeof potentialExtension, + "function" + )); + return; + } + (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic); + } + aggregate.push(ext as Extension); + } + return aggregate; + }, []); + } + else { + return []; + } + }); + return groupBy(flatten(preparedExtensionObjects), elem => elem.kind) || {}; + } + } +} \ No newline at end of file diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0cb4647322d78..b83e1f0873f7f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,6 +1,7 @@ /// /// /// +/// namespace ts { /* @internal */ export let programTime = 0; @@ -1047,7 +1048,7 @@ namespace ts { return result; } - export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program { + export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, extensionCache?: ExtensionCache): Program { let program: Program; let files: SourceFile[] = []; let commonSourceDirectory: string; @@ -1147,7 +1148,7 @@ namespace ts { // unconditionally set oldProgram to undefined to prevent it from being captured in closure oldProgram = undefined; - const compilerExtensions = collectCompilerExtensions(); + extensionCache = extensionCache || createExtensionCache(options, host); program = { getRootFileNames: () => rootNames, @@ -1173,8 +1174,11 @@ namespace ts { getFileProcessingDiagnostics: () => fileProcessingDiagnostics, getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives, getCompilerExtensions() { - return compilerExtensions; - } + return extensionCache.getCompilerExtensions(); + }, + getExtensionLoadingDiagnostics() { + return extensionCache.getExtensionLoadingDiagnostics(); + }, }; verifyCompilerOptions(); @@ -1183,78 +1187,6 @@ namespace ts { return program; - function collectCompilerExtensions(): ExtensionCollectionMap { - const extOptions = options.extensions; - const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); - const extensionLoadResults = map(extensionNames, name => { - let result: any; - let error: any; - if (host.loadExtension) { - const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; - if (resolved) { - try { - result = host.loadExtension(resolved.resolvedFileName); - } - catch (e) { - error = e; - } - } - else { - error = new Error(`Host could not locate extension '${name}'.`); - } - } - else { - error = new Error("Extension loading not implemented in compiler host."); - } - if (error) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Extension_loading_failed_with_error_0, error.stack ? `${error} - Stack trace: - ${error.stack}` : error)); - } - return { name, result, error }; - }); - const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); - const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { - if (res.result) { - return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: BaseProviderStatic, key: string) => { - if (!potentialExtension) { - return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) - } - const annotatedKind = potentialExtension["extension-kind"]; - if (typeof annotatedKind === "string") { - const ext: ExtensionBase = { - name: key !== "default" ? `${res.name}[${key}]` : res.name, - args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], - kind: annotatedKind - }; - switch (ext.kind) { - case ExtensionKind.SemanticLint: - case ExtensionKind.SyntacticLint: - if (typeof potentialExtension !== "function") { - programDiagnostics.add(createCompilerDiagnostic( - Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, - res.name, - key, - (ts as any).ExtensionKind[annotatedKind], - typeof potentialExtension, - "function" - )); - return; - } - (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic); - } - aggregate.push(ext as Extension); - } - return aggregate; - }, []); - } - else { - return []; - } - }); - return groupBy(flatten(preparedExtensionObjects), elem => elem.kind) || {}; - } - function getCommonSourceDirectory() { if (typeof commonSourceDirectory === "undefined") { if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) { @@ -1555,7 +1487,7 @@ namespace ts { * ExtensionKind.SyntacticLint or ExtensionKind.SemanticLint only */ function performLintPassOnFile(sourceFile: SourceFile, kind: ExtensionKind): Diagnostic[] | undefined { - const lints = compilerExtensions[kind]; + const lints = extensionCache.getCompilerExtensions()[kind]; if (!lints || !lints.length) { return; } @@ -1927,6 +1859,7 @@ namespace ts { const allDiagnostics: Diagnostic[] = []; addRange(allDiagnostics, fileProcessingDiagnostics.getGlobalDiagnostics()); addRange(allDiagnostics, programDiagnostics.getGlobalDiagnostics()); + allDiagnostics.push(...extensionCache.getExtensionLoadingDiagnostics()); return sortAndDeduplicateDiagnostics(allDiagnostics); } diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 76308c2cba4ff..3a7098a95fb00 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -21,6 +21,7 @@ "declarationEmitter.ts", "emitter.ts", "program.ts", + "extensions.ts", "commandLineParser.ts", "tsc.ts", "diagnosticInformationMap.generated.ts" diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1b903ae503a76..439b9d324ea88 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1743,6 +1743,11 @@ namespace ts { */ getCompilerExtensions(): ExtensionCollectionMap; + /** + * Gets only diagnostics reported while loading extensions + */ + getExtensionLoadingDiagnostics(): Diagnostic[]; + /* @internal */ getCommonSourceDirectory(): string; // For testing purposes only. Should not be used by any other consumers (including the @@ -2908,71 +2913,6 @@ namespace ts { failedLookupLocations: string[]; } - export type LintErrorMethod = { - (err: string): void; - (err: string, span: Node): void; - (err: string, start: number, length: number): void; - (shortname: string, err: string): void; - (shortname: string, err: string, span: Node): void; - (shortname: string, err: string, start: number, length: number): void; - }; - export type LintStopMethod = () => void; - - /* - * Walkers call stop to halt recursion into the node's children - * Walkers call error to add errors to the output. - */ - export interface LintWalker { - visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void; - } - - export interface BaseProviderStatic { - readonly ["extension-kind"]: ExtensionKind; - new (state: {ts: typeof ts, args: any}): any; - } - - export interface SyntacticLintProviderStatic extends BaseProviderStatic { - readonly ["extension-kind"]: ExtensionKind.SyntacticLint; - new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program}): LintWalker; - } - - export interface SemanticLintProviderStatic extends BaseProviderStatic { - readonly ["extension-kind"]: ExtensionKind.SemanticLint; - new (state: {ts: typeof ts, args: any, host: CompilerHost, program: Program, checker: TypeChecker}): LintWalker; - } - - export namespace ExtensionKind { - export const SemanticLint: "semantic-lint" = "semantic-lint"; - export type SemanticLint = "semantic-lint"; - export const SyntacticLint: "syntactic-lint" = "syntactic-lint"; - export type SyntacticLint = "syntactic-lint"; - } - export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint; - - export interface ExtensionCollectionMap { - "syntactic-lint"?: SyntacticLintExtension[]; - "semantic-lint"?: SemanticLintExtension[]; - [index: string]: Extension[] | undefined; - } - - export interface ExtensionBase { - name: string; - args: any; - kind: ExtensionKind; - } - - // @kind(ExtensionKind.SyntacticLint) - export interface SyntacticLintExtension extends ExtensionBase { - ctor: SyntacticLintProviderStatic; - } - - // @kind(ExtensionKind.SemanticLint) - export interface SemanticLintExtension extends ExtensionBase { - ctor: SemanticLintProviderStatic; - } - - export type Extension = SyntacticLintExtension | SemanticLintExtension; - export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 4bf6e87d7a631..9871c63a40a30 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -22,6 +22,7 @@ "../compiler/declarationEmitter.ts", "../compiler/emitter.ts", "../compiler/program.ts", + "../compiler/extensions.ts", "../compiler/commandLineParser.ts", "../compiler/diagnosticInformationMap.generated.ts", "breakpoints.ts", diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index eb298254ffcab..00829de6ac2a3 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -574,7 +574,7 @@ const x = 3 * 4; `, }, { availableExtensions: ["test-multierrors"], - expectedDiagnostics: ["test-multierrors(FOO)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors(BAR)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors[NoShortNames](SINGLE)",], + expectedDiagnostics: ["test-multierrors(FOO)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors(BAR)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors[NoShortNames](SINGLE)"], compilerOptions: { extensions: ["test-multierrors"], module: ModuleKind.CommonJS, From 257e939fa68074d312fac409bf0c55e038889900 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 10:41:14 -0700 Subject: [PATCH 14/49] Fix lints, identify lifetimeissue --- src/services/services.ts | 6 ++++-- tests/cases/unittests/extensionAPI.ts | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 798ff5e30a19e..098a97e0748e6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3126,7 +3126,7 @@ namespace ts { } // Get a fresh cache of the host information - let hostCache = new HostCache(host, getCanonicalFileName); + const hostCache = new HostCache(host, getCanonicalFileName); // If the program is already up-to-date, we can reuse it if (programUpToDate()) { @@ -3211,7 +3211,9 @@ namespace ts { // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. // It needs to be cleared to allow all collected snapshots to be released - hostCache = undefined; + // TODO (weswig): hostCache needs to exist as long as its associated compilerHost exists, since it is used in fileExists. + // As such, we cannot release it here - it must be tied to the lifetime of the compilerHost. + // hostCache = undefined; program = newProgram; diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 46e6feaa0cf2b..1e9858c0c14ff 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -111,7 +111,7 @@ namespace ts { function makeMockLSHost(files: string[], options: CompilerOptions): LanguageServiceHost { files = filter(files, file => !endsWith(file, ".json")); - return { + const host: LanguageServiceHost = { getCompilationSettings: () => options, getScriptFileNames: () => files, getScriptVersion(fileName) { @@ -130,14 +130,14 @@ namespace ts { }, loadExtension(path) { const fullPath = getCanonicalFileName(path); - const m = {exports: {}}; + const m = { exports: {} }; ((module, exports, require) => { eval(virtualFs[fullPath]); })( m, m.exports, (name: string) => { - return this.loadExtension( + return host.loadExtension( getCanonicalFileName( - resolveModuleName(name, fullPath, {module: ModuleKind.CommonJS}, mockHost, true).resolvedModule.resolvedFileName + resolveModuleName(name, fullPath, { module: ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName ) ); } @@ -148,6 +148,7 @@ namespace ts { console.log(s); } }; + return host; }; const extensionAPI: Map = { @@ -1117,16 +1118,16 @@ being received, for good or for evil, in the superlative degree of comparison only. `; const testDummyLS = (service: LanguageService) => { - assert.deepEqual(service.getEncodedSyntacticClassifications(atotcFile, {start: 0, length: 24}), - {spans: [0, 24, ClassificationType.text], endOfLineState: EndOfLineState.None}, + assert.deepEqual(service.getEncodedSyntacticClassifications(atotcFile, { start: 0, length: 24 }), + { spans: [0, 24, ClassificationType.text], endOfLineState: EndOfLineState.None }, "Syntactic classifications did not match!"); - assert.deepEqual(service.getEncodedSemanticClassifications(atotcFile, {start: 24, length: 42}), - {spans: [24, 42, ClassificationType.moduleName], endOfLineState: EndOfLineState.None}, + assert.deepEqual(service.getEncodedSemanticClassifications(atotcFile, { start: 24, length: 42 }), + { spans: [24, 42, ClassificationType.moduleName], endOfLineState: EndOfLineState.None }, "Semantic classifications did not match!"); assert.deepEqual(service.getCompletionsAtPosition(atotcFile, 0), { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{name: atotcFile, kind: 0, kindModifiers: 0, sortText: atotcFile}] + entries: [{ name: atotcFile, kind: 0, kindModifiers: 0, sortText: atotcFile }] }, "Completions did not match!"); assert.deepEqual(service.getCompletionEntryDetails(atotcFile, 0, "first"), { name: atotcFile, From 9425485a1c62769b82a6c1a439b1b90dc76ca907 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 10:58:15 -0700 Subject: [PATCH 15/49] remove excess deep equal overload --- src/harness/external/chai.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/harness/external/chai.d.ts b/src/harness/external/chai.d.ts index ccd1de1bfb59f..5e4e6e7d00010 100644 --- a/src/harness/external/chai.d.ts +++ b/src/harness/external/chai.d.ts @@ -175,6 +175,5 @@ declare module chai { function isOk(actual: any, message?: string): void; function isUndefined(value: any, message?: string): void; function isDefined(value: any, message?: string): void; - function deepEqual(actual: any, expected: any, message?: string): void; } } \ No newline at end of file From c2f1cc507054a6dce8e765844af4a11471f563b9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 11:03:40 -0700 Subject: [PATCH 16/49] Backport all code related to making extensions run in an LS context --- src/compiler/extensions.ts | 6 + src/harness/harnessLanguageService.ts | 3 + src/server/client.ts | 4 + src/server/editorServices.ts | 2 +- src/services/services.ts | 23 ++- src/services/shims.ts | 10 ++ tests/cases/unittests/extensionAPI.ts | 226 ++++++++++++++++++++++++-- 7 files changed, 252 insertions(+), 22 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 7143a129a9557..db0f3aaa4f3e6 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -153,6 +153,12 @@ namespace ts { return; } (ext as (SemanticLintExtension | SyntacticLintExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic); + break; + default: + // Include a default case which just puts the extension unchecked onto the base extension + // This can allow language service extensions to query for custom extension kinds + (ext as any).__extension = potentialExtension; + break; } aggregate.push(ext as Extension); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index b40cbde73e71a..b2f3b1031d6d5 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -366,6 +366,9 @@ namespace Harness.LanguageService { getCompilerOptionsDiagnostics(): ts.Diagnostic[] { return unwrapJSONCallResult(this.shim.getCompilerOptionsDiagnostics()); } + getProgramDiagnostics(): ts.Diagnostic[] { + return unwrapJSONCallResult(this.shim.getProgramDiagnostics()); + } getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } diff --git a/src/server/client.ts b/src/server/client.ts index f04dbd8dc0253..d12c50459b6fe 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -395,6 +395,10 @@ namespace ts.server { } getCompilerOptionsDiagnostics(): Diagnostic[] { + return this.getProgramDiagnostics(); + } + + getProgramDiagnostics(): Diagnostic[] { throw new Error("Not Implemented Yet."); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index e48d61920177f..476068f688445 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1147,7 +1147,7 @@ namespace ts.server { info.setFormatOptions(this.getFormatCodeOptions()); this.filenameToScriptInfo[fileName] = info; if (!info.isOpen) { - info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); + info.fileWatcher = this.host.watchFile && this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); } } } diff --git a/src/services/services.ts b/src/services/services.ts index a17d9feed2485..2099db112f67c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1079,6 +1079,8 @@ namespace ts { resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; directoryExists?(directoryName: string): boolean; getDirectories?(directoryName: string): string[]; + + loadExtension?(path: string): any; } // @@ -1091,10 +1093,13 @@ namespace ts { getSyntacticDiagnostics(fileName: string): Diagnostic[]; getSemanticDiagnostics(fileName: string): Diagnostic[]; - // TODO: Rename this to getProgramDiagnostics to better indicate that these are any - // diagnostics present for the program level, and not just 'options' diagnostics. + /** + * @deprecated Use getProgramDiagnostics instead. + */ getCompilerOptionsDiagnostics(): Diagnostic[]; + getProgramDiagnostics(): Diagnostic[]; + /** * @deprecated Use getEncodedSyntacticClassifications instead. */ @@ -2971,7 +2976,7 @@ namespace ts { } // Get a fresh cache of the host information - let hostCache = new HostCache(host, getCanonicalFileName); + const hostCache = new HostCache(host, getCanonicalFileName); // If the program is already up-to-date, we can reuse it if (programUpToDate()) { @@ -3021,6 +3026,9 @@ namespace ts { }, getDirectories: path => { return host.getDirectories ? host.getDirectories(path) : []; + }, + loadExtension: path => { + return host.loadExtension ? host.loadExtension(path) : undefined; } }; if (host.trace) { @@ -3053,7 +3061,9 @@ namespace ts { // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. // It needs to be cleared to allow all collected snapshots to be released - hostCache = undefined; + // TODO (weswig): hostCache needs to exist as long as its associated compilerHost exists, since it is used in fileExists. + // As such, we cannot release it here - it must be tied to the lifetime of the compilerHost. + // hostCache = undefined; program = newProgram; @@ -3198,7 +3208,7 @@ namespace ts { return concatenate(semanticDiagnostics, declarationDiagnostics); } - function getCompilerOptionsDiagnostics() { + function getProgramDiagnostics() { synchronizeHostData(); return program.getOptionsDiagnostics(cancellationToken).concat( program.getGlobalDiagnostics(cancellationToken)); @@ -8124,7 +8134,8 @@ namespace ts { cleanupSemanticCache, getSyntacticDiagnostics, getSemanticDiagnostics, - getCompilerOptionsDiagnostics, + getCompilerOptionsDiagnostics: getProgramDiagnostics, + getProgramDiagnostics, getSyntacticClassifications, getSemanticClassifications, getEncodedSyntacticClassifications, diff --git a/src/services/shims.ts b/src/services/shims.ts index 08f26dfcbe754..c79262a15d3e6 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -119,6 +119,7 @@ namespace ts { getSyntacticDiagnostics(fileName: string): string; getSemanticDiagnostics(fileName: string): string; getCompilerOptionsDiagnostics(): string; + getProgramDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; getSemanticClassifications(fileName: string, start: number, length: number): string; @@ -678,6 +679,15 @@ namespace ts { }); } + public getProgramDiagnostics(): string { + return this.forwardJSONCall( + "getProgramDiagnostics()", + () => { + const diagnostics = this.languageService.getProgramDiagnostics(); + return this.realizeDiagnostics(diagnostics); + }); + } + /// QUICKINFO /** diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 00829de6ac2a3..505a92e39dea7 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -20,10 +20,10 @@ namespace ts { } for (let i = 0; i < expectedDiagnosticCodes.length; i++) { - assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); + assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic: (expected) [${expectedDiagnosticCodes.toString()}] vs (actual) [${map(diagnostics, d => d.code).toString()}]. First diagnostic: ${prettyPrintDiagnostic(diagnostics[0])}`); } if (expectedDiagnosticCodes.length === 0 && diagnostics.length) { - throw new Error(`Unexpected diagnostic (${diagnostics.length - 1} more): ${prettyPrintDiagnostic(diagnostics[0])}`); + throw new Error(`Unexpected diagnostic (${map(diagnostics, d => d.code).toString()}): ${prettyPrintDiagnostic(diagnostics[0])}`); } assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); } @@ -43,10 +43,12 @@ namespace ts { let virtualFs: Map = {}; - const getCanonicalFileName = createGetCanonicalFileName(true); + const innerCanonicalName = createGetCanonicalFileName(true); + const getCanonicalFileName = (fileName: string) => toPath(fileName, "/", innerCanonicalName); function loadSetIntoFsAt(set: Map, prefix: string) { - forEachKey(set, key => void (virtualFs[getCanonicalFileName(combinePaths(prefix, key))] = set[key])); + // Load a fileset at the given location, but exclude the /lib/ dir from the added set + forEachKey(set, key => startsWith(key, "/lib/") ? void 0 : void (virtualFs[getCanonicalFileName(prefix + key)] = set[key])); } function loadSetIntoFs(set: Map) { @@ -95,7 +97,7 @@ namespace ts { (name: string) => { return mockHost.loadExtension( mockHost.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName + resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName ) ); } @@ -107,6 +109,48 @@ namespace ts { } }; + function makeMockLSHost(files: string[], options: CompilerOptions): LanguageServiceHost { + files = filter(files, file => !endsWith(file, ".json")); + const host: LanguageServiceHost = { + getCompilationSettings: () => options, + getScriptFileNames: () => files, + getScriptVersion(fileName) { + return "1"; + }, + getScriptSnapshot(fileName): IScriptSnapshot { + const fileContents = virtualFs[getCanonicalFileName(fileName)]; + if (!fileContents) return; + return ScriptSnapshot.fromString(fileContents); + }, + getCurrentDirectory() { + return ""; + }, + getDefaultLibFileName() { + return "/lib/lib.d.ts"; + }, + loadExtension(path) { + const fullPath = getCanonicalFileName(path); + const m = { exports: {} }; + ((module, exports, require) => { eval(virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return host.loadExtension( + getCanonicalFileName( + resolveModuleName(name, fullPath, { module: ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName + ) + ); + } + ); + return m.exports; + }, + trace(s) { + console.log(s); + } + }; + return host; + }; + const extensionAPI: Map = { "package.json": `{ "name": "typescript-plugin-api", @@ -154,18 +198,42 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { }; // Compile extension API once (generating .d.ts and .js) - function compile(fileset: Map, options: ts.CompilerOptions): Diagnostic[] { - loadSetIntoFs(virtualLib); - loadSetIntoFs(fileset); + function languageServiceCompile(typescriptFiles: string[], options: CompilerOptions, additionalVerifiers?: (service: LanguageService) => void): Diagnostic[] { + options.allowJs = true; + options.noEmit = true; + const service = createLanguageService(makeMockLSHost(getKeys(virtualFs), options)); - const program = createProgram(filter(getKeys(fileset), name => name != "package.json"), options, mockHost); + if (additionalVerifiers) { + additionalVerifiers(service); + } + + const diagnostics = concatenate(concatenate( + service.getProgramDiagnostics(), + flatten(map(typescriptFiles, fileName => service.getSyntacticDiagnostics(getCanonicalFileName(fileName))))), + flatten(map(typescriptFiles, fileName => service.getSemanticDiagnostics(getCanonicalFileName(fileName))))); + + return sortAndDeduplicateDiagnostics(diagnostics); + } + + type VirtualCompilationFunction = (files: string[], options: CompilerOptions, additionalVerifiers?: () => void) => Diagnostic[]; + + function programCompile(typescriptFiles: string[], options: CompilerOptions): Diagnostic[] { + const program = createProgram(typescriptFiles, options, mockHost); program.emit(); return ts.getPreEmitDiagnostics(program); } - function buildMap(map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean): Diagnostic[] { - const diagnostics = compile(map, compilerOptions ? compilerOptions : { module: ModuleKind.CommonJS, declaration: true }); + function compile(fileset: Map, options: ts.CompilerOptions, compileFunc: VirtualCompilationFunction, additionalVerifiers?: () => void): Diagnostic[] { + loadSetIntoFs(virtualLib); + loadSetIntoFs(fileset); + + const typescriptFiles = filter(getKeys(fileset), name => endsWith(name, ".ts")); + return compileFunc(typescriptFiles, options, additionalVerifiers); + } + + function buildMap(compileFunc: VirtualCompilationFunction, map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean, additionalVerifiers?: () => void): Diagnostic[] { + const diagnostics = compile(map, compilerOptions ? compilerOptions : { module: ModuleKind.CommonJS, declaration: true }, compileFunc, additionalVerifiers); if (shouldError && diagnostics && diagnostics.length) { for (let i = 0; i < diagnostics.length; i++) { console.log(prettyPrintDiagnostic(diagnostics[i])); @@ -176,7 +244,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { virtualFs = {}; return diagnostics; } - buildMap(extensionAPI, extensionAPI, { module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: { "typescript": ["/lib/typescript.d.ts"] } }, /*shouldError*/true); + buildMap(programCompile, extensionAPI, extensionAPI, { module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: { "typescript": ["/lib/typescript.d.ts"] } }, /*shouldError*/true); const extensions: Map> = { "test-syntactic-lint": { @@ -414,15 +482,15 @@ export class Throws6 extends SyntacticLintWalker { // Compile each extension once with the extension API in its node_modules folder (also generating .d.ts and .js) forEachKey(extensions, extName => { loadSetIntoFsAt(extensionAPI, "/node_modules/typescript-plugin-api"); - buildMap(extensions[extName], extensions[extName], { module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: { "typescript": ["lib/typescript.d.ts"] } }, /*shouldError*/true); + buildMap(programCompile, extensions[extName], extensions[extName], { module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: { "typescript": ["lib/typescript.d.ts"] } }, /*shouldError*/true); }); /** * Setup a new test, where all extensions specified in the options hash are available in a node_modules folder, alongside the extension API */ - function test(sources: Map, options: ExtensionTestOptions) { + function test(sources: Map, options: ExtensionTestOptions, compileFunc: VirtualCompilationFunction = programCompile, additionalVerifiers?: (...args: any[]) => void) { forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/${ext}`)); - const diagnostics = buildMap(sources, sources, options.compilerOptions); + const diagnostics = buildMap(compileFunc, sources, sources, options.compilerOptions, /*shouldError*/false, additionalVerifiers); checkDiagnostics(diagnostics, options.expectedDiagnostics); } @@ -594,5 +662,133 @@ const x = 3 * 4; } }); }); + it("can run all lint plugins in the language service", () => { + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: [], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;} + const s: "foo" = "foo";`, + }, { + availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], + expectedDiagnostics: ["test-syntactic-lint", "test-semantic-lint", "test-semantic-lint"], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {a; b;}`, + }, { + availableExtensions: ["test-extension-arguments"], + expectedDiagnostics: ["test-extension-arguments", "test-extension-arguments"], + compilerOptions: { + extensions: { + "test-extension-arguments": ["a", "b"] + }, + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `interface Foo {b;} + interface Bar {a;} + const f: "foo" = "foo"; + let b: "bar" = "bar";`, + }, { + availableExtensions: ["test-multi-extension"], + expectedDiagnostics: ["test-multi-extension[IsNamedFoo]", "test-multi-extension[IsNamedBar]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueBar]", "test-multi-extension[IsValueBar]"], + compilerOptions: { + extensions: ["test-multi-extension"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + + test({ + "main.ts": `console.log("Hello, world!");`, + }, { + availableExtensions: [], + expectedDiagnostics: [6151, 6151], + compilerOptions: { + extensions: ["test-syntactic-lint", "test-semantic-lint"], + module: ModuleKind.CommonJS, + } + }, languageServiceCompile); + }); }); } From adccddf913acbd8d01ce58f2c5d099e6515e3553 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 11:14:39 -0700 Subject: [PATCH 17/49] Remove whitespace/trailing comma changes --- src/compiler/extensions.ts | 1 - tests/cases/unittests/extensionAPI.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 2a931cf7cb135..d0ec9731cb4f5 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -1,5 +1,4 @@ namespace ts { - export type LintErrorMethod = { (err: string): void; (err: string, span: Node): void; diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index 60e2c7411b634..c83bfee404d52 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -842,7 +842,7 @@ export class NoShortNames extends SyntacticLintWalker { } } } -` +`, }, "test-errors": { "package.json": `{ From af9c1e1993a365203f451896ba833155cfd83df3 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 11:19:15 -0700 Subject: [PATCH 18/49] Fix lint --- tests/cases/unittests/extensionAPI.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cases/unittests/extensionAPI.ts b/tests/cases/unittests/extensionAPI.ts index c83bfee404d52..aea114919b363 100644 --- a/tests/cases/unittests/extensionAPI.ts +++ b/tests/cases/unittests/extensionAPI.ts @@ -480,7 +480,7 @@ export default class extends LanguageServiceProvider { return { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{name: fileName, kind: '', kindModifiers: '', sortText: fileName}] + entries: [{name: fileName, kind: "", kindModifiers: "", sortText: fileName}] }; } getCompletionEntryDetails(fileName, position, entryName) { @@ -619,7 +619,7 @@ export default class extends LanguageServiceProvider { return { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{name: fileName, kind: '', kindModifiers: '', sortText: fileName}] + entries: [{name: fileName, kind: "", kindModifiers: "", sortText: fileName}] }; } getCompletionEntryDetailsFilter(fileName, position, entryName, previous) { @@ -1127,7 +1127,7 @@ of comparison only. assert.deepEqual(service.getCompletionsAtPosition(atotcFile, 0), { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{ name: atotcFile as Path, kind: '', kindModifiers: '', sortText: atotcFile }] + entries: [{ name: atotcFile as Path, kind: "", kindModifiers: "", sortText: atotcFile }] }, "Completions did not match!"); assert.deepEqual(service.getCompletionEntryDetails(atotcFile, 0, "first"), { name: atotcFile, From 908d9e786a0a26f9f3fb6c2a794ba491ee030ebd Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 11:21:43 -0700 Subject: [PATCH 19/49] Add missing members to type --- src/compiler/extensions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index d0ec9731cb4f5..a4ea4905d32e6 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -37,7 +37,8 @@ namespace ts { export interface LanguageServiceProvider {} export interface DocumentRegistry {} - export interface LanguageServiceProviderStatic { + export interface LanguageServiceProviderStatic extends BaseProviderStatic { + readonly ["extension-kind"]: ExtensionKind.LanguageService; new (state: { ts: typeof ts, args: any, host: LanguageServiceHost, service: LanguageService, registry: DocumentRegistry }): LanguageServiceProvider; } From a4762a8da51cd59dd7d6208c11cf5b27a7e4a934 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jun 2016 12:58:15 -0700 Subject: [PATCH 20/49] Add extension profiling functions --- src/compiler/extensions.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index db0f3aaa4f3e6..20d844830b095 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -50,6 +50,30 @@ namespace ts { name: string; args: any; kind: ExtensionKind; + profiles?: Map + } + + export interface ProfileData { + task: string; + start: number; + length: number; + } + + export function startExtensionProfile(ext: ExtensionBase, task: string) { + if (!ext.profiles) ext.profiles = {}; + + ext.profiles[task] = { + task, + start: +(new Date()), + length: -1 + }; + } + + export function completeExtensionProfile(ext: ExtensionBase, task: string) { + const endTime = +(new Date()); + Debug.assert(!!ext.profiles, "Completed profile, but extension has no started profiles."); + Debug.assert(!!ext.profiles[task], "Completed profile did not have a corresponding start."); + ext.profiles[task].length = endTime - ext.profiles[task].start; } // @kind(ExtensionKind.SyntacticLint) From 3036843b4ed93168571dbcebd68d3f0915f9b6de Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 30 Jun 2016 12:49:04 -0700 Subject: [PATCH 21/49] Rejigger references to make scripts compiler --- src/compiler/program.ts | 1 - src/compiler/types.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b83e1f0873f7f..dea306ab6e216 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,7 +1,6 @@ /// /// /// -/// namespace ts { /* @internal */ export let programTime = 0; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 439b9d324ea88..97af9d940bc78 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1,3 +1,4 @@ +/// namespace ts { export interface Map { From 69f0473ec8c720e09533e6106018d6fb46f39a9f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 30 Jun 2016 13:08:58 -0700 Subject: [PATCH 22/49] Add compiler option to enable extension profiling --- src/compiler/commandLineParser.ts | 5 +++++ src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/extensions.ts | 6 +++++- src/compiler/types.ts | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 3cc464634aa3f..d49ffcece52df 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -431,6 +431,11 @@ namespace ts { name: "strictNullChecks", type: "boolean", description: Diagnostics.Enable_strict_null_checks + }, + { + name: "profileExtensions", + type: "boolean", + description: Diagnostics.Enable_extension_profiling, } ]; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 64e95fd9cb69a..f7fe352227245 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2821,6 +2821,10 @@ "category": "Error", "code": 6152 }, + "Enable extension profiling.": { + "category": "Message", + "code": 6153 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 20d844830b095..492052f31ceef 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -124,11 +124,15 @@ namespace ts { const extensionLoadResults = map(extensionNames, name => { let result: any; let error: any; + let loadTime: number; + let startTime: number; if (host.loadExtension) { const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; if (resolved) { try { + startTime = +(new Date()); result = host.loadExtension(resolved.resolvedFileName); + loadTime = +(new Date()) - startTime; } catch (e) { error = e; @@ -160,7 +164,7 @@ namespace ts { const ext: ExtensionBase = { name: key !== "default" ? `${res.name}[${key}]` : res.name, args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], - kind: annotatedKind + kind: annotatedKind, }; switch (ext.kind) { case ExtensionKind.SemanticLint: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 97af9d940bc78..f9655e97e0ebb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2607,6 +2607,7 @@ namespace ts { /*@internal*/ version?: boolean; /*@internal*/ watch?: boolean; extensions?: string[] | Map; + profileExtensions?: boolean; [option: string]: CompilerOptionsValue | undefined; } From 680a75b192689830e14886d94a1969f848c2e582 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 30 Jun 2016 13:52:06 -0700 Subject: [PATCH 23/49] Add profiling for lint extensions --- src/compiler/diagnosticMessages.json | 8 +++++++ src/compiler/extensions.ts | 34 ++++++++++++++++++++++------ src/compiler/program.ts | 5 ++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f7fe352227245..d442a9c5d3d99 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2825,6 +2825,14 @@ "category": "Message", "code": 6153 }, + "PROFILE: Extension '{0}' begin '{1}'": { + "category": "Message", + "code": 6154 + }, + "PROFILE: Extension '{0}' end '{1}' ({2} ms)": { + "category": "Message", + "code": 6155 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 492052f31ceef..c434719217f35 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -50,7 +50,7 @@ namespace ts { name: string; args: any; kind: ExtensionKind; - profiles?: Map + profiles?: Map; } export interface ProfileData { @@ -59,7 +59,13 @@ namespace ts { length: number; } - export function startExtensionProfile(ext: ExtensionBase, task: string) { + function profileTrace(trace: (s: string) => void | undefined, message: DiagnosticMessage, ...args: any[]) { + if (trace) { + trace(flattenDiagnosticMessageText(createCompilerDiagnostic(message, ...args).messageText, (sys && sys.newLine || "\n"))); + } + } + + export function startExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { if (!ext.profiles) ext.profiles = {}; ext.profiles[task] = { @@ -67,13 +73,17 @@ namespace ts { start: +(new Date()), length: -1 }; + + profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, ext.name, task); } - export function completeExtensionProfile(ext: ExtensionBase, task: string) { + export function completeExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { const endTime = +(new Date()); Debug.assert(!!ext.profiles, "Completed profile, but extension has no started profiles."); Debug.assert(!!ext.profiles[task], "Completed profile did not have a corresponding start."); ext.profiles[task].length = endTime - ext.profiles[task].start; + + profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, ext.profiles[task].length.toFixed(4)); } // @kind(ExtensionKind.SyntacticLint) @@ -117,22 +127,32 @@ namespace ts { }; return cache; + function trace(message: DiagnosticMessage, ...args: any[]) { + profileTrace(host.trace, message, ...args); + } + function collectCompilerExtensions(): ExtensionCollectionMap { const extOptions = options.extensions; const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ""; + const shouldProfile = !!options.profileExtensions; const extensionLoadResults = map(extensionNames, name => { let result: any; let error: any; - let loadTime: number; - let startTime: number; if (host.loadExtension) { const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; if (resolved) { try { - startTime = +(new Date()); + let startTime: number; + if (shouldProfile) { + startTime = +(new Date()); + trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); + } result = host.loadExtension(resolved.resolvedFileName); - loadTime = +(new Date()) - startTime; + if (shouldProfile) { + const loadTime = +(new Date()) - startTime; + trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load", loadTime.toFixed(4)); + } } catch (e) { error = e; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index dea306ab6e216..0517cdba2c140 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1495,13 +1495,16 @@ namespace ts { const diagnostics: Diagnostic[] = []; let activeLint: UniqueLint; let parent: Node | undefined = undefined; + const shouldProfile = !!options.profileExtensions; for (let i = 0; i < lints.length; i++) { + if (shouldProfile) startExtensionProfile(lints[i], "construct", host.trace); if (kind === ExtensionKind.SemanticLint) { initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ ts, checker: getTypeChecker(), args: lints[i].args, host, program }), accepted: true }; } else if (kind === ExtensionKind.SyntacticLint) { initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ ts, args: lints[i].args, host, program }), accepted: true }; } + if (shouldProfile) completeExtensionProfile(lints[i], "construct", host.trace); } visitNode(sourceFile); @@ -1516,7 +1519,9 @@ namespace ts { if (initializedLints[i].accepted) { activeLint = initializedLints[i]; node.parent = parent; + if (shouldProfile) startExtensionProfile(lints[i], `visitNode|${getNodeId(node)}`, host.trace); activeLint.walker.visit(node, stop, error); + if (shouldProfile) completeExtensionProfile(lints[i], `visitNode|${getNodeId(node)}`, host.trace); if (activeLint.accepted) { oneAccepted = true; } From 19846c3b571befde03d64daf1445b3ecc2e91d12 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 11:42:52 -0700 Subject: [PATCH 24/49] Encapsulate all the extensions types in the extensions file, ref it from program so harness, scripts compile --- Jakefile.js | 1 + src/compiler/extensions.ts | 54 +++++++++++++++++++++++--------------- src/compiler/program.ts | 2 ++ src/compiler/types.ts | 8 ------ 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 78fadf4f34023..324cd36ffd4ca 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -66,6 +66,7 @@ var servicesSources = [ "declarationEmitter.ts", "emitter.ts", "program.ts", + "extensions.ts", "commandLineParser.ts", "diagnosticInformationMap.generated.ts" ].map(function (f) { diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index c434719217f35..a4a0dd32c947f 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -59,6 +59,39 @@ namespace ts { length: number; } + // @kind(ExtensionKind.SyntacticLint) + export interface SyntacticLintExtension extends ExtensionBase { + ctor: SyntacticLintProviderStatic; + } + + // @kind(ExtensionKind.SemanticLint) + export interface SemanticLintExtension extends ExtensionBase { + ctor: SemanticLintProviderStatic; + } + + export type Extension = SyntacticLintExtension | SemanticLintExtension; + + export interface ExtensionCache { + getCompilerExtensions(): ExtensionCollectionMap; + getExtensionLoadingDiagnostics(): Diagnostic[]; + } + + export interface ExtensionHost extends ModuleResolutionHost { + loadExtension?(name: string): any; + } + + export interface Program { + /** + * Gets a map of loaded compiler extensions + */ + getCompilerExtensions(): ExtensionCollectionMap; + } + + /* @internal */ + export interface TypeCheckerHost { + getCompilerExtensions(): ExtensionCollectionMap; + } + function profileTrace(trace: (s: string) => void | undefined, message: DiagnosticMessage, ...args: any[]) { if (trace) { trace(flattenDiagnosticMessageText(createCompilerDiagnostic(message, ...args).messageText, (sys && sys.newLine || "\n"))); @@ -86,27 +119,6 @@ namespace ts { profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, ext.profiles[task].length.toFixed(4)); } - // @kind(ExtensionKind.SyntacticLint) - export interface SyntacticLintExtension extends ExtensionBase { - ctor: SyntacticLintProviderStatic; - } - - // @kind(ExtensionKind.SemanticLint) - export interface SemanticLintExtension extends ExtensionBase { - ctor: SemanticLintProviderStatic; - } - - export type Extension = SyntacticLintExtension | SemanticLintExtension; - - export interface ExtensionCache { - getCompilerExtensions(): ExtensionCollectionMap; - getExtensionLoadingDiagnostics(): Diagnostic[]; - } - - export interface ExtensionHost extends ModuleResolutionHost { - loadExtension?(name: string): any; - } - export function createExtensionCache(options: CompilerOptions, host: ExtensionHost): ExtensionCache { const diagnostics: Diagnostic[] = []; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0517cdba2c140..ba4751122526e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,6 +1,8 @@ /// /// /// +/// + namespace ts { /* @internal */ export let programTime = 0; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f9655e97e0ebb..5265ef3f0d223 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1,5 +1,3 @@ -/// - namespace ts { export interface Map { [index: string]: T; @@ -1739,11 +1737,6 @@ namespace ts { */ getTypeChecker(): TypeChecker; - /** - * Gets a map of loaded compiler extensions - */ - getCompilerExtensions(): ExtensionCollectionMap; - /** * Gets only diagnostics reported while loading extensions */ @@ -1825,7 +1818,6 @@ namespace ts { getSourceFiles(): SourceFile[]; getSourceFile(fileName: string): SourceFile; getResolvedTypeReferenceDirectives(): Map; - getCompilerExtensions(): ExtensionCollectionMap; } export interface TypeChecker { From 8283881fb634dfc076a2bacee919281cbbead7c0 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 20:51:53 -0700 Subject: [PATCH 25/49] Write a test runner for discovering & running extensions tests, remove now-obsolete unittest --- Gulpfile.ts | 1 + Jakefile.js | 1 + src/harness/extensionRunner.ts | 442 ++++++++++ src/harness/runner.ts | 9 + src/harness/runnerbase.ts | 2 +- .../available/extension-api/index.ts | 33 + .../available/extension-api/package.json | 8 + .../extensions/available/test-errors/index.ts | 49 ++ .../available/test-errors/package.json | 7 + .../test-extension-arguments/index.ts | 14 + .../test-extension-arguments/package.json | 7 + .../available/test-multi-extension/index.ts | 47 ++ .../test-multi-extension/package.json | 7 + .../available/test-multierrors/index.ts | 29 + .../available/test-multierrors/package.json | 7 + .../available/test-semantic-lint/main.ts | 13 + .../available/test-semantic-lint/package.json | 7 + .../available/test-syntactic-lint/index.ts | 12 + .../test-syntactic-lint/package.json | 7 + .../cases/extensions/available/tsconfig.json | 9 + .../available/typescript/package.json | 3 + .../multiLintLoads/both-diagnostics.json | 10 + .../multiLintLoads/no-diagnostics.json | 10 + .../multiLintLoads/semantic-diagnostics.json | 10 + .../multiLintLoads/syntactic-diagnostics.json | 10 + .../test.json | 9 + .../scenarios/passArguments/array.json | 11 + .../reportsAllDIagnosticsFormats/test.json | 9 + .../test.json | 9 + .../scenarios/reportsFailedLoads/test.json | 9 + .../semanticLintLoads/no-diagnostics.json | 10 + .../semanticLintLoads/w-diagnostics.json | 10 + .../syntacticLintLoads/no-diagnostics.json | 10 + .../syntacticLintLoads/w-diagnostics.json | 10 + .../source/foo-bar-const-interface.ts | 4 + tests/cases/extensions/source/foo-bar-math.ts | 3 + tests/cases/extensions/source/foo-const.ts | 1 + .../extensions/source/foo-interface-const.ts | 2 + .../cases/extensions/source/foo-interface.ts | 1 + tests/cases/extensions/source/hello.ts | 1 + tests/cases/unittests/extensionAPI.ts | 794 ------------------ 41 files changed, 852 insertions(+), 795 deletions(-) create mode 100644 src/harness/extensionRunner.ts create mode 100644 tests/cases/extensions/available/extension-api/index.ts create mode 100644 tests/cases/extensions/available/extension-api/package.json create mode 100644 tests/cases/extensions/available/test-errors/index.ts create mode 100644 tests/cases/extensions/available/test-errors/package.json create mode 100644 tests/cases/extensions/available/test-extension-arguments/index.ts create mode 100644 tests/cases/extensions/available/test-extension-arguments/package.json create mode 100644 tests/cases/extensions/available/test-multi-extension/index.ts create mode 100644 tests/cases/extensions/available/test-multi-extension/package.json create mode 100644 tests/cases/extensions/available/test-multierrors/index.ts create mode 100644 tests/cases/extensions/available/test-multierrors/package.json create mode 100644 tests/cases/extensions/available/test-semantic-lint/main.ts create mode 100644 tests/cases/extensions/available/test-semantic-lint/package.json create mode 100644 tests/cases/extensions/available/test-syntactic-lint/index.ts create mode 100644 tests/cases/extensions/available/test-syntactic-lint/package.json create mode 100644 tests/cases/extensions/available/tsconfig.json create mode 100644 tests/cases/extensions/available/typescript/package.json create mode 100644 tests/cases/extensions/scenarios/multiLintLoads/both-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/multiLintLoads/no-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/multiLintLoads/semantic-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/multiLintLoads/syntactic-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/multipleRulesFoundInSingleExtension/test.json create mode 100644 tests/cases/extensions/scenarios/passArguments/array.json create mode 100644 tests/cases/extensions/scenarios/reportsAllDIagnosticsFormats/test.json create mode 100644 tests/cases/extensions/scenarios/reportsDiagnosticsWithShortnames/test.json create mode 100644 tests/cases/extensions/scenarios/reportsFailedLoads/test.json create mode 100644 tests/cases/extensions/scenarios/semanticLintLoads/no-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/semanticLintLoads/w-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/syntacticLintLoads/no-diagnostics.json create mode 100644 tests/cases/extensions/scenarios/syntacticLintLoads/w-diagnostics.json create mode 100644 tests/cases/extensions/source/foo-bar-const-interface.ts create mode 100644 tests/cases/extensions/source/foo-bar-math.ts create mode 100644 tests/cases/extensions/source/foo-const.ts create mode 100644 tests/cases/extensions/source/foo-interface-const.ts create mode 100644 tests/cases/extensions/source/foo-interface.ts create mode 100644 tests/cases/extensions/source/hello.ts delete mode 100644 tests/cases/unittests/extensionAPI.ts diff --git a/Gulpfile.ts b/Gulpfile.ts index 3c2702781b1ac..6446757293b5a 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -130,6 +130,7 @@ const harnessCoreSources = [ "typeWriter.ts", "fourslashRunner.ts", "projectsRunner.ts", + "extensionRunner.ts", "loggedIO.ts", "rwcRunner.ts", "test262Runner.ts", diff --git a/Jakefile.js b/Jakefile.js index 324cd36ffd4ca..709bb1fc49b2a 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -132,6 +132,7 @@ var harnessCoreSources = [ "typeWriter.ts", "fourslashRunner.ts", "projectsRunner.ts", + "extensionRunner.ts", "loggedIO.ts", "rwcRunner.ts", "test262Runner.ts", diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts new file mode 100644 index 0000000000000..1a8d2d981dd82 --- /dev/null +++ b/src/harness/extensionRunner.ts @@ -0,0 +1,442 @@ +/// +/// + +interface ExtensionTestConfig { + inputFiles: string[]; // Files from the source directory to include in the compilation + fourslashTest?: string; // File from the fourslash directory to test this compilation with + availableExtensions: string[]; // Extensions from the available directory to make available to the test + compilerOptions?: ts.CompilerOptions; // Optional compiler options to run with (usually at least "extensions" is specified) +} + +type VirtualCompilationFunction = (files: string[], options: ts.CompilerOptions) => Harness.Compiler.CompilerResult; + +class ExtensionRunner extends RunnerBase { + private basePath = "tests/cases/extensions"; + private scenarioPath = ts.combinePaths(this.basePath, "scenarios"); + private extensionPath = ts.combinePaths(this.basePath, "available"); + private sourcePath = ts.combinePaths(this.basePath, "source"); + private fourslashPath = ts.combinePaths(this.basePath, "fourslash"); + private extensionAPI: ts.Map = {}; + private extensions: ts.Map> = {}; + private virtualLib: ts.Map = {}; + private virtualFs: ts.Map = {}; + + prettyPrintDiagnostic(diagnostic: ts.Diagnostic): string { + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + if (diagnostic.file) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; + } + else { + return `!!!${message}`; + } + } + + private innerCanonicalName = ts.createGetCanonicalFileName(true); + private getCanonicalFileName = (fileName: string) => ts.toPath(fileName, "/", this.innerCanonicalName); + + loadSetIntoFsAt(set: ts.Map, prefix: string) { + ts.Debug.assert(!!prefix, "Prefix must exist"); + ts.Debug.assert(set !== this.virtualFs, "You cannot try to load the fs into itself."); + + // Load a fileset at the given location, but exclude the 'lib' kind files from the added set (they'll be reloaded at the top level before compilation) + ts.forEachKey(set, key => ts.forEachKey(this.virtualLib, path => key === path) ? void 0 : void (this.virtualFs[this.getCanonicalFileName(`${prefix}/${key}`)] = set[key])); + } + + loadSetIntoFs(set: ts.Map) { + ts.Debug.assert(set !== this.virtualFs, "You cannot try to load the fs into itself."); + ts.forEachKey(set, key => void (this.virtualFs[this.getCanonicalFileName(key)] = set[key])); + } + + private traces: string[] = []; + private mockHost: ts.CompilerHost = { + useCaseSensitiveFileNames: () => true, + getNewLine: () => "\n", + readFile: (path) => this.virtualFs[this.mockHost.getCanonicalFileName(path)], + writeFile: (path, content, foo, bar, baz) => { + this.virtualFs[this.mockHost.getCanonicalFileName(path)] = content; + }, + fileExists: (path) => { + return !!this.virtualFs[this.mockHost.getCanonicalFileName(path)]; + }, + directoryExists: (path) => { + const fullPath = this.mockHost.getCanonicalFileName(path); + return ts.forEach(ts.getKeys(this.virtualFs), key => ts.startsWith(key, fullPath)); + }, + getCurrentDirectory(): string { return "/"; }, + getSourceFile: (path, languageVersion, onError): ts.SourceFile => { + const fullPath = this.mockHost.getCanonicalFileName(path); + return ts.createSourceFile(fullPath, this.virtualFs[fullPath], languageVersion); + }, + getDefaultLibLocation: () => "/lib/", + getDefaultLibFileName: (options) => { + return ts.combinePaths(this.mockHost.getDefaultLibLocation(), ts.getDefaultLibFileName(options)); + }, + getCanonicalFileName: this.getCanonicalFileName, + getDirectories: (path) => { + path = this.mockHost.getCanonicalFileName(path); + return ts.filter(ts.map(ts.filter(ts.getKeys(this.virtualFs), + fullpath => ts.startsWith(fullpath, path) && fullpath.substr(path.length, 1) === "/"), + fullpath => fullpath.substr(path.length + 1).indexOf("/") >= 0 ? fullpath.substr(0, 1 + path.length + fullpath.substr(path.length + 1).indexOf("/")) : fullpath), + fullpath => fullpath.lastIndexOf(".") === -1); + }, + loadExtension: (path) => { + const fullPath = this.mockHost.getCanonicalFileName(path); + const m = { exports: {} }; + ((module, exports, require) => { eval(this.virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return this.mockHost.loadExtension( + this.mockHost.getCanonicalFileName( + ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS, moduleResolution: ts.ModuleResolutionKind.NodeJs }, this.mockHost, true).resolvedModule.resolvedFileName + ) + ); + } + ); + return m.exports; + }, + trace: (s) => { + this.traces.push(s); + } + }; + + makeMockLSHost(files: string[], options: ts.CompilerOptions): ts.LanguageServiceHost { + files = ts.filter(files, file => ts.endsWith(file, ".ts") && !ts.endsWith(file, ".d.ts") && !(file.indexOf("node_modules") >= 0)); + const host: ts.LanguageServiceHost = { + getCompilationSettings: () => options, + getScriptFileNames: () => files, + getScriptVersion: (fileName) => "1", + getScriptSnapshot: (fileName): ts.IScriptSnapshot => { + const fileContents = this.virtualFs[this.getCanonicalFileName(fileName)]; + if (!fileContents) return; + return ts.ScriptSnapshot.fromString(fileContents); + }, + getCurrentDirectory: () => "", + getDefaultLibFileName: () => "/lib/lib.d.ts", + loadExtension: (path) => { + const fullPath = this.getCanonicalFileName(path); + const m = { exports: {} }; + ((module, exports, require) => { eval(this.virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return host.loadExtension( + this.getCanonicalFileName( + ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS, moduleResolution: ts.ModuleResolutionKind.NodeJs }, this.mockHost, true).resolvedModule.resolvedFileName + ) + ); + } + ); + return m.exports; + }, + trace: (s) => { + this.traces.push(s); + } + }; + return host; + }; + + getTraces(): string[] { + const traces = this.traces; + this.traces = []; + return traces; + } + + languageServiceCompile(typescriptFiles: string[], options: ts.CompilerOptions): Harness.Compiler.CompilerResult { + const self = this; + const host = this.makeMockLSHost(ts.getKeys(this.virtualFs), options); + const service = ts.createLanguageService(host); + const fileResults: Harness.Compiler.GeneratedFile[] = []; + + const diagnostics = ts.concatenate(ts.concatenate( + service.getProgramDiagnostics(), + ts.flatten(ts.map(typescriptFiles, fileName => service.getSyntacticDiagnostics(this.getCanonicalFileName(fileName))))), + ts.flatten(ts.map(typescriptFiles, fileName => service.getSemanticDiagnostics(this.getCanonicalFileName(fileName))))); + + const emitResult = service.getProgram().emit(/*targetSourceFile*/undefined, writeFile); + + const allDiagnostics = ts.sortAndDeduplicateDiagnostics(ts.concatenate(diagnostics, emitResult.diagnostics)); + + return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, service.getProgram(), host.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); + + function writeFile(fileName: string, code: string, writeByteOrderMark: boolean, onError: (message: string) => void, sourceFiles: ts.SourceFile[]) { + fileResults.push({ + fileName, + writeByteOrderMark, + code + }); + self.mockHost.writeFile(fileName, code, writeByteOrderMark, onError, sourceFiles); + } + } + + programCompile(typescriptFiles: string[], options: ts.CompilerOptions): Harness.Compiler.CompilerResult { + const self = this; + const program = ts.createProgram(typescriptFiles, options, this.mockHost); + const fileResults: Harness.Compiler.GeneratedFile[] = []; + const diagnostics = ts.getPreEmitDiagnostics(program) + const emitResult = program.emit(/*targetSourceFile*/undefined, writeFile); + + const allDiagnostics = ts.sortAndDeduplicateDiagnostics(ts.concatenate(diagnostics, emitResult.diagnostics)); + + return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, program, this.mockHost.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); + function writeFile(fileName: string, code: string, writeByteOrderMark: boolean, onError: (message: string) => void, sourceFiles: ts.SourceFile[]) { + fileResults.push({ + fileName, + writeByteOrderMark, + code + }); + self.mockHost.writeFile(fileName, code, writeByteOrderMark, onError, sourceFiles); + } + } + + compile(fileset: ts.Map, options: ts.CompilerOptions, compileFunc: VirtualCompilationFunction): Harness.Compiler.CompilerResult { + this.loadSetIntoFs(this.virtualLib); + this.loadSetIntoFs(fileset); + + // Consider all TS files in the passed fileset as the root files, but not any under a node_modules folder + const typescriptFiles = ts.filter(ts.getKeys(fileset), name => ts.endsWith(name, ".ts") && !(name.indexOf("node_modules") >= 0)); + return compileFunc(typescriptFiles, options); + } + + buildMap(compileFunc: VirtualCompilationFunction, map: ts.Map, out: ts.Map, compilerOptions?: ts.CompilerOptions, shouldError?: boolean): Harness.Compiler.CompilerResult { + const results = this.compile(map, compilerOptions ? compilerOptions : { module: ts.ModuleKind.CommonJS, declaration: true }, compileFunc); + const diagnostics = results.errors; + if (shouldError && diagnostics && diagnostics.length) { + for (let i = 0; i < diagnostics.length; i++) { + console.log(this.prettyPrintDiagnostic(diagnostics[i])); + } + throw new Error("Compiling test harness extension API code resulted in errors."); + } + ts.copyMap(this.virtualFs, out); + this.virtualFs = {}; + return results; + } + + private loadExtensions() { + this.extensionAPI = { + "package.json": Harness.IO.readFile(ts.combinePaths(this.extensionPath, "extension-api/package.json")), + "index.ts": Harness.IO.readFile(ts.combinePaths(this.extensionPath, "extension-api/index.ts")), + }; + this.buildMap((str, opts) => this.programCompile(str, opts), this.extensionAPI, this.extensionAPI, { module: ts.ModuleKind.CommonJS, declaration: true }, /*shouldError*/true); + + ts.forEach(Harness.IO.getDirectories(this.extensionPath), path => { + if (path === "extension-api" || path === "typescript") return; // Since these are dependencies of every actual test extension, we handle them specially + const packageDir = ts.combinePaths(this.extensionPath, path); + const extensionFileset: ts.Map = {}; + const extensionFiles = this.enumerateFiles(packageDir, /*regex*/ undefined, { recursive: true }); + ts.forEach(extensionFiles, name => { + const shortName = name.substring(packageDir.length + 1); + extensionFileset[shortName] = Harness.IO.readFile(name); + }); + this.loadSetIntoFsAt(this.extensionAPI, "/node_modules/extension-api"); + + this.buildMap((str, opts) => this.programCompile(str, opts), extensionFileset, extensionFileset, { module: ts.ModuleKind.CommonJS, declaration: true }, /*shouldError*/true); + this.extensions[path] = extensionFileset; + }); + } + + constructor() { + super(); + const {content: libContent} = Harness.getDefaultLibraryFile(Harness.IO); + const tsLibContents = Harness.IO.readFile("built/local/typescript.d.ts"); + this.virtualLib = { + "/lib/lib.d.ts": libContent, + "/node_modules/typescript/index.d.ts": tsLibContents + }; + this.loadExtensions(); + } + + kind(): "extension" { + return "extension"; + } + + enumerateTestFiles(): string[] { + return this.enumerateFiles(this.scenarioPath, /\.json$/, { recursive: true }); + } + + /** Setup the runner's tests so that they are ready to be executed by the harness + * The first test should be a describe/it block that sets up the harness's compiler instance appropriately + */ + public initializeTests(): void { + describe("Compiler Extensions", () => { + if (this.tests.length === 0) { + const testFiles = this.enumerateTestFiles(); + testFiles.forEach(fn => { + this.runTest(fn); + }); + } + else { + this.tests.forEach(test => this.runTest(test)); + } + }); + } + + getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string { + return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : ""; + } + + private compileTargets: [string, VirtualCompilationFunction][] = [["CompilerHost", (str, opts) => this.programCompile(str, opts)], ["LanguageServiceHost", (str, opts) => this.languageServiceCompile(str, opts)]]; + /** + * Extensions tests are complete end-to-end tests with multiple compilations to prepare a test + * + * Tests need to be: + * Run under both `compilerHost` and `languageServiceHost` environments + * - When under LSHost, verify all fourslash test-type results included in the test + * - Verify output baseline + * - Verify error baseline + * - Verify sourcemaps if need be + * - Verify traces if need be + */ + private runTest(caseName: string) { + const caseNameNoExtension = caseName.replace(/\.json$/, ""); + const shortCasePath = caseName.substring(this.scenarioPath.length + 1); + const testConfigText = Harness.IO.readFile(caseName); + const testConfig: ExtensionTestConfig = JSON.parse(testConfigText); + const inputSources: ts.Map = {}; + const inputTestFiles: Harness.Compiler.TestFile[] = []; + ts.forEach(testConfig.inputFiles, name => { + inputSources[name] = Harness.IO.readFile(ts.combinePaths(this.sourcePath, name)); + inputTestFiles.push({ + unitName: this.getCanonicalFileName(name), + content: inputSources[name] + }); + }); + + ts.forEach(this.compileTargets, ([name, compileCb]) => { + describe(`${caseNameNoExtension} - ${name}`, () => { + this.traces = []; // Clear out any traces from tests which made traces, but didn't specify traceResolution or profileExtensions + const sources: ts.Map = {}; + ts.copyMap(inputSources, sources); + ts.forEach(testConfig.availableExtensions, ext => this.loadSetIntoFsAt(this.extensions[ext], `/node_modules/${ext}`)); + const result = this.buildMap(compileCb, sources, sources, testConfig.compilerOptions, /*shouldError*/false); + + const errorsTestName = `Correct errors`; + it(errorsTestName, () => { + Harness.Baseline.runBaseline(errorsTestName, `${name}/${shortCasePath}.errors.txt`, () => { + /* tslint:disable:no-null-keyword */ + if (result.errors.length === 0) return null; + /* tslint:enable:no-null-keyword */ + return Harness.Compiler.getErrorBaseline(inputTestFiles, result.errors); + }); + }); + + const traceTestName = `Correct traces`; + it(traceTestName, () => { + if (!(testConfig.compilerOptions.traceResolution || testConfig.compilerOptions.profileExtensions)) { + return; + } + Harness.Baseline.runBaseline(traceTestName, `${name}/${shortCasePath}.trace.txt`, (): string => { + return (result.traceResults || []).join("\n"); + }); + }); + + const sourcemapTestName = `Correct sourcemap content`; + it(sourcemapTestName, () => { + if (!(testConfig.compilerOptions.sourceMap || testConfig.compilerOptions.inlineSourceMap)) { + return; + } + Harness.Baseline.runBaseline(sourcemapTestName,`${name}/${shortCasePath}.sourcemap.txt`, () => { + const record = result.getSourceMapRecord(); + if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && record === undefined) { + // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + return record; + }); + }); + + const sourcemapOutputTestName = `Correct sourcemap output`; + it(sourcemapOutputTestName, () => { + if (testConfig.compilerOptions.inlineSourceMap) { + if (result.sourceMaps.length > 0) { + throw new Error("No sourcemap files should be generated if inlineSourceMaps was set."); + } + return; + } + else if (!testConfig.compilerOptions.sourceMap) { + return; + } + if (result.sourceMaps.length !== result.files.length) { + throw new Error("Number of sourcemap files should be same as js files."); + } + + Harness.Baseline.runBaseline(sourcemapOutputTestName, `${name}/${shortCasePath}.js.map`, () => { + if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { + // We need to return null here or the runBaseLine will actually create a empty file. + // Baselining isn't required here because there is no output. + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + + let sourceMapCode = ""; + for (let i = 0; i < result.sourceMaps.length; i++) { + sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n"; + sourceMapCode += this.getByteOrderMarkText(result.sourceMaps[i]); + sourceMapCode += result.sourceMaps[i].code; + } + + return sourceMapCode; + }); + }); + + const emitOutputTestName = `Correct emit (JS/DTS)`; + it(emitOutputTestName, () => { + if (!ts.forEach(testConfig.inputFiles, name => !ts.endsWith(name, ".d.ts"))) { + return; + } + if (!testConfig.compilerOptions.noEmit && result.files.length === 0 && result.errors.length === 0) { + throw new Error("Expected at least one js file to be emitted or at least one error to be created."); + } + + // check js output + Harness.Baseline.runBaseline(emitOutputTestName, `${name}/${shortCasePath}.js`, () => { + let tsCode = ""; + const tsSources = inputTestFiles; + if (tsSources.length > 1) { + tsCode += "//// [" + caseNameNoExtension + "] ////\r\n\r\n"; + } + for (let i = 0; i < tsSources.length; i++) { + tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n"; + tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : ""); + } + + let jsCode = ""; + for (let i = 0; i < result.files.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n"; + jsCode += this.getByteOrderMarkText(result.files[i]); + jsCode += result.files[i].code; + } + + if (result.declFilesCode.length > 0) { + jsCode += "\r\n\r\n"; + for (let i = 0; i < result.declFilesCode.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n"; + jsCode += this.getByteOrderMarkText(result.declFilesCode[i]); + jsCode += result.declFilesCode[i].code; + } + } + + if (jsCode.length > 0) { + return tsCode + "\r\n\r\n" + jsCode; + } + else { + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + }); + }); + }); + }); + + if (testConfig.fourslashTest) { + describe(`${caseNameNoExtension} - Fourslash`, () => { + // TODO + }); + } + } +} \ No newline at end of file diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 1c36614e61fb0..687710f9bb697 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -17,6 +17,7 @@ /// /// /// +/// /// /// @@ -58,6 +59,8 @@ function createRunner(kind: TestRunnerKind): RunnerBase { return new RWCRunner(); case "test262": return new Test262BaselineRunner(); + case "extension": + return new ExtensionRunner(); } } @@ -155,6 +158,9 @@ if (testConfigContent !== "") { case "test262": runners.push(new Test262BaselineRunner()); break; + case "extension": + runners.push(new ExtensionRunner()); + break; } } } @@ -176,6 +182,9 @@ if (runners.length === 0) { runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess)); runners.push(new FourSlashRunner(FourSlashTestType.Server)); // runners.push(new GeneratedFourslashRunner()); + + // extension + runners.push(new ExtensionRunner()); } if (taskConfigsFolder) { diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index 346382b7a5721..35d345463fde7 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -1,7 +1,7 @@ /// -type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262"; +type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262" | "extension"; type CompilerTestKind = "conformance" | "compiler"; type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server"; diff --git a/tests/cases/extensions/available/extension-api/index.ts b/tests/cases/extensions/available/extension-api/index.ts new file mode 100644 index 0000000000000..5939ebba77c42 --- /dev/null +++ b/tests/cases/extensions/available/extension-api/index.ts @@ -0,0 +1,33 @@ +import * as tsi from "typescript"; + +export abstract class SyntacticLintWalker implements tsi.LintWalker { + static "extension-kind": tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; + protected ts: typeof tsi; + protected args: any; + protected host: tsi.CompilerHost; + protected program: tsi.Program; + constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program}) { + this.ts = state.ts; + this.args = state.args; + this.host = state.host; + this.program = state.program; + } + abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; +} + +export abstract class SemanticLintWalker implements tsi.LintWalker { + static "extension-kind": tsi.ExtensionKind.SemanticLint = "semantic-lint"; + protected ts: typeof tsi; + protected args: any; + protected host: tsi.CompilerHost; + protected program: tsi.Program; + protected checker: tsi.TypeChecker; + constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program, checker: tsi.TypeChecker}) { + this.ts = state.ts; + this.args = state.args; + this.host = state.host; + this.program = state.program; + this.checker = state.checker; + } + abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; +} \ No newline at end of file diff --git a/tests/cases/extensions/available/extension-api/package.json b/tests/cases/extensions/available/extension-api/package.json new file mode 100644 index 0000000000000..4db5f4be792e7 --- /dev/null +++ b/tests/cases/extensions/available/extension-api/package.json @@ -0,0 +1,8 @@ +{ + "name": "extension-api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "", + "types": "index.d.ts" +} \ No newline at end of file diff --git a/tests/cases/extensions/available/test-errors/index.ts b/tests/cases/extensions/available/test-errors/index.ts new file mode 100644 index 0000000000000..4548b4282db6b --- /dev/null +++ b/tests/cases/extensions/available/test-errors/index.ts @@ -0,0 +1,49 @@ +import {SyntacticLintWalker} from "extension-api"; + +export default class Throws extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed."); + stop(); + } +} + +export class Throws2 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS2", "Not allowed."); + stop(); + } +} + +export class Throws3 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS3", "Not allowed.", node); + stop(); + } +} + +export class Throws4 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("THROWS4", "Not allowed.", 0, 10); + stop(); + } +} + +export class Throws5 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed.", node); + stop(); + } +} + +export class Throws6 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + error("Not allowed.", 0, 10); + stop(); + } +} \ No newline at end of file diff --git a/tests/cases/extensions/available/test-errors/package.json b/tests/cases/extensions/available/test-errors/package.json new file mode 100644 index 0000000000000..b3df9c7b4d305 --- /dev/null +++ b/tests/cases/extensions/available/test-errors/package.json @@ -0,0 +1,7 @@ +{ + "name": "test-errors", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "" +} \ No newline at end of file diff --git a/tests/cases/extensions/available/test-extension-arguments/index.ts b/tests/cases/extensions/available/test-extension-arguments/index.ts new file mode 100644 index 0000000000000..2a1c7d8ff3b89 --- /dev/null +++ b/tests/cases/extensions/available/test-extension-arguments/index.ts @@ -0,0 +1,14 @@ +import {SyntacticLintWalker} from "extension-api"; + +export default class IsNamedX extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, stop, error) { + if (node.kind === this.ts.SyntaxKind.Identifier) { + for (let i = 0; i - -namespace ts { - describe("Extension API", () => { - - function prettyPrintDiagnostic(diagnostic: Diagnostic): string { - const message = flattenDiagnosticMessageText(diagnostic.messageText, "\n"); - if (diagnostic.file) { - const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); - return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; - } - else { - return `!!!${message}`; - } - } - - function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: (number | string)[]) { - if (!expectedDiagnosticCodes) { - return; - } - - for (let i = 0; i < expectedDiagnosticCodes.length; i++) { - assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic: (expected) [${expectedDiagnosticCodes.toString()}] vs (actual) [${map(diagnostics, d => d.code).toString()}]. First diagnostic: ${prettyPrintDiagnostic(diagnostics[0])}`); - } - if (expectedDiagnosticCodes.length === 0 && diagnostics.length) { - throw new Error(`Unexpected diagnostic (${map(diagnostics, d => d.code).toString()}): ${prettyPrintDiagnostic(diagnostics[0])}`); - } - assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); - } - - interface ExtensionTestOptions { - compilerOptions: CompilerOptions; - availableExtensions: string[]; - expectedDiagnostics: (number | string)[]; - } - - const {content: libContent} = Harness.getDefaultLibraryFile(Harness.IO); - const tsLibContents = Harness.IO.readFile("built/local/typescript_standalone.d.ts"); - const virtualLib: Map = { - "/lib/lib.d.ts": libContent, - "/lib/typescript.d.ts": tsLibContents - }; - - let virtualFs: Map = {}; - - const innerCanonicalName = createGetCanonicalFileName(true); - const getCanonicalFileName = (fileName: string) => toPath(fileName, "/", innerCanonicalName); - - function loadSetIntoFsAt(set: Map, prefix: string) { - // Load a fileset at the given location, but exclude the /lib/ dir from the added set - forEachKey(set, key => startsWith(key, "/lib/") ? void 0 : void (virtualFs[getCanonicalFileName(prefix + key)] = set[key])); - } - - function loadSetIntoFs(set: Map) { - forEachKey(set, key => void (virtualFs[getCanonicalFileName(key)] = set[key])); - } - - const mockHost: CompilerHost = { - useCaseSensitiveFileNames() { return true; }, - getNewLine() { return "\n"; }, - readFile(path) { return virtualFs[mockHost.getCanonicalFileName(path)]; }, - writeFile(path, content, foo, bar, baz) { - virtualFs[mockHost.getCanonicalFileName(path)] = content; - }, - fileExists(path) { - return !!virtualFs[mockHost.getCanonicalFileName(path)]; - }, - directoryExists(path) { - const fullPath = mockHost.getCanonicalFileName(path); - return forEach(getKeys(virtualFs), key => startsWith(key, fullPath)); - }, - getCurrentDirectory(): string { return "/"; }, - getSourceFile(path, languageVersion, onError): SourceFile { - const fullPath = mockHost.getCanonicalFileName(path); - return createSourceFile(fullPath, virtualFs[fullPath], languageVersion); - }, - getDefaultLibLocation() { - return "/lib/"; - }, - getDefaultLibFileName(options) { - return combinePaths(mockHost.getDefaultLibLocation(), getDefaultLibFileName(options)); - }, - getCanonicalFileName, - getDirectories(path) { - path = mockHost.getCanonicalFileName(path); - return filter(map(filter(getKeys(virtualFs), - fullpath => startsWith(fullpath, path) && fullpath.substr(path.length, 1) === "/"), - fullpath => fullpath.substr(path.length + 1).indexOf("/") >= 0 ? fullpath.substr(0, 1 + path.length + fullpath.substr(path.length + 1).indexOf("/")) : fullpath), - fullpath => fullpath.lastIndexOf(".") === -1); - }, - loadExtension(path) { - const fullPath = mockHost.getCanonicalFileName(path); - const m = { exports: {} }; - ((module, exports, require) => { eval(virtualFs[fullPath]); })( - m, - m.exports, - (name: string) => { - return mockHost.loadExtension( - mockHost.getCanonicalFileName( - resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName - ) - ); - } - ); - return m.exports; - }, - trace(s) { - console.log(s); - } - }; - - function makeMockLSHost(files: string[], options: CompilerOptions): LanguageServiceHost { - files = filter(files, file => !endsWith(file, ".json")); - const host: LanguageServiceHost = { - getCompilationSettings: () => options, - getScriptFileNames: () => files, - getScriptVersion(fileName) { - return "1"; - }, - getScriptSnapshot(fileName): IScriptSnapshot { - const fileContents = virtualFs[getCanonicalFileName(fileName)]; - if (!fileContents) return; - return ScriptSnapshot.fromString(fileContents); - }, - getCurrentDirectory() { - return ""; - }, - getDefaultLibFileName() { - return "/lib/lib.d.ts"; - }, - loadExtension(path) { - const fullPath = getCanonicalFileName(path); - const m = { exports: {} }; - ((module, exports, require) => { eval(virtualFs[fullPath]); })( - m, - m.exports, - (name: string) => { - return host.loadExtension( - getCanonicalFileName( - resolveModuleName(name, fullPath, { module: ModuleKind.CommonJS }, mockHost, true).resolvedModule.resolvedFileName - ) - ); - } - ); - return m.exports; - }, - trace(s) { - console.log(s); - } - }; - return host; - }; - - const extensionAPI: Map = { - "package.json": `{ - "name": "typescript-plugin-api", - "version": "1.0.0", - "description": "", - "main": "index.js", - "author": "", - "types": "index.d.ts" -}`, - "index.ts": ` -import * as tsi from "typescript"; - -export abstract class SyntacticLintWalker implements tsi.LintWalker { - static "extension-kind": tsi.ExtensionKind.SyntacticLint = "syntactic-lint"; - protected ts: typeof tsi; - protected args: any; - protected host: tsi.CompilerHost; - protected program: tsi.Program; - constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program}) { - this.ts = state.ts; - this.args = state.args; - this.host = state.host; - this.program = state.program; - } - abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; -} - -export abstract class SemanticLintWalker implements tsi.LintWalker { - static "extension-kind": tsi.ExtensionKind.SemanticLint = "semantic-lint"; - protected ts: typeof tsi; - protected args: any; - protected host: tsi.CompilerHost; - protected program: tsi.Program; - protected checker: tsi.TypeChecker; - constructor(state: {ts: typeof tsi, args: any, host: tsi.CompilerHost, program: tsi.Program, checker: tsi.TypeChecker}) { - this.ts = state.ts; - this.args = state.args; - this.host = state.host; - this.program = state.program; - this.checker = state.checker; - } - abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; -} -` - }; - // Compile extension API once (generating .d.ts and .js) - - function languageServiceCompile(typescriptFiles: string[], options: CompilerOptions, additionalVerifiers?: (service: LanguageService) => void): Diagnostic[] { - options.allowJs = true; - options.noEmit = true; - const service = createLanguageService(makeMockLSHost(getKeys(virtualFs), options)); - - if (additionalVerifiers) { - additionalVerifiers(service); - } - - const diagnostics = concatenate(concatenate( - service.getProgramDiagnostics(), - flatten(map(typescriptFiles, fileName => service.getSyntacticDiagnostics(getCanonicalFileName(fileName))))), - flatten(map(typescriptFiles, fileName => service.getSemanticDiagnostics(getCanonicalFileName(fileName))))); - - return sortAndDeduplicateDiagnostics(diagnostics); - } - - type VirtualCompilationFunction = (files: string[], options: CompilerOptions, additionalVerifiers?: () => void) => Diagnostic[]; - - function programCompile(typescriptFiles: string[], options: CompilerOptions): Diagnostic[] { - const program = createProgram(typescriptFiles, options, mockHost); - program.emit(); - - return ts.getPreEmitDiagnostics(program); - } - - function compile(fileset: Map, options: ts.CompilerOptions, compileFunc: VirtualCompilationFunction, additionalVerifiers?: () => void): Diagnostic[] { - loadSetIntoFs(virtualLib); - loadSetIntoFs(fileset); - - const typescriptFiles = filter(getKeys(fileset), name => endsWith(name, ".ts")); - return compileFunc(typescriptFiles, options, additionalVerifiers); - } - - function buildMap(compileFunc: VirtualCompilationFunction, map: Map, out: Map, compilerOptions?: CompilerOptions, shouldError?: boolean, additionalVerifiers?: () => void): Diagnostic[] { - const diagnostics = compile(map, compilerOptions ? compilerOptions : { module: ModuleKind.CommonJS, declaration: true }, compileFunc, additionalVerifiers); - if (shouldError && diagnostics && diagnostics.length) { - for (let i = 0; i < diagnostics.length; i++) { - console.log(prettyPrintDiagnostic(diagnostics[i])); - } - throw new Error("Compiling test harness extension API code resulted in errors."); - } - copyMap(virtualFs, out); - virtualFs = {}; - return diagnostics; - } - buildMap(programCompile, extensionAPI, extensionAPI, { module: ModuleKind.CommonJS, declaration: true, baseUrl: ".", paths: { "typescript": ["/lib/typescript.d.ts"] } }, /*shouldError*/true); - - const extensions: Map> = { - "test-syntactic-lint": { - "package.json": `{ - "name": "test-syntactic-lint", - "version": "1.0.0", - "description": "", - "main": "index.js", - "author": "" -}`, - "index.ts": ` -import {SyntacticLintWalker} from "typescript-plugin-api"; - -export default class IsNamedFoo extends SyntacticLintWalker { - constructor(state) { super(state); } - visit(node, stop, error) { - if (node.kind === this.ts.SyntaxKind.Identifier) { - if (node.text.toLowerCase() === "foo") { - error("Identifier 'foo' is forbidden.", node); - } - } - } -} -`, - }, - "test-semantic-lint": { - "package.json": `{ - "name": "test-semantic-lint", - "version": "1.0.0", - "description": "", - "main": "main.js", - "author": "" -}`, - "main.ts": ` -import {SemanticLintWalker} from "typescript-plugin-api"; - -export default class IsValueFoo extends SemanticLintWalker { - constructor(state) { super(state); } - visit(node, stop, error) { - const type = this.checker.getTypeAtLocation(node); - if (type.flags & this.ts.TypeFlags.StringLiteral) { - if (node.text === "foo") { - error("String literal type 'foo' is forbidden.", node); - } - } - } -} -`, - }, - "test-extension-arguments": { - "package.json": `{ - "name": "test-extension-arguments", - "version": "1.0.0", - "description": "", - "main": "index.js", - "author": "" -}`, - "index.ts": ` -import {SyntacticLintWalker} from "typescript-plugin-api"; - -export default class IsNamedX extends SyntacticLintWalker { - constructor(state) { super(state); } - visit(node, stop, error) { - if (node.kind === this.ts.SyntaxKind.Identifier) { - for (let i = 0; i { - loadSetIntoFsAt(extensionAPI, "/node_modules/typescript-plugin-api"); - buildMap(programCompile, extensions[extName], extensions[extName], { module: ModuleKind.CommonJS, declaration: true, experimentalDecorators: true, baseUrl: "/", paths: { "typescript": ["lib/typescript.d.ts"] } }, /*shouldError*/true); - }); - - /** - * Setup a new test, where all extensions specified in the options hash are available in a node_modules folder, alongside the extension API - */ - function test(sources: Map, options: ExtensionTestOptions, compileFunc: VirtualCompilationFunction = programCompile, additionalVerifiers?: (...args: any[]) => void) { - forEach(options.availableExtensions, ext => loadSetIntoFsAt(extensions[ext], `/node_modules/${ext}`)); - const diagnostics = buildMap(compileFunc, sources, sources, options.compilerOptions, /*shouldError*/false, additionalVerifiers); - checkDiagnostics(diagnostics, options.expectedDiagnostics); - } - - it("can load syntactic lint extensions", () => { - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-syntactic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-syntactic-lint"], - module: ModuleKind.CommonJS, - } - }); - - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-syntactic-lint"], - expectedDiagnostics: ["test-syntactic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("can load semantic lint extensions", () => { - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-semantic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - - test({ - "main.ts": `const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-semantic-lint"], - expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("can load semantic & syntactic lint extensions simultaneously", () => { - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - - test({ - "main.ts": `const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-syntactic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - - test({ - "main.ts": `interface Foo {a; b;} - const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-syntactic-lint", "test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("can pass arguments to lint rules", () => { - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-extension-arguments"], - expectedDiagnostics: ["test-extension-arguments", "test-extension-arguments"], - compilerOptions: { - extensions: { - "test-extension-arguments": ["a", "b"] - }, - module: ModuleKind.CommonJS, - } - }); - }); - - it("can load multiple rules from a single extension", () => { - test({ - "main.ts": `interface Foo {b;} - interface Bar {a;} - const f: "foo" = "foo"; - let b: "bar" = "bar";`, - }, { - availableExtensions: ["test-multi-extension"], - expectedDiagnostics: ["test-multi-extension[IsNamedFoo]", "test-multi-extension[IsNamedBar]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueBar]", "test-multi-extension[IsValueBar]"], - compilerOptions: { - extensions: ["test-multi-extension"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("can error when it fails to load a lint rule", () => { - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: [], - expectedDiagnostics: [6151, 6151], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("can handle multiple diagnostics from a single rule", () => { - test({ - "main.ts": ` -const foo = 3; -const bar = 4; -const x = 3 * 4; - `, - }, { - availableExtensions: ["test-multierrors"], - expectedDiagnostics: ["test-multierrors(FOO)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors(BAR)", "test-multierrors[NoShortNames](SHORT)", "test-multierrors[NoShortNames](SINGLE)"], - compilerOptions: { - extensions: ["test-multierrors"], - module: ModuleKind.CommonJS, - } - }); - }); - - it("sucessfully handles all six avalable error method overloads", () => { - test({ - "main.ts": `console.log('Hello, world!')`, - }, { - availableExtensions: ["test-errors"], - expectedDiagnostics: ["test-errors", "test-errors[Throws2](THROWS2)", "test-errors[Throws3](THROWS3)", "test-errors[Throws5]", "test-errors[Throws4](THROWS4)", "test-errors[Throws6]"], - compilerOptions: { - extensions: ["test-errors"], - module: ModuleKind.CommonJS, - } - }); - }); - it("can run all lint plugins in the language service", () => { - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-syntactic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-syntactic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-syntactic-lint"], - expectedDiagnostics: ["test-syntactic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-semantic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-semantic-lint"], - expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: [], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-syntactic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `interface Foo {a; b;} - const s: "foo" = "foo";`, - }, { - availableExtensions: ["test-syntactic-lint", "test-semantic-lint"], - expectedDiagnostics: ["test-syntactic-lint", "test-semantic-lint", "test-semantic-lint"], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `interface Foo {a; b;}`, - }, { - availableExtensions: ["test-extension-arguments"], - expectedDiagnostics: ["test-extension-arguments", "test-extension-arguments"], - compilerOptions: { - extensions: { - "test-extension-arguments": ["a", "b"] - }, - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `interface Foo {b;} - interface Bar {a;} - const f: "foo" = "foo"; - let b: "bar" = "bar";`, - }, { - availableExtensions: ["test-multi-extension"], - expectedDiagnostics: ["test-multi-extension[IsNamedFoo]", "test-multi-extension[IsNamedBar]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueFoo]", "test-multi-extension[IsValueBar]", "test-multi-extension[IsValueBar]"], - compilerOptions: { - extensions: ["test-multi-extension"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - - test({ - "main.ts": `console.log("Hello, world!");`, - }, { - availableExtensions: [], - expectedDiagnostics: [6151, 6151], - compilerOptions: { - extensions: ["test-syntactic-lint", "test-semantic-lint"], - module: ModuleKind.CommonJS, - } - }, languageServiceCompile); - }); - }); -} From 4fd46c84e72af5ebf2ead9d436de82be315e3313 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 20:59:31 -0700 Subject: [PATCH 26/49] Do away with the Extension diagnostic category --- src/compiler/tsc.ts | 12 +++++++----- src/compiler/types.ts | 1 - src/compiler/utilities.ts | 8 ++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index e1f2543db98bc..e6410d75f8413 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -115,7 +115,7 @@ namespace ts { } const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - if (diagnostic.category === DiagnosticCategory.Extension) { + if (typeof diagnostic.category === "string") { output += `${ category } ${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; } else { @@ -609,15 +609,17 @@ namespace ts { // First get and report any syntactic errors. diagnostics = program.getSyntacticDiagnostics(); - // Count extension diagnostics and ignore them for determining continued error reporting - const extensionDiagnostics = filter(diagnostics, d => d.category === DiagnosticCategory.Extension).length; + // Count warnings and ignore them for determining continued error reporting + const warningsCount = filter(diagnostics, d => d.category === DiagnosticCategory.Warning).length; // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. - if (diagnostics.length === extensionDiagnostics) { + if (diagnostics.length === warningsCount) { diagnostics = diagnostics.concat(program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics())); - if (diagnostics.length === extensionDiagnostics) { + const warningsCount = filter(diagnostics, d => d.category === DiagnosticCategory.Warning).length; + + if (diagnostics.length === warningsCount) { diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5265ef3f0d223..98fd547152f55 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2512,7 +2512,6 @@ namespace ts { Warning, Error, Message, - Extension, } export enum ModuleResolutionKind { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1aa8a047b6011..6ca543b240400 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -456,20 +456,20 @@ namespace ts { return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2); } - export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string): Diagnostic { + export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string, isError?: boolean): Diagnostic { const sourceFile = getSourceFileOfNode(node); const span = getErrorSpanForNode(sourceFile, node); - return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length); + return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length, isError); } - export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number): Diagnostic { + export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number, isError?: boolean): Diagnostic { return { file: file, messageText: message, code: extension, start: start, length: length, - category: DiagnosticCategory.Extension + category: isError ? DiagnosticCategory.Error : DiagnosticCategory.Warning }; } From 7eca070337de1a0960923a1a817fea02ebbf9cd6 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 21:12:22 -0700 Subject: [PATCH 27/49] First set of baselines for the new test runner --- src/harness/extensionRunner.ts | 2 +- .../both-diagnostics.errors.txt | 14 +++++ .../multiLintLoads/both-diagnostics.js | 6 +++ .../multiLintLoads/both-diagnostics.trace.txt | 18 +++++++ .../multiLintLoads/no-diagnostics.js | 5 ++ .../multiLintLoads/no-diagnostics.trace.txt | 18 +++++++ .../semantic-diagnostics.errors.txt | 10 ++++ .../multiLintLoads/semantic-diagnostics.js | 5 ++ .../semantic-diagnostics.trace.txt | 18 +++++++ .../syntactic-diagnostics.errors.txt | 7 +++ .../multiLintLoads/syntactic-diagnostics.js | 4 ++ .../syntactic-diagnostics.trace.txt | 18 +++++++ .../test.errors.txt | 25 +++++++++ .../test.js | 9 ++++ .../passArguments/array.errors.txt | 10 ++++ .../CompilerHost/passArguments/array.js | 4 ++ .../test.errors.txt | 20 +++++++ .../reportsAllDIagnosticsFormats/test.js | 5 ++ .../test.errors.txt | 21 ++++++++ .../reportsDiagnosticsWithShortnames/test.js | 9 ++++ .../reportsFailedLoads/test.errors.txt | 20 +++++++ .../CompilerHost/reportsFailedLoads/test.js | 5 ++ .../semanticLintLoads/no-diagnostics.js | 5 ++ .../no-diagnostics.trace.txt | 9 ++++ .../w-diagnostics.errors.txt | 10 ++++ .../semanticLintLoads/w-diagnostics.js | 5 ++ .../semanticLintLoads/w-diagnostics.trace.txt | 9 ++++ .../syntacticLintLoads/no-diagnostics.js | 5 ++ .../no-diagnostics.trace.txt | 9 ++++ .../w-diagnostics.errors.txt | 7 +++ .../syntacticLintLoads/w-diagnostics.js | 4 ++ .../w-diagnostics.trace.txt | 9 ++++ .../both-diagnostics.errors.txt | 14 +++++ .../multiLintLoads/both-diagnostics.js | 6 +++ .../multiLintLoads/both-diagnostics.trace.txt | 54 +++++++++++++++++++ .../multiLintLoads/no-diagnostics.js | 5 ++ .../multiLintLoads/no-diagnostics.trace.txt | 54 +++++++++++++++++++ .../semantic-diagnostics.errors.txt | 10 ++++ .../multiLintLoads/semantic-diagnostics.js | 5 ++ .../semantic-diagnostics.trace.txt | 54 +++++++++++++++++++ .../syntactic-diagnostics.errors.txt | 7 +++ .../multiLintLoads/syntactic-diagnostics.js | 4 ++ .../syntactic-diagnostics.trace.txt | 54 +++++++++++++++++++ .../test.errors.txt | 25 +++++++++ .../test.js | 9 ++++ .../passArguments/array.errors.txt | 10 ++++ .../passArguments/array.js | 4 ++ .../test.errors.txt | 20 +++++++ .../reportsAllDIagnosticsFormats/test.js | 5 ++ .../test.errors.txt | 21 ++++++++ .../reportsDiagnosticsWithShortnames/test.js | 9 ++++ .../reportsFailedLoads/test.errors.txt | 20 +++++++ .../reportsFailedLoads/test.js | 5 ++ .../semanticLintLoads/no-diagnostics.js | 5 ++ .../no-diagnostics.trace.txt | 27 ++++++++++ .../w-diagnostics.errors.txt | 10 ++++ .../semanticLintLoads/w-diagnostics.js | 5 ++ .../semanticLintLoads/w-diagnostics.trace.txt | 27 ++++++++++ .../syntacticLintLoads/no-diagnostics.js | 5 ++ .../no-diagnostics.trace.txt | 27 ++++++++++ .../w-diagnostics.errors.txt | 7 +++ .../syntacticLintLoads/w-diagnostics.js | 4 ++ .../w-diagnostics.trace.txt | 27 ++++++++++ 63 files changed, 863 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.js create mode 100644 tests/baselines/reference/CompilerHost/passArguments/array.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/passArguments/array.js create mode 100644 tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js create mode 100644 tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.js create mode 100644 tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js create mode 100644 tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.js create mode 100644 tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/passArguments/array.js create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.js create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js create mode 100644 tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index 1a8d2d981dd82..4dbd5f5f14003 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -290,7 +290,7 @@ class ExtensionRunner extends RunnerBase { */ private runTest(caseName: string) { const caseNameNoExtension = caseName.replace(/\.json$/, ""); - const shortCasePath = caseName.substring(this.scenarioPath.length + 1); + const shortCasePath = caseName.substring(this.scenarioPath.length + 1).replace(/\.json$/, ""); const testConfigText = Harness.IO.readFile(caseName); const testConfig: ExtensionTestConfig = JSON.parse(testConfigText); const inputSources: ts.Map = {}; diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt new file mode 100644 index 0000000000000..52a5cb739b649 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt @@ -0,0 +1,14 @@ +/foo-interface-const.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(2,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-interface-const.ts (3 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.js b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.js new file mode 100644 index 0000000000000..09240cac36985 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.js @@ -0,0 +1,6 @@ +//// [foo-interface-const.ts] +interface Foo {a; b;} +const s: "foo" = "foo"; + +//// [foo-interface-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.trace.txt new file mode 100644 index 0000000000000..9069e84844866 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.trace.txt @@ -0,0 +1,18 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..9069e84844866 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,18 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt new file mode 100644 index 0000000000000..deeb59bd6fef0 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -0,0 +1,10 @@ +/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-const.ts (2 errors) ==== + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.js b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.js new file mode 100644 index 0000000000000..93ea8cd509684 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.js @@ -0,0 +1,5 @@ +//// [foo-const.ts] +const s: "foo" = "foo"; + +//// [foo-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.trace.txt new file mode 100644 index 0000000000000..9069e84844866 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.trace.txt @@ -0,0 +1,18 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt new file mode 100644 index 0000000000000..0561479d6353c --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt @@ -0,0 +1,7 @@ +/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + + +==== /foo-interface.ts (1 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.js b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.trace.txt new file mode 100644 index 0000000000000..9069e84844866 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.trace.txt @@ -0,0 +1,18 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt new file mode 100644 index 0000000000000..13c348707973e --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -0,0 +1,25 @@ +/foo-bar-const-interface.ts(1,11): warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +/foo-bar-const-interface.ts(2,11): warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,10): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(3,18): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,8): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(4,16): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. + + +==== /foo-bar-const-interface.ts (6 errors) ==== + interface Foo {b;} + ~~~ +!!! warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. + interface Bar {a;} + ~~~ +!!! warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. + const f: "foo" = "foo"; + ~~~~~ +!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. + let b: "bar" = "bar"; + ~~~~~ +!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. + ~~~~~ +!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.js b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.js new file mode 100644 index 0000000000000..b0cf15485cf35 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.js @@ -0,0 +1,9 @@ +//// [foo-bar-const-interface.ts] +interface Foo {b;} +interface Bar {a;} +const f: "foo" = "foo"; +let b: "bar" = "bar"; + +//// [foo-bar-const-interface.js] +var f = "foo"; +var b = "bar"; diff --git a/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt b/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt new file mode 100644 index 0000000000000..e0c09e3666129 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt @@ -0,0 +1,10 @@ +/foo-interface.ts(1,16): warning TStest-extension-arguments: Identifier a is forbidden. +/foo-interface.ts(1,19): warning TStest-extension-arguments: Identifier b is forbidden. + + +==== /foo-interface.ts (2 errors) ==== + interface Foo {a; b;} + ~ +!!! warning TStest-extension-arguments: Identifier a is forbidden. + ~ +!!! warning TStest-extension-arguments: Identifier b is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/passArguments/array.js b/tests/baselines/reference/CompilerHost/passArguments/array.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/passArguments/array.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt new file mode 100644 index 0000000000000..e2dfd18137835 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -0,0 +1,20 @@ +warning TStest-errors: Not allowed. +warning TStest-errors[Throws2](THROWS2): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws5]: Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws4](THROWS4): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws6]: Not allowed. + + +!!! warning TStest-errors: Not allowed. +!!! warning TStest-errors[Throws2](THROWS2): Not allowed. +==== /hello.ts (4 errors) ==== + console.log("Hello, world!"); + ~~~~~~~ +!!! warning TStest-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~ +!!! warning TStest-errors[Throws5]: Not allowed. + ~~~~~~~~~~ +!!! warning TStest-errors[Throws4](THROWS4): Not allowed. + ~~~~~~~~~~ +!!! warning TStest-errors[Throws6]: Not allowed. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt new file mode 100644 index 0000000000000..fccf341519f36 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt @@ -0,0 +1,21 @@ +/foo-bar-math.ts(1,7): warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. +/foo-bar-math.ts(1,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(2,7): warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. +/foo-bar-math.ts(2,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(3,7): warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden + + +==== /foo-bar-math.ts (5 errors) ==== + const foo = 3; + ~~~ +!!! warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. + ~~~ +!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. + const bar = 4; + ~~~ +!!! warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. + ~~~ +!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. + const x = 3 * 4; + ~ +!!! warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.js b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.js new file mode 100644 index 0000000000000..8cf880068a1c5 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.js @@ -0,0 +1,9 @@ +//// [foo-bar-math.ts] +const foo = 3; +const bar = 4; +const x = 3 * 4; + +//// [foo-bar-math.js] +var foo = 3; +var bar = 4; +var x = 3 * 4; diff --git a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt new file mode 100644 index 0000000000000..1ab39f417a7e6 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt @@ -0,0 +1,20 @@ +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. + Stack trace: + Error: Host could not locate extension 'test-semantic-lint'. + at F:\Repos\TypeScript\built\local\run.js:42948:33'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. + Stack trace: + Error: Host could not locate extension 'test-syntactic-lint'. + at F:\Repos\TypeScript\built\local\run.js:42948:33'. + + +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. +!!! error TS6151: Stack trace: +!!! error TS6151: Error: Host could not locate extension 'test-semantic-lint'. +!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. +!!! error TS6151: Stack trace: +!!! error TS6151: Error: Host could not locate extension 'test-syntactic-lint'. +!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +==== /hello.ts (0 errors) ==== + console.log("Hello, world!"); \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..acf7782714e0c --- /dev/null +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,9 @@ +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt new file mode 100644 index 0000000000000..deeb59bd6fef0 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt @@ -0,0 +1,10 @@ +/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-const.ts (2 errors) ==== + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.js b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.js new file mode 100644 index 0000000000000..93ea8cd509684 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.js @@ -0,0 +1,5 @@ +//// [foo-const.ts] +const s: "foo" = "foo"; + +//// [foo-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.trace.txt new file mode 100644 index 0000000000000..acf7782714e0c --- /dev/null +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.trace.txt @@ -0,0 +1,9 @@ +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..76f57ec088c21 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,9 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt new file mode 100644 index 0000000000000..0561479d6353c --- /dev/null +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt @@ -0,0 +1,7 @@ +/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + + +==== /foo-interface.ts (1 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.js b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.trace.txt new file mode 100644 index 0000000000000..76f57ec088c21 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.trace.txt @@ -0,0 +1,9 @@ +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt new file mode 100644 index 0000000000000..52a5cb739b649 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt @@ -0,0 +1,14 @@ +/foo-interface-const.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(2,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-interface-const.ts (3 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.js new file mode 100644 index 0000000000000..fc662ca5eb71c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.js @@ -0,0 +1,6 @@ +//// [foo-interface-const.ts] +interface Foo {a; b;} +const s: "foo" = "foo"; + +//// [foo-interface-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt new file mode 100644 index 0000000000000..6832ca513c219 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt @@ -0,0 +1,54 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..6832ca513c219 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,54 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt new file mode 100644 index 0000000000000..deeb59bd6fef0 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -0,0 +1,10 @@ +/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-const.ts (2 errors) ==== + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.js new file mode 100644 index 0000000000000..3743391a17e19 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.js @@ -0,0 +1,5 @@ +//// [foo-const.ts] +const s: "foo" = "foo"; + +//// [foo-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt new file mode 100644 index 0000000000000..6832ca513c219 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt @@ -0,0 +1,54 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt new file mode 100644 index 0000000000000..0561479d6353c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt @@ -0,0 +1,7 @@ +/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + + +==== /foo-interface.ts (1 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt new file mode 100644 index 0000000000000..6832ca513c219 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt @@ -0,0 +1,54 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt new file mode 100644 index 0000000000000..13c348707973e --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -0,0 +1,25 @@ +/foo-bar-const-interface.ts(1,11): warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +/foo-bar-const-interface.ts(2,11): warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,10): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(3,18): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,8): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(4,16): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. + + +==== /foo-bar-const-interface.ts (6 errors) ==== + interface Foo {b;} + ~~~ +!!! warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. + interface Bar {a;} + ~~~ +!!! warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. + const f: "foo" = "foo"; + ~~~~~ +!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. + let b: "bar" = "bar"; + ~~~~~ +!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. + ~~~~~ +!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.js b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.js new file mode 100644 index 0000000000000..7c7d27a43ddf5 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.js @@ -0,0 +1,9 @@ +//// [foo-bar-const-interface.ts] +interface Foo {b;} +interface Bar {a;} +const f: "foo" = "foo"; +let b: "bar" = "bar"; + +//// [foo-bar-const-interface.js] +var f = "foo"; +var b = "bar"; diff --git a/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt b/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt new file mode 100644 index 0000000000000..e0c09e3666129 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt @@ -0,0 +1,10 @@ +/foo-interface.ts(1,16): warning TStest-extension-arguments: Identifier a is forbidden. +/foo-interface.ts(1,19): warning TStest-extension-arguments: Identifier b is forbidden. + + +==== /foo-interface.ts (2 errors) ==== + interface Foo {a; b;} + ~ +!!! warning TStest-extension-arguments: Identifier a is forbidden. + ~ +!!! warning TStest-extension-arguments: Identifier b is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/passArguments/array.js b/tests/baselines/reference/LanguageServiceHost/passArguments/array.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/passArguments/array.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt new file mode 100644 index 0000000000000..e2dfd18137835 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -0,0 +1,20 @@ +warning TStest-errors: Not allowed. +warning TStest-errors[Throws2](THROWS2): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws5]: Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws4](THROWS4): Not allowed. +/hello.ts(1,1): warning TStest-errors[Throws6]: Not allowed. + + +!!! warning TStest-errors: Not allowed. +!!! warning TStest-errors[Throws2](THROWS2): Not allowed. +==== /hello.ts (4 errors) ==== + console.log("Hello, world!"); + ~~~~~~~ +!!! warning TStest-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~ +!!! warning TStest-errors[Throws5]: Not allowed. + ~~~~~~~~~~ +!!! warning TStest-errors[Throws4](THROWS4): Not allowed. + ~~~~~~~~~~ +!!! warning TStest-errors[Throws6]: Not allowed. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt new file mode 100644 index 0000000000000..fccf341519f36 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt @@ -0,0 +1,21 @@ +/foo-bar-math.ts(1,7): warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. +/foo-bar-math.ts(1,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(2,7): warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. +/foo-bar-math.ts(2,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(3,7): warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden + + +==== /foo-bar-math.ts (5 errors) ==== + const foo = 3; + ~~~ +!!! warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. + ~~~ +!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. + const bar = 4; + ~~~ +!!! warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. + ~~~ +!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. + const x = 3 * 4; + ~ +!!! warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.js b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.js new file mode 100644 index 0000000000000..cf277cae619b3 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.js @@ -0,0 +1,9 @@ +//// [foo-bar-math.ts] +const foo = 3; +const bar = 4; +const x = 3 * 4; + +//// [foo-bar-math.js] +var foo = 3; +var bar = 4; +var x = 3 * 4; diff --git a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt new file mode 100644 index 0000000000000..1ab39f417a7e6 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt @@ -0,0 +1,20 @@ +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. + Stack trace: + Error: Host could not locate extension 'test-semantic-lint'. + at F:\Repos\TypeScript\built\local\run.js:42948:33'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. + Stack trace: + Error: Host could not locate extension 'test-syntactic-lint'. + at F:\Repos\TypeScript\built\local\run.js:42948:33'. + + +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. +!!! error TS6151: Stack trace: +!!! error TS6151: Error: Host could not locate extension 'test-semantic-lint'. +!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. +!!! error TS6151: Stack trace: +!!! error TS6151: Error: Host could not locate extension 'test-syntactic-lint'. +!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +==== /hello.ts (0 errors) ==== + console.log("Hello, world!"); \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..4c81570af10bc --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,27 @@ +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt new file mode 100644 index 0000000000000..deeb59bd6fef0 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt @@ -0,0 +1,10 @@ +/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. + + +==== /foo-const.ts (2 errors) ==== + const s: "foo" = "foo"; + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. + ~~~~~ +!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.js new file mode 100644 index 0000000000000..3743391a17e19 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.js @@ -0,0 +1,5 @@ +//// [foo-const.ts] +const s: "foo" = "foo"; + +//// [foo-const.js] +var s = "foo"; diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt new file mode 100644 index 0000000000000..4c81570af10bc --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt @@ -0,0 +1,27 @@ +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== +======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-semantic-lint' from 'node_modules' folder. +File 'node_modules/test-semantic-lint.js' does not exist. +File 'node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. +File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt new file mode 100644 index 0000000000000..4cf96f6c7e747 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt @@ -0,0 +1,27 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt new file mode 100644 index 0000000000000..0561479d6353c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt @@ -0,0 +1,7 @@ +/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. + + +==== /foo-interface.ts (1 errors) ==== + interface Foo {a; b;} + ~~~ +!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.js new file mode 100644 index 0000000000000..9bb521dc08570 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.js @@ -0,0 +1,4 @@ +//// [foo-interface.ts] +interface Foo {a; b;} + +//// [foo-interface.js] diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt new file mode 100644 index 0000000000000..4cf96f6c7e747 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt @@ -0,0 +1,27 @@ +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'test-syntactic-lint' from 'node_modules' folder. +File 'node_modules/test-syntactic-lint.js' does not exist. +File 'node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. +File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file From ab90cbad0f356620caadfe1f40fa0c060188221a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 22:49:21 -0700 Subject: [PATCH 28/49] Fix error baselines, add cache persistence to the LS --- src/compiler/core.ts | 45 +++++++++++++++++++ src/compiler/extensions.ts | 4 +- src/services/services.ts | 8 +++- .../reportsFailedLoads/test.errors.txt | 20 ++------- .../multiLintLoads/both-diagnostics.trace.txt | 36 --------------- .../multiLintLoads/no-diagnostics.trace.txt | 36 --------------- .../semantic-diagnostics.trace.txt | 36 --------------- .../syntactic-diagnostics.trace.txt | 36 --------------- .../reportsFailedLoads/test.errors.txt | 20 ++------- .../no-diagnostics.trace.txt | 18 -------- .../semanticLintLoads/w-diagnostics.trace.txt | 18 -------- .../no-diagnostics.trace.txt | 18 -------- .../w-diagnostics.trace.txt | 18 -------- 13 files changed, 61 insertions(+), 252 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index a0de8e4dc165a..aa38cc9687e44 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1331,4 +1331,49 @@ namespace ts { : ((fileName) => fileName.toLowerCase()); } + /** + * This isn't the strictest deep equal, but it's good enough for us + * - +0 === -0 (though who really wants to consider them different?) + * - arguments and arrays can be equal (both typeof === object, both have enumerable keys) + * - doesn't inspect es6 iterables (not that they're used in this code base) + * - doesn't inspect regex toString value (so only references to the same regex are equal) + * - doesn't inspect date primitive number value (so only references to the same date are equal) + */ + export function deepEqual(a: any, b: any, memo?: [any, any][]): boolean { + if (a === b) return true; + if (typeof a !== typeof b) return false; + // Special case NaN + if (typeof a === "number" && isNaN(a) && isNaN(b)) return true; + // We can't know if function arguments are deep equal, so we say they're equal if they look alike + if (typeof a === "object" || typeof a === "function") { + if (memo) { + for (let i = 0; i < memo.length; i++) { + if (memo[i][0] === a && memo[i][1] === b) return true; + if (memo[i][0] === b && memo[i][1] === a) return true; + } + } + else { + memo = []; + } + + const aKeys = ts.getKeys(a); + const bKeys = ts.getKeys(b); + aKeys.sort(); + bKeys.sort(); + + if (aKeys.length !== bKeys.length) return false; + + for (let i = 0; i < aKeys.length; i++) { + if (aKeys[i] !== bKeys[i]) return false; + } + + memo.push([a, b]); + + for (const key of aKeys) { + if (!deepEqual(a[key], b[key], memo)) return false; + } + return true; + } + return false; + } } diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index a4a0dd32c947f..f6f71b7ed0538 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -178,9 +178,7 @@ namespace ts { error = new Error("Extension loading not implemented in host!"); } if (error) { - diagnostics.push(createCompilerDiagnostic(Diagnostics.Extension_loading_failed_with_error_0, error.stack ? `${error} - Stack trace: - ${error.stack}` : error)); + diagnostics.push(createCompilerDiagnostic(Diagnostics.Extension_loading_failed_with_error_0, error)); } return { name, result, error }; }); diff --git a/src/services/services.ts b/src/services/services.ts index 2099db112f67c..5c17b37b2f131 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2925,6 +2925,7 @@ namespace ts { const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); let ruleProvider: formatting.RulesProvider; let program: Program; + let extensionCache: ExtensionCache; let lastProjectVersion: string; const useCaseSensitivefileNames = false; @@ -3044,8 +3045,13 @@ namespace ts { }; } + const changesInCompilationSettingsAffectExtensions = oldSettings && !deepEqual(oldSettings.extensions, newSettings.extensions); + if (!extensionCache || changesInCompilationSettingsAffectExtensions) { + extensionCache = createExtensionCache(newSettings, compilerHost); + } + const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); - const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program); + const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program, extensionCache); // Release any files we have acquired in the old program but are // not part of the new program. diff --git a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt index 1ab39f417a7e6..b8eeda0cb4527 100644 --- a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt @@ -1,20 +1,8 @@ -error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. - Stack trace: - Error: Host could not locate extension 'test-semantic-lint'. - at F:\Repos\TypeScript\built\local\run.js:42948:33'. -error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. - Stack trace: - Error: Host could not locate extension 'test-syntactic-lint'. - at F:\Repos\TypeScript\built\local\run.js:42948:33'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. -!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. -!!! error TS6151: Stack trace: -!!! error TS6151: Error: Host could not locate extension 'test-semantic-lint'. -!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. -!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. -!!! error TS6151: Stack trace: -!!! error TS6151: Error: Host could not locate extension 'test-syntactic-lint'. -!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. ==== /hello.ts (0 errors) ==== console.log("Hello, world!"); \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt index 6832ca513c219..90d89805927db 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt @@ -15,40 +15,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt index 6832ca513c219..90d89805927db 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt @@ -15,40 +15,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt index 6832ca513c219..90d89805927db 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt @@ -15,40 +15,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt index 6832ca513c219..90d89805927db 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt @@ -15,40 +15,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt index 1ab39f417a7e6..b8eeda0cb4527 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt @@ -1,20 +1,8 @@ -error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. - Stack trace: - Error: Host could not locate extension 'test-semantic-lint'. - at F:\Repos\TypeScript\built\local\run.js:42948:33'. -error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. - Stack trace: - Error: Host could not locate extension 'test-syntactic-lint'. - at F:\Repos\TypeScript\built\local\run.js:42948:33'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. +error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. -!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'. -!!! error TS6151: Stack trace: -!!! error TS6151: Error: Host could not locate extension 'test-semantic-lint'. -!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. -!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'. -!!! error TS6151: Stack trace: -!!! error TS6151: Error: Host could not locate extension 'test-syntactic-lint'. -!!! error TS6151: at F:\Repos\TypeScript\built\local\run.js:42948:33'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. +!!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. ==== /hello.ts (0 errors) ==== console.log("Hello, world!"); \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt index 4c81570af10bc..cb8ddfddb2a00 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt @@ -6,22 +6,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt index 4c81570af10bc..cb8ddfddb2a00 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt @@ -6,22 +6,4 @@ File 'node_modules/test-semantic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. 'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. ======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt index 4cf96f6c7e747..19b1c83eb2e85 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt @@ -6,22 +6,4 @@ File 'node_modules/test-syntactic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. 'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. ======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt index 4cf96f6c7e747..19b1c83eb2e85 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt @@ -6,22 +6,4 @@ File 'node_modules/test-syntactic-lint.jsx' does not exist. Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. 'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== -Module resolution kind is not specified, using 'NodeJs'. -Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. ======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file From 8a972d9aec13e1168501a10c64c981683c2835af Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 23:28:18 -0700 Subject: [PATCH 29/49] Fix lints, remove ref to extensionAPI unit, add perf trace test --- Gulpfile.ts | 1 - Jakefile.js | 1 - src/compiler/extensions.ts | 44 ++++++++--- src/harness/extensionRunner.ts | 7 +- .../profileExtensionsTraces/test.js | 5 ++ .../profileExtensionsTraces/test.trace.txt | 74 +++++++++++++++++++ .../profileExtensionsTraces/test.js | 5 ++ .../profileExtensionsTraces/test.trace.txt | 74 +++++++++++++++++++ .../profileExtensionsTraces/test.json | 10 +++ 9 files changed, 204 insertions(+), 17 deletions(-) create mode 100644 tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js create mode 100644 tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js create mode 100644 tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt create mode 100644 tests/cases/extensions/scenarios/profileExtensionsTraces/test.json diff --git a/Gulpfile.ts b/Gulpfile.ts index 6446757293b5a..43e54ae068f70 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -159,7 +159,6 @@ const harnessSources = harnessCoreSources.concat([ "convertTypingOptionsFromJson.ts", "tsserverProjectSystem.ts", "matchFiles.ts", - "extensionAPI.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/Jakefile.js b/Jakefile.js index 709bb1fc49b2a..5a23af6f3be14 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -161,7 +161,6 @@ var harnessSources = harnessCoreSources.concat([ "convertTypingOptionsFromJson.ts", "tsserverProjectSystem.ts", "matchFiles.ts", - "extensionAPI.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index f6f71b7ed0538..2b89b9564fbfc 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -53,10 +53,11 @@ namespace ts { profiles?: Map; } + export type Timestamp = number & { __timestampBrand: void }; export interface ProfileData { task: string; - start: number; - length: number; + start: Timestamp; + length?: Timestamp; } // @kind(ExtensionKind.SyntacticLint) @@ -98,25 +99,46 @@ namespace ts { } } + declare var performance: { now?(): number }; // If we're running in a context with high resolution timers, make use of them + declare var process: { hrtime?(start?: [number, number]): [number, number] }; + + function getTimestampInternal(): number { + if (typeof performance !== "undefined" && performance.now) { + return performance.now(); + } + if (typeof process !== "undefined" && process.hrtime) { + const time = process.hrtime(); + return (time[0] * 1e9 + time[1]) / 1e6; + } + return +(new Date()); + } + + export function getTimestampMs(since?: Timestamp): Timestamp { + if (typeof since !== "number") { + return getTimestampInternal() as Timestamp; + } + + return (getTimestampInternal() - since) as Timestamp; + } + export function startExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { if (!ext.profiles) ext.profiles = {}; ext.profiles[task] = { task, - start: +(new Date()), - length: -1 + start: getTimestampMs(), + length: undefined }; profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, ext.name, task); } export function completeExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { - const endTime = +(new Date()); Debug.assert(!!ext.profiles, "Completed profile, but extension has no started profiles."); Debug.assert(!!ext.profiles[task], "Completed profile did not have a corresponding start."); - ext.profiles[task].length = endTime - ext.profiles[task].start; + ext.profiles[task].length = getTimestampMs(ext.profiles[task].start); - profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, ext.profiles[task].length.toFixed(4)); + profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, ext.profiles[task].length.toPrecision(5)); } export function createExtensionCache(options: CompilerOptions, host: ExtensionHost): ExtensionCache { @@ -155,15 +177,15 @@ namespace ts { const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; if (resolved) { try { - let startTime: number; + let startTime: Timestamp; if (shouldProfile) { - startTime = +(new Date()); + startTime = getTimestampMs(); trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); } result = host.loadExtension(resolved.resolvedFileName); if (shouldProfile) { - const loadTime = +(new Date()) - startTime; - trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load", loadTime.toFixed(4)); + const loadTime = getTimestampMs(startTime); + trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", loadTime.toPrecision(5)); } } catch (e) { diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index 4dbd5f5f14003..e50d9e1a256b7 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -15,7 +15,6 @@ class ExtensionRunner extends RunnerBase { private scenarioPath = ts.combinePaths(this.basePath, "scenarios"); private extensionPath = ts.combinePaths(this.basePath, "available"); private sourcePath = ts.combinePaths(this.basePath, "source"); - private fourslashPath = ts.combinePaths(this.basePath, "fourslash"); private extensionAPI: ts.Map = {}; private extensions: ts.Map> = {}; private virtualLib: ts.Map = {}; @@ -140,7 +139,7 @@ class ExtensionRunner extends RunnerBase { getTraces(): string[] { const traces = this.traces; this.traces = []; - return traces; + return traces.map(t => t.replace(/\([0-9\.e\+\-]+ ms\)$/, "(REDACTED ms)")); } languageServiceCompile(typescriptFiles: string[], options: ts.CompilerOptions): Harness.Compiler.CompilerResult { @@ -174,7 +173,7 @@ class ExtensionRunner extends RunnerBase { const self = this; const program = ts.createProgram(typescriptFiles, options, this.mockHost); const fileResults: Harness.Compiler.GeneratedFile[] = []; - const diagnostics = ts.getPreEmitDiagnostics(program) + const diagnostics = ts.getPreEmitDiagnostics(program); const emitResult = program.emit(/*targetSourceFile*/undefined, writeFile); const allDiagnostics = ts.sortAndDeduplicateDiagnostics(ts.concatenate(diagnostics, emitResult.diagnostics)); @@ -336,7 +335,7 @@ class ExtensionRunner extends RunnerBase { if (!(testConfig.compilerOptions.sourceMap || testConfig.compilerOptions.inlineSourceMap)) { return; } - Harness.Baseline.runBaseline(sourcemapTestName,`${name}/${shortCasePath}.sourcemap.txt`, () => { + Harness.Baseline.runBaseline(sourcemapTestName, `${name}/${shortCasePath}.sourcemap.txt`, () => { const record = result.getSourceMapRecord(); if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && record === undefined) { // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. diff --git a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt new file mode 100644 index 0000000000000..2772d7bad1940 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt @@ -0,0 +1,74 @@ +PROFILE: Extension 'test-multi-extension' begin 'load' +PROFILE: Extension 'test-multi-extension' end 'load' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303883' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303883' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303883' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303883' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303884' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303884' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303884' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303884' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303885' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303885' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303885' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303885' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303886' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303886' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303886' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303886' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303887' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303887' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303887' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303887' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303888' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303888' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303888' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303888' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303889' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303889' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303889' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303889' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303890' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303890' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303890' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303890' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303883' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303883' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303883' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303883' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303884' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303884' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303884' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303884' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303885' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303885' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303885' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303885' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303886' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303886' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303886' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303886' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303887' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303887' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303887' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303887' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303888' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303888' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303888' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303888' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303889' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303889' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303889' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303889' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303890' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303890' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303890' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303890' (REDACTED ms) \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt new file mode 100644 index 0000000000000..3bf22ec1ea18d --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt @@ -0,0 +1,74 @@ +PROFILE: Extension 'test-multi-extension' begin 'load' +PROFILE: Extension 'test-multi-extension' end 'load' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319090' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319090' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319090' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319090' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319091' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319091' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319091' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319091' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319092' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319092' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319092' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319092' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319093' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319093' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319093' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319093' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319094' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319094' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319094' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319094' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319095' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319095' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319095' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319095' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319096' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319096' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319096' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319096' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319097' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319097' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319097' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319097' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319090' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319090' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319090' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319090' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319091' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319091' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319091' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319091' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319092' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319092' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319092' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319092' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319093' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319093' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319093' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319093' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319094' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319094' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319094' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319094' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319095' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319095' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319095' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319095' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319096' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319096' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319096' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319096' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319097' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319097' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319097' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319097' (REDACTED ms) \ No newline at end of file diff --git a/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json b/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json new file mode 100644 index 0000000000000..ccf409f767119 --- /dev/null +++ b/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json @@ -0,0 +1,10 @@ +{ + "inputFiles": [ + "hello.ts" + ], + "availableExtensions": ["test-multi-extension"], + "compilerOptions": { + "extensions": ["test-multi-extension"], + "profileExtensions": true + } +} \ No newline at end of file From dad1bbe66e060e7857fe84b090f5c0e875effa7c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 1 Jul 2016 23:42:48 -0700 Subject: [PATCH 30/49] Remove TS from extension error baselines, maybe deterministic profiling IDs --- src/compiler/program.ts | 6 +- src/harness/harness.ts | 9 +- .../both-diagnostics.errors.txt | 12 +- .../semantic-diagnostics.errors.txt | 8 +- .../syntactic-diagnostics.errors.txt | 4 +- .../test.errors.txt | 24 ++-- .../passArguments/array.errors.txt | 8 +- .../profileExtensionsTraces/test.trace.txt | 128 +++++++++--------- .../test.errors.txt | 24 ++-- .../test.errors.txt | 20 +-- .../w-diagnostics.errors.txt | 8 +- .../w-diagnostics.errors.txt | 4 +- .../both-diagnostics.errors.txt | 12 +- .../semantic-diagnostics.errors.txt | 8 +- .../syntactic-diagnostics.errors.txt | 4 +- .../test.errors.txt | 24 ++-- .../passArguments/array.errors.txt | 8 +- .../profileExtensionsTraces/test.trace.txt | 128 +++++++++--------- .../test.errors.txt | 24 ++-- .../test.errors.txt | 20 +-- .../w-diagnostics.errors.txt | 8 +- .../w-diagnostics.errors.txt | 4 +- 22 files changed, 251 insertions(+), 244 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ba4751122526e..f3b0b210ccf25 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1509,11 +1509,13 @@ namespace ts { if (shouldProfile) completeExtensionProfile(lints[i], "construct", host.trace); } + let nodesVisited = 0; visitNode(sourceFile); return diagnostics; function visitNode(node: Node) { + nodesVisited++; let oneAccepted = false; const oldParent = parent; const needsReset: Map = {}; @@ -1521,9 +1523,9 @@ namespace ts { if (initializedLints[i].accepted) { activeLint = initializedLints[i]; node.parent = parent; - if (shouldProfile) startExtensionProfile(lints[i], `visitNode|${getNodeId(node)}`, host.trace); + if (shouldProfile) startExtensionProfile(lints[i], `visitNode|${nodesVisited}`, host.trace); activeLint.walker.visit(node, stop, error); - if (shouldProfile) completeExtensionProfile(lints[i], `visitNode|${getNodeId(node)}`, host.trace); + if (shouldProfile) completeExtensionProfile(lints[i], `visitNode|${nodesVisited}`, host.trace); if (activeLint.accepted) { oneAccepted = true; } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 1977d95492ccf..6e8e37a80b148 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1202,6 +1202,11 @@ namespace Harness { return normalized; } + function getDiagnosticCodeString(code: string | number) { + if (typeof code === "number") return `TS${code}`; + return code; + } + export function minimalDiagnosticsToString(diagnostics: ts.Diagnostic[]) { // This is basically copied from tsc.ts's reportError to replicate what tsc does let errorOutput = ""; @@ -1211,7 +1216,7 @@ namespace Harness { errorOutput += diagnostic.file.fileName + "(" + (lineAndCharacter.line + 1) + "," + (lineAndCharacter.character + 1) + "): "; } - errorOutput += ts.DiagnosticCategory[diagnostic.category].toLowerCase() + " TS" + diagnostic.code + ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()) + Harness.IO.newLine(); + errorOutput += ts.DiagnosticCategory[diagnostic.category].toLowerCase() + " " + getDiagnosticCodeString(diagnostic.code) + ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()) + Harness.IO.newLine(); }); return errorOutput; @@ -1230,7 +1235,7 @@ namespace Harness { .split("\n") .map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s) .filter(s => s.length > 0) - .map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s); + .map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " " + getDiagnosticCodeString(error.code) + ": " + s); errLines.forEach(e => outputLines.push(e)); // do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt index 52a5cb739b649..3468d669f3056 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt @@ -1,14 +1,14 @@ -/foo-interface-const.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. -/foo-interface-const.ts(2,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-interface-const.ts(2,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(2,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-interface-const.ts (3 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt index deeb59bd6fef0..fedeb2199df77 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -1,10 +1,10 @@ -/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-const.ts (2 errors) ==== const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt index 0561479d6353c..26aff22d2534b 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/syntactic-diagnostics.errors.txt @@ -1,7 +1,7 @@ -/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. ==== /foo-interface.ts (1 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt index 13c348707973e..48d30107e5b3d 100644 --- a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -1,25 +1,25 @@ -/foo-bar-const-interface.ts(1,11): warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. -/foo-bar-const-interface.ts(2,11): warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. -/foo-bar-const-interface.ts(3,10): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. -/foo-bar-const-interface.ts(3,18): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. -/foo-bar-const-interface.ts(4,8): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. -/foo-bar-const-interface.ts(4,16): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(1,11): warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +/foo-bar-const-interface.ts(2,11): warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,10): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(3,18): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,8): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(4,16): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ==== /foo-bar-const-interface.ts (6 errors) ==== interface Foo {b;} ~~~ -!!! warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +!!! warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. interface Bar {a;} ~~~ -!!! warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +!!! warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. const f: "foo" = "foo"; ~~~~~ -!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. let b: "bar" = "bar"; ~~~~~ -!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ -!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt b/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt index e0c09e3666129..111f82a3d9064 100644 --- a/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt +++ b/tests/baselines/reference/CompilerHost/passArguments/array.errors.txt @@ -1,10 +1,10 @@ -/foo-interface.ts(1,16): warning TStest-extension-arguments: Identifier a is forbidden. -/foo-interface.ts(1,19): warning TStest-extension-arguments: Identifier b is forbidden. +/foo-interface.ts(1,16): warning test-extension-arguments: Identifier a is forbidden. +/foo-interface.ts(1,19): warning test-extension-arguments: Identifier b is forbidden. ==== /foo-interface.ts (2 errors) ==== interface Foo {a; b;} ~ -!!! warning TStest-extension-arguments: Identifier a is forbidden. +!!! warning test-extension-arguments: Identifier a is forbidden. ~ -!!! warning TStest-extension-arguments: Identifier b is forbidden. \ No newline at end of file +!!! warning test-extension-arguments: Identifier b is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt index 2772d7bad1940..53405c1d07d9d 100644 --- a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt +++ b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt @@ -4,71 +4,71 @@ PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303883' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303883' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303883' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303883' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303884' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303884' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303884' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303884' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303885' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303885' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303885' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303885' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303886' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303886' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303886' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303886' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303887' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303887' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303887' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303887' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303888' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303888' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303888' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303888' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303889' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303889' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303889' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303889' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|303890' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|303890' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|303890' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|303890' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|8' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|8' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303883' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303883' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303883' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303883' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303884' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303884' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303884' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303884' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303885' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303885' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303885' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303885' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303886' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303886' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303886' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303886' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303887' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303887' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303887' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303887' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303888' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303888' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303888' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303888' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303889' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303889' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303889' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303889' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|303890' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|303890' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|303890' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|303890' (REDACTED ms) \ No newline at end of file +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|8' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|8' (REDACTED ms) \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt index e2dfd18137835..61243deabf4b3 100644 --- a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -1,20 +1,20 @@ -warning TStest-errors: Not allowed. -warning TStest-errors[Throws2](THROWS2): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws3](THROWS3): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws5]: Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws4](THROWS4): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws6]: Not allowed. +warning test-errors: Not allowed. +warning test-errors[Throws2](THROWS2): Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws4](THROWS4): Not allowed. +/hello.ts(1,1): warning test-errors[Throws6]: Not allowed. -!!! warning TStest-errors: Not allowed. -!!! warning TStest-errors[Throws2](THROWS2): Not allowed. +!!! warning test-errors: Not allowed. +!!! warning test-errors[Throws2](THROWS2): Not allowed. ==== /hello.ts (4 errors) ==== console.log("Hello, world!"); ~~~~~~~ -!!! warning TStest-errors[Throws3](THROWS3): Not allowed. +!!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ -!!! warning TStest-errors[Throws5]: Not allowed. +!!! warning test-errors[Throws5]: Not allowed. ~~~~~~~~~~ -!!! warning TStest-errors[Throws4](THROWS4): Not allowed. +!!! warning test-errors[Throws4](THROWS4): Not allowed. ~~~~~~~~~~ -!!! warning TStest-errors[Throws6]: Not allowed. \ No newline at end of file +!!! warning test-errors[Throws6]: Not allowed. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt index fccf341519f36..2f527e1085ea8 100644 --- a/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsDiagnosticsWithShortnames/test.errors.txt @@ -1,21 +1,21 @@ -/foo-bar-math.ts(1,7): warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. -/foo-bar-math.ts(1,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. -/foo-bar-math.ts(2,7): warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. -/foo-bar-math.ts(2,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. -/foo-bar-math.ts(3,7): warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden +/foo-bar-math.ts(1,7): warning test-multierrors(FOO): Identifier 'foo' is forbidden. +/foo-bar-math.ts(1,7): warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(2,7): warning test-multierrors(BAR): Identifier 'bar' is forbidden. +/foo-bar-math.ts(2,7): warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(3,7): warning test-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden ==== /foo-bar-math.ts (5 errors) ==== const foo = 3; ~~~ -!!! warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. +!!! warning test-multierrors(FOO): Identifier 'foo' is forbidden. ~~~ -!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +!!! warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. const bar = 4; ~~~ -!!! warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. +!!! warning test-multierrors(BAR): Identifier 'bar' is forbidden. ~~~ -!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +!!! warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. const x = 3 * 4; ~ -!!! warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file +!!! warning test-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt index deeb59bd6fef0..fedeb2199df77 100644 --- a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt @@ -1,10 +1,10 @@ -/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-const.ts (2 errors) ==== const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt index 0561479d6353c..26aff22d2534b 100644 --- a/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/w-diagnostics.errors.txt @@ -1,7 +1,7 @@ -/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. ==== /foo-interface.ts (1 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt index 52a5cb739b649..3468d669f3056 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt @@ -1,14 +1,14 @@ -/foo-interface-const.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. -/foo-interface-const.ts(2,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-interface-const.ts(2,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-interface-const.ts(2,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-interface-const.ts (3 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt index deeb59bd6fef0..fedeb2199df77 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -1,10 +1,10 @@ -/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-const.ts (2 errors) ==== const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt index 0561479d6353c..26aff22d2534b 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.errors.txt @@ -1,7 +1,7 @@ -/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. ==== /foo-interface.ts (1 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt index 13c348707973e..48d30107e5b3d 100644 --- a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -1,25 +1,25 @@ -/foo-bar-const-interface.ts(1,11): warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. -/foo-bar-const-interface.ts(2,11): warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. -/foo-bar-const-interface.ts(3,10): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. -/foo-bar-const-interface.ts(3,18): warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. -/foo-bar-const-interface.ts(4,8): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. -/foo-bar-const-interface.ts(4,16): warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(1,11): warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +/foo-bar-const-interface.ts(2,11): warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,10): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(3,18): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,8): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +/foo-bar-const-interface.ts(4,16): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ==== /foo-bar-const-interface.ts (6 errors) ==== interface Foo {b;} ~~~ -!!! warning TStest-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. +!!! warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. interface Bar {a;} ~~~ -!!! warning TStest-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +!!! warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. const f: "foo" = "foo"; ~~~~~ -!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. let b: "bar" = "bar"; ~~~~~ -!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ -!!! warning TStest-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt b/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt index e0c09e3666129..111f82a3d9064 100644 --- a/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/passArguments/array.errors.txt @@ -1,10 +1,10 @@ -/foo-interface.ts(1,16): warning TStest-extension-arguments: Identifier a is forbidden. -/foo-interface.ts(1,19): warning TStest-extension-arguments: Identifier b is forbidden. +/foo-interface.ts(1,16): warning test-extension-arguments: Identifier a is forbidden. +/foo-interface.ts(1,19): warning test-extension-arguments: Identifier b is forbidden. ==== /foo-interface.ts (2 errors) ==== interface Foo {a; b;} ~ -!!! warning TStest-extension-arguments: Identifier a is forbidden. +!!! warning test-extension-arguments: Identifier a is forbidden. ~ -!!! warning TStest-extension-arguments: Identifier b is forbidden. \ No newline at end of file +!!! warning test-extension-arguments: Identifier b is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt index 3bf22ec1ea18d..53405c1d07d9d 100644 --- a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt @@ -4,71 +4,71 @@ PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319090' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319090' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319090' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319090' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319091' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319091' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319091' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319091' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319092' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319092' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319092' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319092' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319093' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319093' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319093' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319093' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319094' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319094' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319094' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319094' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319095' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319095' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319095' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319095' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319096' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319096' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319096' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319096' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|319097' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|319097' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|319097' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|319097' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|8' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|8' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319090' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319090' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319090' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319090' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319091' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319091' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319091' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319091' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319092' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319092' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319092' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319092' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319093' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319093' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319093' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319093' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319094' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319094' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319094' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319094' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319095' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319095' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319095' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319095' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319096' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319096' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319096' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319096' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|319097' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|319097' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|319097' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|319097' (REDACTED ms) \ No newline at end of file +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|1' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|1' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|2' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|2' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|3' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|3' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|4' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|4' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|5' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|5' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|6' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|6' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|7' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|7' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|8' (REDACTED ms) +PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|8' +PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|8' (REDACTED ms) \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt index e2dfd18137835..61243deabf4b3 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -1,20 +1,20 @@ -warning TStest-errors: Not allowed. -warning TStest-errors[Throws2](THROWS2): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws3](THROWS3): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws5]: Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws4](THROWS4): Not allowed. -/hello.ts(1,1): warning TStest-errors[Throws6]: Not allowed. +warning test-errors: Not allowed. +warning test-errors[Throws2](THROWS2): Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws4](THROWS4): Not allowed. +/hello.ts(1,1): warning test-errors[Throws6]: Not allowed. -!!! warning TStest-errors: Not allowed. -!!! warning TStest-errors[Throws2](THROWS2): Not allowed. +!!! warning test-errors: Not allowed. +!!! warning test-errors[Throws2](THROWS2): Not allowed. ==== /hello.ts (4 errors) ==== console.log("Hello, world!"); ~~~~~~~ -!!! warning TStest-errors[Throws3](THROWS3): Not allowed. +!!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ -!!! warning TStest-errors[Throws5]: Not allowed. +!!! warning test-errors[Throws5]: Not allowed. ~~~~~~~~~~ -!!! warning TStest-errors[Throws4](THROWS4): Not allowed. +!!! warning test-errors[Throws4](THROWS4): Not allowed. ~~~~~~~~~~ -!!! warning TStest-errors[Throws6]: Not allowed. \ No newline at end of file +!!! warning test-errors[Throws6]: Not allowed. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt index fccf341519f36..2f527e1085ea8 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsDiagnosticsWithShortnames/test.errors.txt @@ -1,21 +1,21 @@ -/foo-bar-math.ts(1,7): warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. -/foo-bar-math.ts(1,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. -/foo-bar-math.ts(2,7): warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. -/foo-bar-math.ts(2,7): warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. -/foo-bar-math.ts(3,7): warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden +/foo-bar-math.ts(1,7): warning test-multierrors(FOO): Identifier 'foo' is forbidden. +/foo-bar-math.ts(1,7): warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(2,7): warning test-multierrors(BAR): Identifier 'bar' is forbidden. +/foo-bar-math.ts(2,7): warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +/foo-bar-math.ts(3,7): warning test-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden ==== /foo-bar-math.ts (5 errors) ==== const foo = 3; ~~~ -!!! warning TStest-multierrors(FOO): Identifier 'foo' is forbidden. +!!! warning test-multierrors(FOO): Identifier 'foo' is forbidden. ~~~ -!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +!!! warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. const bar = 4; ~~~ -!!! warning TStest-multierrors(BAR): Identifier 'bar' is forbidden. +!!! warning test-multierrors(BAR): Identifier 'bar' is forbidden. ~~~ -!!! warning TStest-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. +!!! warning test-multierrors[NoShortNames](SHORT): Short identifiers are forbidden. const x = 3 * 4; ~ -!!! warning TStest-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file +!!! warning test-multierrors[NoShortNames](SINGLE): Single character identifiers are forbidden \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt index deeb59bd6fef0..fedeb2199df77 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt @@ -1,10 +1,10 @@ -/foo-const.ts(1,10): warning TStest-semantic-lint: String literal type 'foo' is forbidden. -/foo-const.ts(1,18): warning TStest-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. +/foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. ==== /foo-const.ts (2 errors) ==== const s: "foo" = "foo"; ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ -!!! warning TStest-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt index 0561479d6353c..26aff22d2534b 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.errors.txt @@ -1,7 +1,7 @@ -/foo-interface.ts(1,11): warning TStest-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. ==== /foo-interface.ts (1 errors) ==== interface Foo {a; b;} ~~~ -!!! warning TStest-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file +!!! warning test-syntactic-lint: Identifier 'foo' is forbidden. \ No newline at end of file From 9405dd342a143ea95e837739725d7eafc092b0ae Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 5 Jul 2016 11:42:09 -0700 Subject: [PATCH 31/49] Make extension profiling be a two-level process --- src/compiler/commandLineParser.ts | 8 ++- src/compiler/diagnosticMessages.json | 2 +- src/compiler/extensions.ts | 58 ++++++++++++------- src/compiler/program.ts | 10 ++-- src/compiler/tsc.ts | 16 +++++ src/compiler/types.ts | 8 ++- .../profileExtensionsTraces/test.json | 2 +- 7 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index d49ffcece52df..9b2cdcc66d030 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -434,8 +434,12 @@ namespace ts { }, { name: "profileExtensions", - type: "boolean", - description: Diagnostics.Enable_extension_profiling, + type: { + "none": ProfileLevel.None, + "summary": ProfileLevel.Summary, + "full": ProfileLevel.Full, + }, + description: Diagnostics.Set_extension_profiling_level_Colon, } ]; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d442a9c5d3d99..bd5f468e18fbd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2821,7 +2821,7 @@ "category": "Error", "code": 6152 }, - "Enable extension profiling.": { + "Set extension profiling level:": { "category": "Message", "code": 6153 }, diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 2b89b9564fbfc..226f10701712e 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -50,11 +50,11 @@ namespace ts { name: string; args: any; kind: ExtensionKind; - profiles?: Map; } export type Timestamp = number & { __timestampBrand: void }; export interface ProfileData { + globalBucket: string; task: string; start: Timestamp; length?: Timestamp; @@ -121,24 +121,43 @@ namespace ts { return (getTimestampInternal() - since) as Timestamp; } - export function startExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { - if (!ext.profiles) ext.profiles = {}; + export const perfTraces: Map = {}; - ext.profiles[task] = { - task, + function getExtensionRootName(ext: ExtensionBase) { + return ext.name.substring(0, ext.name.indexOf("[")) || ext.name; + } + + function createTaskName(ext: ExtensionBase, task: string) { + return `${task}|${ext.name}`; + } + + export function startProfile(key: string, bucket?: string) { + perfTraces[key] = { + task: key, start: getTimestampMs(), - length: undefined + length: undefined, + globalBucket: bucket }; + } + + export function completeProfile(key: string) { + Debug.assert(!!perfTraces[key], "Completed profile did not have a corresponding start."); + perfTraces[key].length = getTimestampMs(perfTraces[key].start); + } - profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, ext.name, task); + export function startExtensionProfile(level: ProfileLevel, ext: ExtensionBase, task: string, trace?: (s: string) => void) { + if (!level) return; + if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, ext.name, task); + const longTask = createTaskName(ext, task); + startProfile(longTask, getExtensionRootName(ext)); } - export function completeExtensionProfile(ext: ExtensionBase, task: string, trace?: (s: string) => void) { - Debug.assert(!!ext.profiles, "Completed profile, but extension has no started profiles."); - Debug.assert(!!ext.profiles[task], "Completed profile did not have a corresponding start."); - ext.profiles[task].length = getTimestampMs(ext.profiles[task].start); + export function completeExtensionProfile(level: ProfileLevel, ext: ExtensionBase, task: string, trace?: (s: string) => void) { + if (!level) return; + const longTask = createTaskName(ext, task); + completeProfile(longTask); - profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, ext.profiles[task].length.toPrecision(5)); + if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, perfTraces[longTask].length.toPrecision(5)); } export function createExtensionCache(options: CompilerOptions, host: ExtensionHost): ExtensionCache { @@ -169,7 +188,7 @@ namespace ts { const extOptions = options.extensions; const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ""; - const shouldProfile = !!options.profileExtensions; + const profileLevel = options.profileExtensions; const extensionLoadResults = map(extensionNames, name => { let result: any; let error: any; @@ -177,15 +196,14 @@ namespace ts { const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; if (resolved) { try { - let startTime: Timestamp; - if (shouldProfile) { - startTime = getTimestampMs(); - trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); + if (profileLevel) { + startProfile(name, name); + if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); } result = host.loadExtension(resolved.resolvedFileName); - if (shouldProfile) { - const loadTime = getTimestampMs(startTime); - trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", loadTime.toPrecision(5)); + if (profileLevel) { + completeProfile(name); + if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", perfTraces[name].length.toPrecision(5)); } } catch (e) { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index f3b0b210ccf25..ac97944371fda 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1497,16 +1497,16 @@ namespace ts { const diagnostics: Diagnostic[] = []; let activeLint: UniqueLint; let parent: Node | undefined = undefined; - const shouldProfile = !!options.profileExtensions; + const profileLevel = options.profileExtensions; for (let i = 0; i < lints.length; i++) { - if (shouldProfile) startExtensionProfile(lints[i], "construct", host.trace); + startExtensionProfile(profileLevel, lints[i], "construct", host.trace); if (kind === ExtensionKind.SemanticLint) { initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ ts, checker: getTypeChecker(), args: lints[i].args, host, program }), accepted: true }; } else if (kind === ExtensionKind.SyntacticLint) { initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ ts, args: lints[i].args, host, program }), accepted: true }; } - if (shouldProfile) completeExtensionProfile(lints[i], "construct", host.trace); + completeExtensionProfile(profileLevel, lints[i], "construct", host.trace); } let nodesVisited = 0; @@ -1523,9 +1523,9 @@ namespace ts { if (initializedLints[i].accepted) { activeLint = initializedLints[i]; node.parent = parent; - if (shouldProfile) startExtensionProfile(lints[i], `visitNode|${nodesVisited}`, host.trace); + startExtensionProfile(profileLevel, lints[i], `visitNode|${nodesVisited}`, host.trace); activeLint.walker.visit(node, stop, error); - if (shouldProfile) completeExtensionProfile(lints[i], `visitNode|${nodesVisited}`, host.trace); + completeExtensionProfile(profileLevel, lints[i], `visitNode|${nodesVisited}`, host.trace); if (activeLint.accepted) { oneAccepted = true; } diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index e6410d75f8413..696be13148213 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -601,6 +601,22 @@ namespace ts { reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); } + if (compilerOptions.profileExtensions) { + let totalExtensionTime = 0; + const perfTotals = reduceProperties(perfTraces, (aggregate, value, key) => { + if (typeof aggregate[value.globalBucket] !== "number") { + aggregate[value.globalBucket] = 0; + } + aggregate[value.globalBucket] += value.length; + totalExtensionTime += value.length; + return aggregate; + }, {} as {[index: string]: number}); + forEachKey(perfTotals, (key) => { + reportTimeStatistic(`Extension '${key}' time`, perfTotals[key]); + }); + reportTimeStatistic("Total extension time", totalExtensionTime); + } + return { program, exitStatus }; function compileProgram(): ExitStatus { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 98fd547152f55..ab41a7428df6f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2598,11 +2598,17 @@ namespace ts { /*@internal*/ version?: boolean; /*@internal*/ watch?: boolean; extensions?: string[] | Map; - profileExtensions?: boolean; + profileExtensions?: ProfileLevel; [option: string]: CompilerOptionsValue | undefined; } + export const enum ProfileLevel { + None, + Summary, + Full + } + export interface TypingOptions { enableAutoDiscovery?: boolean; include?: string[]; diff --git a/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json b/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json index ccf409f767119..9544e514cb2b6 100644 --- a/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json +++ b/tests/cases/extensions/scenarios/profileExtensionsTraces/test.json @@ -5,6 +5,6 @@ "availableExtensions": ["test-multi-extension"], "compilerOptions": { "extensions": ["test-multi-extension"], - "profileExtensions": true + "profileExtensions": 2 } } \ No newline at end of file From 5c9726295cd8e47cbdf74425e2682383205d0aa0 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 5 Jul 2016 12:30:30 -0700 Subject: [PATCH 32/49] Always print global perf buckets (if any are present) --- src/compiler/tsc.ts | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 696be13148213..1b56d84693952 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -601,21 +601,17 @@ namespace ts { reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); } - if (compilerOptions.profileExtensions) { - let totalExtensionTime = 0; - const perfTotals = reduceProperties(perfTraces, (aggregate, value, key) => { - if (typeof aggregate[value.globalBucket] !== "number") { - aggregate[value.globalBucket] = 0; - } - aggregate[value.globalBucket] += value.length; - totalExtensionTime += value.length; - return aggregate; - }, {} as {[index: string]: number}); - forEachKey(perfTotals, (key) => { - reportTimeStatistic(`Extension '${key}' time`, perfTotals[key]); - }); - reportTimeStatistic("Total extension time", totalExtensionTime); - } + const perfTotals = reduceProperties(perfTraces, (aggregate, value, key) => { + if (!value.globalBucket) return aggregate; + if (typeof aggregate[value.globalBucket] !== "number") { + aggregate[value.globalBucket] = 0; + } + aggregate[value.globalBucket] += value.length; + return aggregate; + }, {} as {[index: string]: number}); + forEachKey(perfTotals, (key) => { + reportTimeStatistic(`'${key}' time`, perfTotals[key]); + }); return { program, exitStatus }; From 625e3cf60c2382f13f33c97f16f9dd2bf77bfe8f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 5 Jul 2016 15:55:53 -0700 Subject: [PATCH 33/49] Resolve paths early - stop considering all files in cache as root files --- src/compiler/extensions.ts | 57 ++++++++++++++++++++-------------- src/harness/extensionRunner.ts | 2 +- src/services/services.ts | 20 ++++++------ 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 226f10701712e..c693f66376dd3 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -160,9 +160,13 @@ namespace ts { if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, perfTraces[longTask].length.toPrecision(5)); } - export function createExtensionCache(options: CompilerOptions, host: ExtensionHost): ExtensionCache { + export function createExtensionCache(options: CompilerOptions, host: ExtensionHost, resolvedExtensionNames?: Map): ExtensionCache { const diagnostics: Diagnostic[] = []; + const extOptions = options.extensions; + const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); + // Eagerly evaluate extension paths, but lazily execute their contents + resolvedExtensionNames = resolvedExtensionNames || resolveExtensionNames(); let extensions: ExtensionCollectionMap; const cache: ExtensionCache = { @@ -184,37 +188,44 @@ namespace ts { profileTrace(host.trace, message, ...args); } - function collectCompilerExtensions(): ExtensionCollectionMap { - const extOptions = options.extensions; - const extensionNames = (extOptions instanceof Array) ? extOptions : getKeys(extOptions); + function resolveExtensionNames(): Map { const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ""; + const extMap: Map = {}; + forEach(extensionNames, name => { + const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; + if (resolved) { + extMap[name] = resolved.resolvedFileName; + } + }) + return extMap; + } + + function collectCompilerExtensions(): ExtensionCollectionMap { const profileLevel = options.profileExtensions; - const extensionLoadResults = map(extensionNames, name => { + const extensionLoadResults = map(extensionNames, (name) => { + const resolved = resolvedExtensionNames[name]; let result: any; let error: any; - if (host.loadExtension) { - const resolved = resolveModuleName(name, combinePaths(currentDirectory, "tsconfig.json"), options, host, /*loadJs*/true).resolvedModule; - if (resolved) { - try { - if (profileLevel) { - startProfile(name, name); - if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); - } - result = host.loadExtension(resolved.resolvedFileName); - if (profileLevel) { - completeProfile(name); - if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", perfTraces[name].length.toPrecision(5)); - } + if (!resolved) { + error = new Error(`Host could not locate extension '${name}'.`); + } + if (resolved && host.loadExtension) { + try { + if (profileLevel) { + startProfile(name, name); + if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); } - catch (e) { - error = e; + result = host.loadExtension(resolved); + if (profileLevel) { + completeProfile(name); + if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", perfTraces[name].length.toPrecision(5)); } } - else { - error = new Error(`Host could not locate extension '${name}'.`); + catch (e) { + error = e; } } - else { + else if (!host.loadExtension) { error = new Error("Extension loading not implemented in host!"); } if (error) { diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index e50d9e1a256b7..63adfde59864c 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -101,7 +101,7 @@ class ExtensionRunner extends RunnerBase { }; makeMockLSHost(files: string[], options: ts.CompilerOptions): ts.LanguageServiceHost { - files = ts.filter(files, file => ts.endsWith(file, ".ts") && !ts.endsWith(file, ".d.ts") && !(file.indexOf("node_modules") >= 0)); + files = ts.filter(files, file => ts.endsWith(file, ".ts") && !ts.endsWith(file, ".d.ts") && (file.indexOf("node_modules") === -1)); const host: ts.LanguageServiceHost = { getCompilationSettings: () => options, getScriptFileNames: () => files, diff --git a/src/services/services.ts b/src/services/services.ts index bb6f3022c8b0f..ced41528847f0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1741,6 +1741,7 @@ namespace ts { version: string; scriptSnapshot: IScriptSnapshot; scriptKind: ScriptKind; + isRoot: boolean; } interface DocumentRegistryEntry { @@ -1817,7 +1818,7 @@ namespace ts { // Initialize the list with the root file names const rootFileNames = host.getScriptFileNames(); for (const fileName of rootFileNames) { - this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName)); + this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName), /*isRoot*/true); } // store the compilation settings @@ -1828,7 +1829,7 @@ namespace ts { return this._compilationSettings; } - private createEntry(fileName: string, path: Path) { + private createEntry(fileName: string, path: Path, isRoot: boolean) { let entry: HostFileInformation; const scriptSnapshot = this.host.getScriptSnapshot(fileName); if (scriptSnapshot) { @@ -1836,7 +1837,8 @@ namespace ts { hostFileName: fileName, version: this.host.getScriptVersion(fileName), scriptSnapshot: scriptSnapshot, - scriptKind: getScriptKind(fileName, this.host) + scriptKind: getScriptKind(fileName, this.host), + isRoot }; } @@ -1860,14 +1862,14 @@ namespace ts { public getOrCreateEntryByPath(fileName: string, path: Path): HostFileInformation { return this.contains(path) ? this.getEntry(path) - : this.createEntry(fileName, path); + : this.createEntry(fileName, path, /*isRoot*/false); } public getRootFileNames(): string[] { const fileNames: string[] = []; this.fileNameToEntry.forEachValue((path, value) => { - if (value) { + if (value && value.isRoot) { fileNames.push(value.hostFileName); } }); @@ -2978,7 +2980,7 @@ namespace ts { } // Get a fresh cache of the host information - const hostCache = new HostCache(host, getCanonicalFileName); + let hostCache = new HostCache(host, getCanonicalFileName); // If the program is already up-to-date, we can reuse it if (programUpToDate()) { @@ -3015,11 +3017,13 @@ namespace ts { getCurrentDirectory: () => currentDirectory, fileExists: (fileName): boolean => { // stub missing host functionality + Debug.assert(!!hostCache, "LS CompilerHost may not persist beyond the execution of a synchronize call"); Debug.assert(!host.resolveModuleNames || !host.resolveTypeReferenceDirectives); return hostCache.getOrCreateEntry(fileName) !== undefined; }, readFile: (fileName): string => { // stub missing host functionality + Debug.assert(!!hostCache, "LS CompilerHost may not persist beyond the execution of a synchronize call"); const entry = hostCache.getOrCreateEntry(fileName); return entry && entry.scriptSnapshot.getText(0, entry.scriptSnapshot.getLength()); }, @@ -3068,9 +3072,7 @@ namespace ts { // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. // It needs to be cleared to allow all collected snapshots to be released - // TODO (weswig): hostCache needs to exist as long as its associated compilerHost exists, since it is used in fileExists. - // As such, we cannot release it here - it must be tied to the lifetime of the compilerHost. - // hostCache = undefined; + hostCache = undefined; program = newProgram; From ed12a9c959a5c503bcc9623e24cd5b8e20fc4e78 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Jul 2016 15:18:53 -0700 Subject: [PATCH 34/49] Do not retain programs from compiler extension compilations --- src/harness/extensionRunner.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index 63adfde59864c..12d39dd83bc3c 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -157,7 +157,7 @@ class ExtensionRunner extends RunnerBase { const allDiagnostics = ts.sortAndDeduplicateDiagnostics(ts.concatenate(diagnostics, emitResult.diagnostics)); - return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, service.getProgram(), host.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); + return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, /*program*/undefined, host.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); function writeFile(fileName: string, code: string, writeByteOrderMark: boolean, onError: (message: string) => void, sourceFiles: ts.SourceFile[]) { fileResults.push({ @@ -178,7 +178,7 @@ class ExtensionRunner extends RunnerBase { const allDiagnostics = ts.sortAndDeduplicateDiagnostics(ts.concatenate(diagnostics, emitResult.diagnostics)); - return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, program, this.mockHost.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); + return new Harness.Compiler.CompilerResult(fileResults, allDiagnostics, /*program*/undefined, this.mockHost.getCurrentDirectory(), emitResult.sourceMaps, this.getTraces()); function writeFile(fileName: string, code: string, writeByteOrderMark: boolean, onError: (message: string) => void, sourceFiles: ts.SourceFile[]) { fileResults.push({ fileName, From b4fc76c3a1a6cf58d04fa2ff3822173bed882026 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Jul 2016 16:07:58 -0700 Subject: [PATCH 35/49] Actually accept the baselines for the LS extension tests --- .../can-add-program-diagnostics.js | 5 + .../can-chain-services.errors.txt | 10 + .../can-chain-services.js | 5 + .../can-filter-all-functions.errors.txt | 653 ++++++++++++++++++ .../can-filter-all-functions.js | 117 ++++ .../can-filter-passthru.errors.txt | 10 + .../can-filter-passthru.js | 5 + .../can-override-all-functions.errors.txt | 653 ++++++++++++++++++ .../can-override-all-functions.js | 117 ++++ .../can-add-program-diagnostics.errors.txt | 6 + .../can-add-program-diagnostics.js | 5 + .../can-chain-services.errors.txt | 16 + .../can-chain-services.js | 5 + .../can-filter-all-functions.errors.txt | 20 + .../can-filter-all-functions.js | 117 ++++ .../can-filter-passthru.errors.txt | 10 + .../can-filter-passthru.js | 5 + .../can-override-all-functions.errors.txt | 20 + .../can-override-all-functions.js | 117 ++++ 19 files changed, 1896 insertions(+) create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.js create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.js create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.js create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.errors.txt create mode 100644 tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.js create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.js create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.js create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.js create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.errors.txt create mode 100644 tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.js diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js new file mode 100644 index 0000000000000..359dd9ef1ec96 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.errors.txt b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.errors.txt new file mode 100644 index 0000000000000..5402510857df8 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.errors.txt @@ -0,0 +1,10 @@ +/hello-error.ts(1,1): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +/hello-error.ts(1,31): error TS1109: Expression expected. + + +==== /hello-error.ts (2 errors) ==== + console.log("Hello, error!") - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. + +!!! error TS1109: Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.js new file mode 100644 index 0000000000000..10802294f21ba --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-chain-services.js @@ -0,0 +1,5 @@ +//// [hello-error.ts] +console.log("Hello, error!") - + +//// [hello-error.js] +console.log("Hello, error!") - ; diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.errors.txt b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.errors.txt new file mode 100644 index 0000000000000..c268502890d90 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.errors.txt @@ -0,0 +1,653 @@ +/atotc.ts(1,1): error TS2304: Cannot find name 'It'. +/atotc.ts(1,4): error TS1005: ';' expected. +/atotc.ts(1,4): error TS2304: Cannot find name 'was'. +/atotc.ts(1,8): error TS1005: ';' expected. +/atotc.ts(1,8): error TS2304: Cannot find name 'the'. +/atotc.ts(1,12): error TS1005: ';' expected. +/atotc.ts(1,12): error TS2304: Cannot find name 'best'. +/atotc.ts(1,17): error TS1005: ';' expected. +/atotc.ts(1,17): error TS2304: Cannot find name 'of'. +/atotc.ts(1,20): error TS1005: ';' expected. +/atotc.ts(1,20): error TS2304: Cannot find name 'times'. +/atotc.ts(1,27): error TS2304: Cannot find name 'it'. +/atotc.ts(1,30): error TS1005: ';' expected. +/atotc.ts(1,30): error TS2304: Cannot find name 'was'. +/atotc.ts(1,34): error TS1005: ';' expected. +/atotc.ts(1,34): error TS2304: Cannot find name 'the'. +/atotc.ts(1,38): error TS1005: ';' expected. +/atotc.ts(1,38): error TS2304: Cannot find name 'worst'. +/atotc.ts(1,44): error TS1005: ';' expected. +/atotc.ts(1,44): error TS2304: Cannot find name 'of'. +/atotc.ts(1,47): error TS1005: ';' expected. +/atotc.ts(1,47): error TS2304: Cannot find name 'times'. +/atotc.ts(2,1): error TS2304: Cannot find name 'it'. +/atotc.ts(2,4): error TS1005: ';' expected. +/atotc.ts(2,4): error TS2304: Cannot find name 'was'. +/atotc.ts(2,8): error TS1005: ';' expected. +/atotc.ts(2,8): error TS2304: Cannot find name 'the'. +/atotc.ts(2,12): error TS1005: ';' expected. +/atotc.ts(2,12): error TS2304: Cannot find name 'age'. +/atotc.ts(2,16): error TS1005: ';' expected. +/atotc.ts(2,16): error TS2304: Cannot find name 'of'. +/atotc.ts(2,19): error TS1005: ';' expected. +/atotc.ts(2,19): error TS2304: Cannot find name 'wisdom'. +/atotc.ts(2,27): error TS2304: Cannot find name 'it'. +/atotc.ts(2,30): error TS1005: ';' expected. +/atotc.ts(2,30): error TS2304: Cannot find name 'was'. +/atotc.ts(2,34): error TS1005: ';' expected. +/atotc.ts(2,34): error TS2304: Cannot find name 'the'. +/atotc.ts(2,38): error TS1005: ';' expected. +/atotc.ts(2,38): error TS2304: Cannot find name 'age'. +/atotc.ts(2,42): error TS1005: ';' expected. +/atotc.ts(2,42): error TS2304: Cannot find name 'of'. +/atotc.ts(2,45): error TS1005: ';' expected. +/atotc.ts(2,45): error TS2304: Cannot find name 'foolishness'. +/atotc.ts(3,1): error TS2304: Cannot find name 'it'. +/atotc.ts(3,4): error TS1005: ';' expected. +/atotc.ts(3,4): error TS2304: Cannot find name 'was'. +/atotc.ts(3,8): error TS1005: ';' expected. +/atotc.ts(3,8): error TS2304: Cannot find name 'the'. +/atotc.ts(3,12): error TS1005: ';' expected. +/atotc.ts(3,12): error TS2304: Cannot find name 'epoch'. +/atotc.ts(3,18): error TS1005: ';' expected. +/atotc.ts(3,18): error TS2304: Cannot find name 'of'. +/atotc.ts(3,21): error TS1005: ';' expected. +/atotc.ts(3,21): error TS2304: Cannot find name 'belief'. +/atotc.ts(3,29): error TS2304: Cannot find name 'it'. +/atotc.ts(3,32): error TS1005: ';' expected. +/atotc.ts(3,32): error TS2304: Cannot find name 'was'. +/atotc.ts(3,36): error TS1005: ';' expected. +/atotc.ts(3,36): error TS2304: Cannot find name 'the'. +/atotc.ts(3,40): error TS1005: ';' expected. +/atotc.ts(3,40): error TS2304: Cannot find name 'epoch'. +/atotc.ts(3,46): error TS1005: ';' expected. +/atotc.ts(3,46): error TS2304: Cannot find name 'of'. +/atotc.ts(3,49): error TS1005: ';' expected. +/atotc.ts(3,49): error TS2304: Cannot find name 'incredulity'. +/atotc.ts(4,1): error TS2304: Cannot find name 'it'. +/atotc.ts(4,4): error TS1005: ';' expected. +/atotc.ts(4,4): error TS2304: Cannot find name 'was'. +/atotc.ts(4,8): error TS1005: ';' expected. +/atotc.ts(4,8): error TS2304: Cannot find name 'the'. +/atotc.ts(4,12): error TS1005: ';' expected. +/atotc.ts(4,12): error TS2304: Cannot find name 'season'. +/atotc.ts(4,19): error TS1005: ';' expected. +/atotc.ts(4,19): error TS2304: Cannot find name 'of'. +/atotc.ts(4,22): error TS1005: ';' expected. +/atotc.ts(4,22): error TS2304: Cannot find name 'Light'. +/atotc.ts(4,29): error TS2304: Cannot find name 'it'. +/atotc.ts(4,32): error TS1005: ';' expected. +/atotc.ts(4,32): error TS2304: Cannot find name 'was'. +/atotc.ts(4,36): error TS1005: ';' expected. +/atotc.ts(4,36): error TS2304: Cannot find name 'the'. +/atotc.ts(4,40): error TS1005: ';' expected. +/atotc.ts(4,40): error TS2304: Cannot find name 'season'. +/atotc.ts(4,47): error TS1005: ';' expected. +/atotc.ts(4,47): error TS2304: Cannot find name 'of'. +/atotc.ts(4,50): error TS1005: ';' expected. +/atotc.ts(4,50): error TS2304: Cannot find name 'Darkness'. +/atotc.ts(5,1): error TS2304: Cannot find name 'it'. +/atotc.ts(5,4): error TS1005: ';' expected. +/atotc.ts(5,4): error TS2304: Cannot find name 'was'. +/atotc.ts(5,8): error TS1005: ';' expected. +/atotc.ts(5,8): error TS2304: Cannot find name 'the'. +/atotc.ts(5,12): error TS1005: ';' expected. +/atotc.ts(5,12): error TS2304: Cannot find name 'spring'. +/atotc.ts(5,19): error TS1005: ';' expected. +/atotc.ts(5,19): error TS2304: Cannot find name 'of'. +/atotc.ts(5,22): error TS1005: ';' expected. +/atotc.ts(5,22): error TS2304: Cannot find name 'hope'. +/atotc.ts(5,28): error TS2304: Cannot find name 'it'. +/atotc.ts(5,31): error TS1005: ';' expected. +/atotc.ts(5,31): error TS2304: Cannot find name 'was'. +/atotc.ts(5,35): error TS1005: ';' expected. +/atotc.ts(5,35): error TS2304: Cannot find name 'the'. +/atotc.ts(5,39): error TS1005: ';' expected. +/atotc.ts(5,39): error TS2304: Cannot find name 'winter'. +/atotc.ts(5,46): error TS1005: ';' expected. +/atotc.ts(5,46): error TS2304: Cannot find name 'of'. +/atotc.ts(5,49): error TS1005: ';' expected. +/atotc.ts(5,49): error TS2304: Cannot find name 'despair'. +/atotc.ts(6,1): error TS2304: Cannot find name 'we'. +/atotc.ts(6,4): error TS1005: ';' expected. +/atotc.ts(6,4): error TS2304: Cannot find name 'had'. +/atotc.ts(6,8): error TS1005: ';' expected. +/atotc.ts(6,8): error TS2304: Cannot find name 'everything'. +/atotc.ts(6,19): error TS1005: ';' expected. +/atotc.ts(6,19): error TS2304: Cannot find name 'before'. +/atotc.ts(6,26): error TS1005: ';' expected. +/atotc.ts(6,26): error TS2304: Cannot find name 'us'. +/atotc.ts(6,30): error TS2304: Cannot find name 'we'. +/atotc.ts(6,33): error TS1005: ';' expected. +/atotc.ts(6,33): error TS2304: Cannot find name 'had'. +/atotc.ts(6,37): error TS1005: ';' expected. +/atotc.ts(6,37): error TS2304: Cannot find name 'nothing'. +/atotc.ts(6,45): error TS1005: ';' expected. +/atotc.ts(6,45): error TS2304: Cannot find name 'before'. +/atotc.ts(6,52): error TS1005: ';' expected. +/atotc.ts(6,52): error TS2304: Cannot find name 'us'. +/atotc.ts(7,1): error TS2304: Cannot find name 'we'. +/atotc.ts(7,4): error TS1005: ';' expected. +/atotc.ts(7,4): error TS2304: Cannot find name 'were'. +/atotc.ts(7,9): error TS1005: ';' expected. +/atotc.ts(7,9): error TS2304: Cannot find name 'all'. +/atotc.ts(7,13): error TS1005: ';' expected. +/atotc.ts(7,13): error TS2304: Cannot find name 'going'. +/atotc.ts(7,19): error TS1005: ';' expected. +/atotc.ts(7,19): error TS2304: Cannot find name 'direct'. +/atotc.ts(7,26): error TS1005: ';' expected. +/atotc.ts(7,26): error TS2304: Cannot find name 'to'. +/atotc.ts(7,29): error TS1005: ';' expected. +/atotc.ts(7,29): error TS2304: Cannot find name 'Heaven'. +/atotc.ts(7,37): error TS2304: Cannot find name 'we'. +/atotc.ts(7,40): error TS1005: ';' expected. +/atotc.ts(7,40): error TS2304: Cannot find name 'were'. +/atotc.ts(7,45): error TS1005: ';' expected. +/atotc.ts(7,45): error TS2304: Cannot find name 'all'. +/atotc.ts(7,49): error TS1005: ';' expected. +/atotc.ts(7,49): error TS2304: Cannot find name 'going'. +/atotc.ts(7,55): error TS1005: ';' expected. +/atotc.ts(7,55): error TS2304: Cannot find name 'direct'. +/atotc.ts(8,1): error TS2304: Cannot find name 'the'. +/atotc.ts(8,5): error TS1005: ';' expected. +/atotc.ts(8,5): error TS2304: Cannot find name 'other'. +/atotc.ts(8,11): error TS1005: ';' expected. +/atotc.ts(8,11): error TS2304: Cannot find name 'way'. +/atotc.ts(8,19): error TS2304: Cannot find name 'short'. +/atotc.ts(8,26): error TS2304: Cannot find name 'the'. +/atotc.ts(8,30): error TS1005: ';' expected. +/atotc.ts(8,30): error TS2304: Cannot find name 'period'. +/atotc.ts(8,37): error TS1005: ';' expected. +/atotc.ts(8,37): error TS2304: Cannot find name 'was'. +/atotc.ts(8,41): error TS1005: ';' expected. +/atotc.ts(8,41): error TS2304: Cannot find name 'so'. +/atotc.ts(8,44): error TS1005: ';' expected. +/atotc.ts(8,44): error TS2304: Cannot find name 'far'. +/atotc.ts(8,48): error TS1005: ';' expected. +/atotc.ts(8,48): error TS2304: Cannot find name 'like'. +/atotc.ts(8,53): error TS1005: ';' expected. +/atotc.ts(8,53): error TS2304: Cannot find name 'the'. +/atotc.ts(8,57): error TS1005: ';' expected. +/atotc.ts(8,57): error TS2304: Cannot find name 'present'. +/atotc.ts(9,1): error TS2304: Cannot find name 'period'. +/atotc.ts(9,9): error TS2304: Cannot find name 'that'. +/atotc.ts(9,14): error TS1005: ';' expected. +/atotc.ts(9,14): error TS2304: Cannot find name 'some'. +/atotc.ts(9,19): error TS1005: ';' expected. +/atotc.ts(9,19): error TS2304: Cannot find name 'of'. +/atotc.ts(9,22): error TS1005: ';' expected. +/atotc.ts(9,22): error TS2304: Cannot find name 'its'. +/atotc.ts(9,26): error TS1005: ';' expected. +/atotc.ts(9,26): error TS2304: Cannot find name 'noisiest'. +/atotc.ts(9,35): error TS1005: ';' expected. +/atotc.ts(9,35): error TS2304: Cannot find name 'authorities'. +/atotc.ts(9,47): error TS1005: ';' expected. +/atotc.ts(9,47): error TS2304: Cannot find name 'insisted'. +/atotc.ts(9,56): error TS1005: ';' expected. +/atotc.ts(9,56): error TS2304: Cannot find name 'on'. +/atotc.ts(9,59): error TS1005: ';' expected. +/atotc.ts(9,59): error TS2304: Cannot find name 'its'. +/atotc.ts(10,1): error TS2304: Cannot find name 'being'. +/atotc.ts(10,7): error TS1005: ';' expected. +/atotc.ts(10,7): error TS2304: Cannot find name 'received'. +/atotc.ts(10,17): error TS1109: Expression expected. +/atotc.ts(10,21): error TS1005: '(' expected. +/atotc.ts(10,21): error TS2304: Cannot find name 'good'. +/atotc.ts(10,26): error TS1005: ';' expected. +/atotc.ts(10,26): error TS2304: Cannot find name 'or'. +/atotc.ts(10,29): error TS1005: ';' expected. +/atotc.ts(10,33): error TS1005: '(' expected. +/atotc.ts(10,33): error TS2304: Cannot find name 'evil'. +/atotc.ts(10,33): error TS2406: Invalid left-hand side in 'for...in' statement. +/atotc.ts(10,39): error TS1109: Expression expected. +/atotc.ts(10,42): error TS2304: Cannot find name 'the'. +/atotc.ts(10,46): error TS1005: ')' expected. +/atotc.ts(10,46): error TS2304: Cannot find name 'superlative'. +/atotc.ts(10,58): error TS1005: ';' expected. +/atotc.ts(10,58): error TS2304: Cannot find name 'degree'. +/atotc.ts(11,1): error TS2304: Cannot find name 'of'. +/atotc.ts(11,4): error TS1005: ';' expected. +/atotc.ts(11,4): error TS2304: Cannot find name 'comparison'. +/atotc.ts(11,15): error TS1005: ';' expected. +/atotc.ts(11,15): error TS2304: Cannot find name 'only'. +/atotc.ts(11,20): error TS1003: Identifier expected. + + +==== /atotc.ts (213 errors) ==== + It was the best of times, it was the worst of times, + ~~ +!!! error TS2304: Cannot find name 'It'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'best'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'times'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'worst'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'times'. + it was the age of wisdom, it was the age of foolishness, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'age'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'wisdom'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'age'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'foolishness'. + it was the epoch of belief, it was the epoch of incredulity, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'epoch'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'belief'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'epoch'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'incredulity'. + it was the season of Light, it was the season of Darkness, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'season'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'Light'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'season'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'Darkness'. + it was the spring of hope, it was the winter of despair, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'spring'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'hope'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'winter'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'despair'. + we had everything before us, we had nothing before us, + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'had'. + ~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'everything'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'before'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'us'. + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'had'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'nothing'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'before'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'us'. + we were all going direct to Heaven, we were all going direct + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'were'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'all'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'going'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'direct'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'to'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'Heaven'. + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'were'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'all'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'going'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'direct'. + the other way--in short, the period was so far like the present + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'other'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'way'. + ~~~~~ +!!! error TS2304: Cannot find name 'short'. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'period'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'so'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'far'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'like'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'present'. + period, that some of its noisiest authorities insisted on its + ~~~~~~ +!!! error TS2304: Cannot find name 'period'. + ~~~~ +!!! error TS2304: Cannot find name 'that'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'some'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'its'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'noisiest'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'authorities'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'insisted'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'on'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'its'. + being received, for good or for evil, in the superlative degree + ~~~~~ +!!! error TS2304: Cannot find name 'being'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'received'. + ~~~ +!!! error TS1109: Expression expected. + ~~~~ +!!! error TS1005: '(' expected. + ~~~~ +!!! error TS2304: Cannot find name 'good'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'or'. + ~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS1005: '(' expected. + ~~~~ +!!! error TS2304: Cannot find name 'evil'. + ~~~~~ +!!! error TS2406: Invalid left-hand side in 'for...in' statement. + ~~ +!!! error TS1109: Expression expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~~~~~~ +!!! error TS1005: ')' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'superlative'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'degree'. + of comparison only. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'comparison'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'only'. + +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.js new file mode 100644 index 0000000000000..30c1de3575183 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-all-functions.js @@ -0,0 +1,117 @@ +//// [atotc.ts] +It was the best of times, it was the worst of times, +it was the age of wisdom, it was the age of foolishness, +it was the epoch of belief, it was the epoch of incredulity, +it was the season of Light, it was the season of Darkness, +it was the spring of hope, it was the winter of despair, +we had everything before us, we had nothing before us, +we were all going direct to Heaven, we were all going direct +the other way--in short, the period was so far like the present +period, that some of its noisiest authorities insisted on its +being received, for good or for evil, in the superlative degree +of comparison only. + +//// [atotc.js] +It; +was; +the; +best; +of; +times, it; +was; +the; +worst; +of; +times, + it; +was; +the; +age; +of; +wisdom, it; +was; +the; +age; +of; +foolishness, + it; +was; +the; +epoch; +of; +belief, it; +was; +the; +epoch; +of; +incredulity, + it; +was; +the; +season; +of; +Light, it; +was; +the; +season; +of; +Darkness, + it; +was; +the; +spring; +of; +hope, it; +was; +the; +winter; +of; +despair, + we; +had; +everything; +before; +us, we; +had; +nothing; +before; +us, + we; +were; +all; +going; +direct; +to; +Heaven, we; +were; +all; +going; +direct; +the; +other; +way-- in short, the; +period; +was; +so; +far; +like; +the; +present; +period, that; +some; +of; +its; +noisiest; +authorities; +insisted; +on; +its; +being; +received, ; +for (good; or; ) + for (evil, in the) + superlative; +degree; +of; +comparison; +only.; diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.errors.txt b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.errors.txt new file mode 100644 index 0000000000000..5402510857df8 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.errors.txt @@ -0,0 +1,10 @@ +/hello-error.ts(1,1): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +/hello-error.ts(1,31): error TS1109: Expression expected. + + +==== /hello-error.ts (2 errors) ==== + console.log("Hello, error!") - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. + +!!! error TS1109: Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.js new file mode 100644 index 0000000000000..10802294f21ba --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-filter-passthru.js @@ -0,0 +1,5 @@ +//// [hello-error.ts] +console.log("Hello, error!") - + +//// [hello-error.js] +console.log("Hello, error!") - ; diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.errors.txt b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.errors.txt new file mode 100644 index 0000000000000..c268502890d90 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.errors.txt @@ -0,0 +1,653 @@ +/atotc.ts(1,1): error TS2304: Cannot find name 'It'. +/atotc.ts(1,4): error TS1005: ';' expected. +/atotc.ts(1,4): error TS2304: Cannot find name 'was'. +/atotc.ts(1,8): error TS1005: ';' expected. +/atotc.ts(1,8): error TS2304: Cannot find name 'the'. +/atotc.ts(1,12): error TS1005: ';' expected. +/atotc.ts(1,12): error TS2304: Cannot find name 'best'. +/atotc.ts(1,17): error TS1005: ';' expected. +/atotc.ts(1,17): error TS2304: Cannot find name 'of'. +/atotc.ts(1,20): error TS1005: ';' expected. +/atotc.ts(1,20): error TS2304: Cannot find name 'times'. +/atotc.ts(1,27): error TS2304: Cannot find name 'it'. +/atotc.ts(1,30): error TS1005: ';' expected. +/atotc.ts(1,30): error TS2304: Cannot find name 'was'. +/atotc.ts(1,34): error TS1005: ';' expected. +/atotc.ts(1,34): error TS2304: Cannot find name 'the'. +/atotc.ts(1,38): error TS1005: ';' expected. +/atotc.ts(1,38): error TS2304: Cannot find name 'worst'. +/atotc.ts(1,44): error TS1005: ';' expected. +/atotc.ts(1,44): error TS2304: Cannot find name 'of'. +/atotc.ts(1,47): error TS1005: ';' expected. +/atotc.ts(1,47): error TS2304: Cannot find name 'times'. +/atotc.ts(2,1): error TS2304: Cannot find name 'it'. +/atotc.ts(2,4): error TS1005: ';' expected. +/atotc.ts(2,4): error TS2304: Cannot find name 'was'. +/atotc.ts(2,8): error TS1005: ';' expected. +/atotc.ts(2,8): error TS2304: Cannot find name 'the'. +/atotc.ts(2,12): error TS1005: ';' expected. +/atotc.ts(2,12): error TS2304: Cannot find name 'age'. +/atotc.ts(2,16): error TS1005: ';' expected. +/atotc.ts(2,16): error TS2304: Cannot find name 'of'. +/atotc.ts(2,19): error TS1005: ';' expected. +/atotc.ts(2,19): error TS2304: Cannot find name 'wisdom'. +/atotc.ts(2,27): error TS2304: Cannot find name 'it'. +/atotc.ts(2,30): error TS1005: ';' expected. +/atotc.ts(2,30): error TS2304: Cannot find name 'was'. +/atotc.ts(2,34): error TS1005: ';' expected. +/atotc.ts(2,34): error TS2304: Cannot find name 'the'. +/atotc.ts(2,38): error TS1005: ';' expected. +/atotc.ts(2,38): error TS2304: Cannot find name 'age'. +/atotc.ts(2,42): error TS1005: ';' expected. +/atotc.ts(2,42): error TS2304: Cannot find name 'of'. +/atotc.ts(2,45): error TS1005: ';' expected. +/atotc.ts(2,45): error TS2304: Cannot find name 'foolishness'. +/atotc.ts(3,1): error TS2304: Cannot find name 'it'. +/atotc.ts(3,4): error TS1005: ';' expected. +/atotc.ts(3,4): error TS2304: Cannot find name 'was'. +/atotc.ts(3,8): error TS1005: ';' expected. +/atotc.ts(3,8): error TS2304: Cannot find name 'the'. +/atotc.ts(3,12): error TS1005: ';' expected. +/atotc.ts(3,12): error TS2304: Cannot find name 'epoch'. +/atotc.ts(3,18): error TS1005: ';' expected. +/atotc.ts(3,18): error TS2304: Cannot find name 'of'. +/atotc.ts(3,21): error TS1005: ';' expected. +/atotc.ts(3,21): error TS2304: Cannot find name 'belief'. +/atotc.ts(3,29): error TS2304: Cannot find name 'it'. +/atotc.ts(3,32): error TS1005: ';' expected. +/atotc.ts(3,32): error TS2304: Cannot find name 'was'. +/atotc.ts(3,36): error TS1005: ';' expected. +/atotc.ts(3,36): error TS2304: Cannot find name 'the'. +/atotc.ts(3,40): error TS1005: ';' expected. +/atotc.ts(3,40): error TS2304: Cannot find name 'epoch'. +/atotc.ts(3,46): error TS1005: ';' expected. +/atotc.ts(3,46): error TS2304: Cannot find name 'of'. +/atotc.ts(3,49): error TS1005: ';' expected. +/atotc.ts(3,49): error TS2304: Cannot find name 'incredulity'. +/atotc.ts(4,1): error TS2304: Cannot find name 'it'. +/atotc.ts(4,4): error TS1005: ';' expected. +/atotc.ts(4,4): error TS2304: Cannot find name 'was'. +/atotc.ts(4,8): error TS1005: ';' expected. +/atotc.ts(4,8): error TS2304: Cannot find name 'the'. +/atotc.ts(4,12): error TS1005: ';' expected. +/atotc.ts(4,12): error TS2304: Cannot find name 'season'. +/atotc.ts(4,19): error TS1005: ';' expected. +/atotc.ts(4,19): error TS2304: Cannot find name 'of'. +/atotc.ts(4,22): error TS1005: ';' expected. +/atotc.ts(4,22): error TS2304: Cannot find name 'Light'. +/atotc.ts(4,29): error TS2304: Cannot find name 'it'. +/atotc.ts(4,32): error TS1005: ';' expected. +/atotc.ts(4,32): error TS2304: Cannot find name 'was'. +/atotc.ts(4,36): error TS1005: ';' expected. +/atotc.ts(4,36): error TS2304: Cannot find name 'the'. +/atotc.ts(4,40): error TS1005: ';' expected. +/atotc.ts(4,40): error TS2304: Cannot find name 'season'. +/atotc.ts(4,47): error TS1005: ';' expected. +/atotc.ts(4,47): error TS2304: Cannot find name 'of'. +/atotc.ts(4,50): error TS1005: ';' expected. +/atotc.ts(4,50): error TS2304: Cannot find name 'Darkness'. +/atotc.ts(5,1): error TS2304: Cannot find name 'it'. +/atotc.ts(5,4): error TS1005: ';' expected. +/atotc.ts(5,4): error TS2304: Cannot find name 'was'. +/atotc.ts(5,8): error TS1005: ';' expected. +/atotc.ts(5,8): error TS2304: Cannot find name 'the'. +/atotc.ts(5,12): error TS1005: ';' expected. +/atotc.ts(5,12): error TS2304: Cannot find name 'spring'. +/atotc.ts(5,19): error TS1005: ';' expected. +/atotc.ts(5,19): error TS2304: Cannot find name 'of'. +/atotc.ts(5,22): error TS1005: ';' expected. +/atotc.ts(5,22): error TS2304: Cannot find name 'hope'. +/atotc.ts(5,28): error TS2304: Cannot find name 'it'. +/atotc.ts(5,31): error TS1005: ';' expected. +/atotc.ts(5,31): error TS2304: Cannot find name 'was'. +/atotc.ts(5,35): error TS1005: ';' expected. +/atotc.ts(5,35): error TS2304: Cannot find name 'the'. +/atotc.ts(5,39): error TS1005: ';' expected. +/atotc.ts(5,39): error TS2304: Cannot find name 'winter'. +/atotc.ts(5,46): error TS1005: ';' expected. +/atotc.ts(5,46): error TS2304: Cannot find name 'of'. +/atotc.ts(5,49): error TS1005: ';' expected. +/atotc.ts(5,49): error TS2304: Cannot find name 'despair'. +/atotc.ts(6,1): error TS2304: Cannot find name 'we'. +/atotc.ts(6,4): error TS1005: ';' expected. +/atotc.ts(6,4): error TS2304: Cannot find name 'had'. +/atotc.ts(6,8): error TS1005: ';' expected. +/atotc.ts(6,8): error TS2304: Cannot find name 'everything'. +/atotc.ts(6,19): error TS1005: ';' expected. +/atotc.ts(6,19): error TS2304: Cannot find name 'before'. +/atotc.ts(6,26): error TS1005: ';' expected. +/atotc.ts(6,26): error TS2304: Cannot find name 'us'. +/atotc.ts(6,30): error TS2304: Cannot find name 'we'. +/atotc.ts(6,33): error TS1005: ';' expected. +/atotc.ts(6,33): error TS2304: Cannot find name 'had'. +/atotc.ts(6,37): error TS1005: ';' expected. +/atotc.ts(6,37): error TS2304: Cannot find name 'nothing'. +/atotc.ts(6,45): error TS1005: ';' expected. +/atotc.ts(6,45): error TS2304: Cannot find name 'before'. +/atotc.ts(6,52): error TS1005: ';' expected. +/atotc.ts(6,52): error TS2304: Cannot find name 'us'. +/atotc.ts(7,1): error TS2304: Cannot find name 'we'. +/atotc.ts(7,4): error TS1005: ';' expected. +/atotc.ts(7,4): error TS2304: Cannot find name 'were'. +/atotc.ts(7,9): error TS1005: ';' expected. +/atotc.ts(7,9): error TS2304: Cannot find name 'all'. +/atotc.ts(7,13): error TS1005: ';' expected. +/atotc.ts(7,13): error TS2304: Cannot find name 'going'. +/atotc.ts(7,19): error TS1005: ';' expected. +/atotc.ts(7,19): error TS2304: Cannot find name 'direct'. +/atotc.ts(7,26): error TS1005: ';' expected. +/atotc.ts(7,26): error TS2304: Cannot find name 'to'. +/atotc.ts(7,29): error TS1005: ';' expected. +/atotc.ts(7,29): error TS2304: Cannot find name 'Heaven'. +/atotc.ts(7,37): error TS2304: Cannot find name 'we'. +/atotc.ts(7,40): error TS1005: ';' expected. +/atotc.ts(7,40): error TS2304: Cannot find name 'were'. +/atotc.ts(7,45): error TS1005: ';' expected. +/atotc.ts(7,45): error TS2304: Cannot find name 'all'. +/atotc.ts(7,49): error TS1005: ';' expected. +/atotc.ts(7,49): error TS2304: Cannot find name 'going'. +/atotc.ts(7,55): error TS1005: ';' expected. +/atotc.ts(7,55): error TS2304: Cannot find name 'direct'. +/atotc.ts(8,1): error TS2304: Cannot find name 'the'. +/atotc.ts(8,5): error TS1005: ';' expected. +/atotc.ts(8,5): error TS2304: Cannot find name 'other'. +/atotc.ts(8,11): error TS1005: ';' expected. +/atotc.ts(8,11): error TS2304: Cannot find name 'way'. +/atotc.ts(8,19): error TS2304: Cannot find name 'short'. +/atotc.ts(8,26): error TS2304: Cannot find name 'the'. +/atotc.ts(8,30): error TS1005: ';' expected. +/atotc.ts(8,30): error TS2304: Cannot find name 'period'. +/atotc.ts(8,37): error TS1005: ';' expected. +/atotc.ts(8,37): error TS2304: Cannot find name 'was'. +/atotc.ts(8,41): error TS1005: ';' expected. +/atotc.ts(8,41): error TS2304: Cannot find name 'so'. +/atotc.ts(8,44): error TS1005: ';' expected. +/atotc.ts(8,44): error TS2304: Cannot find name 'far'. +/atotc.ts(8,48): error TS1005: ';' expected. +/atotc.ts(8,48): error TS2304: Cannot find name 'like'. +/atotc.ts(8,53): error TS1005: ';' expected. +/atotc.ts(8,53): error TS2304: Cannot find name 'the'. +/atotc.ts(8,57): error TS1005: ';' expected. +/atotc.ts(8,57): error TS2304: Cannot find name 'present'. +/atotc.ts(9,1): error TS2304: Cannot find name 'period'. +/atotc.ts(9,9): error TS2304: Cannot find name 'that'. +/atotc.ts(9,14): error TS1005: ';' expected. +/atotc.ts(9,14): error TS2304: Cannot find name 'some'. +/atotc.ts(9,19): error TS1005: ';' expected. +/atotc.ts(9,19): error TS2304: Cannot find name 'of'. +/atotc.ts(9,22): error TS1005: ';' expected. +/atotc.ts(9,22): error TS2304: Cannot find name 'its'. +/atotc.ts(9,26): error TS1005: ';' expected. +/atotc.ts(9,26): error TS2304: Cannot find name 'noisiest'. +/atotc.ts(9,35): error TS1005: ';' expected. +/atotc.ts(9,35): error TS2304: Cannot find name 'authorities'. +/atotc.ts(9,47): error TS1005: ';' expected. +/atotc.ts(9,47): error TS2304: Cannot find name 'insisted'. +/atotc.ts(9,56): error TS1005: ';' expected. +/atotc.ts(9,56): error TS2304: Cannot find name 'on'. +/atotc.ts(9,59): error TS1005: ';' expected. +/atotc.ts(9,59): error TS2304: Cannot find name 'its'. +/atotc.ts(10,1): error TS2304: Cannot find name 'being'. +/atotc.ts(10,7): error TS1005: ';' expected. +/atotc.ts(10,7): error TS2304: Cannot find name 'received'. +/atotc.ts(10,17): error TS1109: Expression expected. +/atotc.ts(10,21): error TS1005: '(' expected. +/atotc.ts(10,21): error TS2304: Cannot find name 'good'. +/atotc.ts(10,26): error TS1005: ';' expected. +/atotc.ts(10,26): error TS2304: Cannot find name 'or'. +/atotc.ts(10,29): error TS1005: ';' expected. +/atotc.ts(10,33): error TS1005: '(' expected. +/atotc.ts(10,33): error TS2304: Cannot find name 'evil'. +/atotc.ts(10,33): error TS2406: Invalid left-hand side in 'for...in' statement. +/atotc.ts(10,39): error TS1109: Expression expected. +/atotc.ts(10,42): error TS2304: Cannot find name 'the'. +/atotc.ts(10,46): error TS1005: ')' expected. +/atotc.ts(10,46): error TS2304: Cannot find name 'superlative'. +/atotc.ts(10,58): error TS1005: ';' expected. +/atotc.ts(10,58): error TS2304: Cannot find name 'degree'. +/atotc.ts(11,1): error TS2304: Cannot find name 'of'. +/atotc.ts(11,4): error TS1005: ';' expected. +/atotc.ts(11,4): error TS2304: Cannot find name 'comparison'. +/atotc.ts(11,15): error TS1005: ';' expected. +/atotc.ts(11,15): error TS2304: Cannot find name 'only'. +/atotc.ts(11,20): error TS1003: Identifier expected. + + +==== /atotc.ts (213 errors) ==== + It was the best of times, it was the worst of times, + ~~ +!!! error TS2304: Cannot find name 'It'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'best'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'times'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'worst'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'times'. + it was the age of wisdom, it was the age of foolishness, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'age'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'wisdom'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'age'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'foolishness'. + it was the epoch of belief, it was the epoch of incredulity, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'epoch'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'belief'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'epoch'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'incredulity'. + it was the season of Light, it was the season of Darkness, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'season'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'Light'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'season'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'Darkness'. + it was the spring of hope, it was the winter of despair, + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'spring'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'hope'. + ~~ +!!! error TS2304: Cannot find name 'it'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'winter'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'despair'. + we had everything before us, we had nothing before us, + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'had'. + ~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'everything'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'before'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'us'. + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'had'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'nothing'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'before'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'us'. + we were all going direct to Heaven, we were all going direct + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'were'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'all'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'going'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'direct'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'to'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'Heaven'. + ~~ +!!! error TS2304: Cannot find name 'we'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'were'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'all'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'going'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'direct'. + the other way--in short, the period was so far like the present + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~ +!!! error TS1005: ';' expected. + ~~~~~ +!!! error TS2304: Cannot find name 'other'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'way'. + ~~~~~ +!!! error TS2304: Cannot find name 'short'. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'period'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'was'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'so'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'far'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'like'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~ +!!! error TS2304: Cannot find name 'present'. + period, that some of its noisiest authorities insisted on its + ~~~~~~ +!!! error TS2304: Cannot find name 'period'. + ~~~~ +!!! error TS2304: Cannot find name 'that'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'some'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'its'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'noisiest'. + ~~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'authorities'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'insisted'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'on'. + ~~~ +!!! error TS1005: ';' expected. + ~~~ +!!! error TS2304: Cannot find name 'its'. + being received, for good or for evil, in the superlative degree + ~~~~~ +!!! error TS2304: Cannot find name 'being'. + ~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'received'. + ~~~ +!!! error TS1109: Expression expected. + ~~~~ +!!! error TS1005: '(' expected. + ~~~~ +!!! error TS2304: Cannot find name 'good'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'or'. + ~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS1005: '(' expected. + ~~~~ +!!! error TS2304: Cannot find name 'evil'. + ~~~~~ +!!! error TS2406: Invalid left-hand side in 'for...in' statement. + ~~ +!!! error TS1109: Expression expected. + ~~~ +!!! error TS2304: Cannot find name 'the'. + ~~~~~~~~~~~ +!!! error TS1005: ')' expected. + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'superlative'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'degree'. + of comparison only. + ~~ +!!! error TS2304: Cannot find name 'of'. + ~~~~~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'comparison'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'only'. + +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.js new file mode 100644 index 0000000000000..30c1de3575183 --- /dev/null +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-override-all-functions.js @@ -0,0 +1,117 @@ +//// [atotc.ts] +It was the best of times, it was the worst of times, +it was the age of wisdom, it was the age of foolishness, +it was the epoch of belief, it was the epoch of incredulity, +it was the season of Light, it was the season of Darkness, +it was the spring of hope, it was the winter of despair, +we had everything before us, we had nothing before us, +we were all going direct to Heaven, we were all going direct +the other way--in short, the period was so far like the present +period, that some of its noisiest authorities insisted on its +being received, for good or for evil, in the superlative degree +of comparison only. + +//// [atotc.js] +It; +was; +the; +best; +of; +times, it; +was; +the; +worst; +of; +times, + it; +was; +the; +age; +of; +wisdom, it; +was; +the; +age; +of; +foolishness, + it; +was; +the; +epoch; +of; +belief, it; +was; +the; +epoch; +of; +incredulity, + it; +was; +the; +season; +of; +Light, it; +was; +the; +season; +of; +Darkness, + it; +was; +the; +spring; +of; +hope, it; +was; +the; +winter; +of; +despair, + we; +had; +everything; +before; +us, we; +had; +nothing; +before; +us, + we; +were; +all; +going; +direct; +to; +Heaven, we; +were; +all; +going; +direct; +the; +other; +way-- in short, the; +period; +was; +so; +far; +like; +the; +present; +period, that; +some; +of; +its; +noisiest; +authorities; +insisted; +on; +its; +being; +received, ; +for (good; or; ) + for (evil, in the) + superlative; +degree; +of; +comparison; +only.; diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt new file mode 100644 index 0000000000000..c2bff29a61d9c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt @@ -0,0 +1,6 @@ +message test-plugin-loaded: Test language service plugin loaded! + + +!!! message test-plugin-loaded: Test language service plugin loaded! +==== /hello.ts (0 errors) ==== + console.log("Hello, world!"); \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js new file mode 100644 index 0000000000000..18c9f14991232 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js @@ -0,0 +1,5 @@ +//// [hello.ts] +console.log("Hello, world!"); + +//// [hello.js] +console.log("Hello, world!"); diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.errors.txt new file mode 100644 index 0000000000000..28ac94a0b59fb --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.errors.txt @@ -0,0 +1,16 @@ +message program-diagnostics-mutated: Program diagnostics mutated! +message semantic-diagnostics-mutated: Semantic diagnostics mutated! +message syntactic-diagnostics-mutated: Syntactic diagnostics mutated! +/hello-error.ts(1,1): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +/hello-error.ts(1,31): error TS1109: Expression expected. + + +!!! message program-diagnostics-mutated: Program diagnostics mutated! +!!! message semantic-diagnostics-mutated: Semantic diagnostics mutated! +!!! message syntactic-diagnostics-mutated: Syntactic diagnostics mutated! +==== /hello-error.ts (2 errors) ==== + console.log("Hello, error!") - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. + +!!! error TS1109: Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.js new file mode 100644 index 0000000000000..9650d50b1bb7c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-chain-services.js @@ -0,0 +1,5 @@ +//// [hello-error.ts] +console.log("Hello, error!") - + +//// [hello-error.js] +console.log("Hello, error!") - ; diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.errors.txt new file mode 100644 index 0000000000000..63a20e9cb70e1 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.errors.txt @@ -0,0 +1,20 @@ +message program-diagnostics-replaced: Program diagnostics replaced! +message semantic-diagnostics-replaced: Semantic diagnostics replaced! +message syntactic-diagnostics-replaced: Syntactic diagnostics replaced! + + +!!! message program-diagnostics-replaced: Program diagnostics replaced! +!!! message semantic-diagnostics-replaced: Semantic diagnostics replaced! +!!! message syntactic-diagnostics-replaced: Syntactic diagnostics replaced! +==== /atotc.ts (0 errors) ==== + It was the best of times, it was the worst of times, + it was the age of wisdom, it was the age of foolishness, + it was the epoch of belief, it was the epoch of incredulity, + it was the season of Light, it was the season of Darkness, + it was the spring of hope, it was the winter of despair, + we had everything before us, we had nothing before us, + we were all going direct to Heaven, we were all going direct + the other way--in short, the period was so far like the present + period, that some of its noisiest authorities insisted on its + being received, for good or for evil, in the superlative degree + of comparison only. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.js new file mode 100644 index 0000000000000..0a4b5fe31af18 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-all-functions.js @@ -0,0 +1,117 @@ +//// [atotc.ts] +It was the best of times, it was the worst of times, +it was the age of wisdom, it was the age of foolishness, +it was the epoch of belief, it was the epoch of incredulity, +it was the season of Light, it was the season of Darkness, +it was the spring of hope, it was the winter of despair, +we had everything before us, we had nothing before us, +we were all going direct to Heaven, we were all going direct +the other way--in short, the period was so far like the present +period, that some of its noisiest authorities insisted on its +being received, for good or for evil, in the superlative degree +of comparison only. + +//// [atotc.js] +It; +was; +the; +best; +of; +times, it; +was; +the; +worst; +of; +times, + it; +was; +the; +age; +of; +wisdom, it; +was; +the; +age; +of; +foolishness, + it; +was; +the; +epoch; +of; +belief, it; +was; +the; +epoch; +of; +incredulity, + it; +was; +the; +season; +of; +Light, it; +was; +the; +season; +of; +Darkness, + it; +was; +the; +spring; +of; +hope, it; +was; +the; +winter; +of; +despair, + we; +had; +everything; +before; +us, we; +had; +nothing; +before; +us, + we; +were; +all; +going; +direct; +to; +Heaven, we; +were; +all; +going; +direct; +the; +other; +way-- in short, the; +period; +was; +so; +far; +like; +the; +present; +period, that; +some; +of; +its; +noisiest; +authorities; +insisted; +on; +its; +being; +received, ; +for (good; or; ) + for (evil, in the) + superlative; +degree; +of; +comparison; +only.; diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.errors.txt new file mode 100644 index 0000000000000..5402510857df8 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.errors.txt @@ -0,0 +1,10 @@ +/hello-error.ts(1,1): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +/hello-error.ts(1,31): error TS1109: Expression expected. + + +==== /hello-error.ts (2 errors) ==== + console.log("Hello, error!") - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. + +!!! error TS1109: Expression expected. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.js new file mode 100644 index 0000000000000..9650d50b1bb7c --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-filter-passthru.js @@ -0,0 +1,5 @@ +//// [hello-error.ts] +console.log("Hello, error!") - + +//// [hello-error.js] +console.log("Hello, error!") - ; diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.errors.txt new file mode 100644 index 0000000000000..63a20e9cb70e1 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.errors.txt @@ -0,0 +1,20 @@ +message program-diagnostics-replaced: Program diagnostics replaced! +message semantic-diagnostics-replaced: Semantic diagnostics replaced! +message syntactic-diagnostics-replaced: Syntactic diagnostics replaced! + + +!!! message program-diagnostics-replaced: Program diagnostics replaced! +!!! message semantic-diagnostics-replaced: Semantic diagnostics replaced! +!!! message syntactic-diagnostics-replaced: Syntactic diagnostics replaced! +==== /atotc.ts (0 errors) ==== + It was the best of times, it was the worst of times, + it was the age of wisdom, it was the age of foolishness, + it was the epoch of belief, it was the epoch of incredulity, + it was the season of Light, it was the season of Darkness, + it was the spring of hope, it was the winter of despair, + we had everything before us, we had nothing before us, + we were all going direct to Heaven, we were all going direct + the other way--in short, the period was so far like the present + period, that some of its noisiest authorities insisted on its + being received, for good or for evil, in the superlative degree + of comparison only. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.js new file mode 100644 index 0000000000000..0a4b5fe31af18 --- /dev/null +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-override-all-functions.js @@ -0,0 +1,117 @@ +//// [atotc.ts] +It was the best of times, it was the worst of times, +it was the age of wisdom, it was the age of foolishness, +it was the epoch of belief, it was the epoch of incredulity, +it was the season of Light, it was the season of Darkness, +it was the spring of hope, it was the winter of despair, +we had everything before us, we had nothing before us, +we were all going direct to Heaven, we were all going direct +the other way--in short, the period was so far like the present +period, that some of its noisiest authorities insisted on its +being received, for good or for evil, in the superlative degree +of comparison only. + +//// [atotc.js] +It; +was; +the; +best; +of; +times, it; +was; +the; +worst; +of; +times, + it; +was; +the; +age; +of; +wisdom, it; +was; +the; +age; +of; +foolishness, + it; +was; +the; +epoch; +of; +belief, it; +was; +the; +epoch; +of; +incredulity, + it; +was; +the; +season; +of; +Light, it; +was; +the; +season; +of; +Darkness, + it; +was; +the; +spring; +of; +hope, it; +was; +the; +winter; +of; +despair, + we; +had; +everything; +before; +us, we; +had; +nothing; +before; +us, + we; +were; +all; +going; +direct; +to; +Heaven, we; +were; +all; +going; +direct; +the; +other; +way-- in short, the; +period; +was; +so; +far; +like; +the; +present; +period, that; +some; +of; +its; +noisiest; +authorities; +insisted; +on; +its; +being; +received, ; +for (good; or; ) + for (evil, in the) + superlative; +degree; +of; +comparison; +only.; From 1582d10c1d003548f8b6e577f8819091bae17573 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Jul 2016 19:48:41 -0700 Subject: [PATCH 36/49] FourSlash tests for ExtensionRunner basic functionality --- src/harness/extensionRunner.ts | 385 ++++++++++-------- src/harness/fourslash.ts | 12 +- src/harness/harnessLanguageService.ts | 2 +- .../can-add-program-diagnostics.js | 4 +- .../multiLintLoads/no-diagnostics.js | 4 +- .../profileExtensionsTraces/test.js | 4 +- .../test.errors.txt | 2 +- .../reportsAllDIagnosticsFormats/test.js | 4 +- .../reportsFailedLoads/test.errors.txt | 2 +- .../CompilerHost/reportsFailedLoads/test.js | 4 +- .../semanticLintLoads/no-diagnostics.js | 4 +- .../syntacticLintLoads/no-diagnostics.js | 4 +- .../can-add-program-diagnostics.errors.txt | 2 +- .../can-add-program-diagnostics.js | 4 +- .../multiLintLoads/both-diagnostics.trace.txt | 28 +- .../multiLintLoads/no-diagnostics.js | 4 +- .../multiLintLoads/no-diagnostics.trace.txt | 28 +- .../semantic-diagnostics.trace.txt | 28 +- .../syntactic-diagnostics.trace.txt | 28 +- .../profileExtensionsTraces/test.js | 4 +- .../test.errors.txt | 2 +- .../reportsAllDIagnosticsFormats/test.js | 4 +- .../reportsFailedLoads/test.errors.txt | 2 +- .../reportsFailedLoads/test.js | 4 +- .../semanticLintLoads/no-diagnostics.js | 4 +- .../no-diagnostics.trace.txt | 14 +- .../semanticLintLoads/w-diagnostics.trace.txt | 14 +- .../syntacticLintLoads/no-diagnostics.js | 4 +- .../no-diagnostics.trace.txt | 14 +- .../w-diagnostics.trace.txt | 14 +- tests/cases/extensions/fourslash/test.ts | 5 + .../can-add-program-diagnostics.json | 3 +- tests/cases/extensions/source/hello.ts | 2 +- 33 files changed, 353 insertions(+), 290 deletions(-) create mode 100644 tests/cases/extensions/fourslash/test.ts diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index 12d39dd83bc3c..54ac8cd957b96 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -1,5 +1,6 @@ /// /// +/// interface ExtensionTestConfig { inputFiles: string[]; // Files from the source directory to include in the compilation @@ -15,6 +16,7 @@ class ExtensionRunner extends RunnerBase { private scenarioPath = ts.combinePaths(this.basePath, "scenarios"); private extensionPath = ts.combinePaths(this.basePath, "available"); private sourcePath = ts.combinePaths(this.basePath, "source"); + private fourslashPath = ts.combinePaths(this.basePath, "fourslash"); private extensionAPI: ts.Map = {}; private extensions: ts.Map> = {}; private virtualLib: ts.Map = {}; @@ -79,61 +81,64 @@ class ExtensionRunner extends RunnerBase { fullpath => fullpath.substr(path.length + 1).indexOf("/") >= 0 ? fullpath.substr(0, 1 + path.length + fullpath.substr(path.length + 1).indexOf("/")) : fullpath), fullpath => fullpath.lastIndexOf(".") === -1); }, - loadExtension: (path) => { - const fullPath = this.mockHost.getCanonicalFileName(path); - const m = { exports: {} }; - ((module, exports, require) => { eval(this.virtualFs[fullPath]); })( - m, - m.exports, - (name: string) => { - return this.mockHost.loadExtension( - this.mockHost.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS, moduleResolution: ts.ModuleResolutionKind.NodeJs }, this.mockHost, true).resolvedModule.resolvedFileName - ) - ); - } - ); - return m.exports; - }, + loadExtension: (path) => this.mockLoadExtension(path), trace: (s) => { this.traces.push(s); } }; - makeMockLSHost(files: string[], options: ts.CompilerOptions): ts.LanguageServiceHost { - files = ts.filter(files, file => ts.endsWith(file, ".ts") && !ts.endsWith(file, ".d.ts") && (file.indexOf("node_modules") === -1)); - const host: ts.LanguageServiceHost = { - getCompilationSettings: () => options, - getScriptFileNames: () => files, - getScriptVersion: (fileName) => "1", - getScriptSnapshot: (fileName): ts.IScriptSnapshot => { - const fileContents = this.virtualFs[this.getCanonicalFileName(fileName)]; - if (!fileContents) return; - return ts.ScriptSnapshot.fromString(fileContents); - }, - getCurrentDirectory: () => "", - getDefaultLibFileName: () => "/lib/lib.d.ts", - loadExtension: (path) => { - const fullPath = this.getCanonicalFileName(path); - const m = { exports: {} }; - ((module, exports, require) => { eval(this.virtualFs[fullPath]); })( - m, - m.exports, - (name: string) => { - return host.loadExtension( - this.getCanonicalFileName( - ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS, moduleResolution: ts.ModuleResolutionKind.NodeJs }, this.mockHost, true).resolvedModule.resolvedFileName - ) - ); - } + mockLoadExtension(path: string) { + const fullPath = this.getCanonicalFileName(path); + const m = { exports: {} }; + ((module, exports, require) => { eval(this.virtualFs[fullPath]); })( + m, + m.exports, + (name: string) => { + return this.mockLoadExtension( + this.getCanonicalFileName( + ts.resolveModuleName(name, fullPath, { module: ts.ModuleKind.CommonJS, moduleResolution: ts.ModuleResolutionKind.NodeJs }, this.mockHost, true).resolvedModule.resolvedFileName + ) ); - return m.exports; - }, - trace: (s) => { - this.traces.push(s); } + ); + return m.exports; + } + + makeLSMockAdapter(files: string[], options: ts.CompilerOptions, token?: ts.HostCancellationToken) { + const adapter = new Harness.LanguageService.NativeLanguageServiceAdapter(token, options); + // The host returned by the harness is _mostly_ suitable for use here + // it just needs to be monkeypatched to load extensions, report directories, and canonicalize script paths + const host = adapter.getHost(); + host.getDefaultLibFileName = () => "/lib/lib.d.ts"; + host.getCurrentDirectory = () => "/"; + (host as ts.LanguageServiceHost).loadExtension = (path) => this.mockLoadExtension(path); + (host as ts.LanguageServiceHost).useCaseSensitiveFileNames = () => true; + host.trace = (s) => { + this.traces.push(s); }; - return host; + host.getScriptInfo = (fileName: string) => { + fileName = this.getCanonicalFileName(fileName); + return ts.lookUp(host.fileNameToScript, fileName); + }; + host.getDirectories = (s: string) => this.mockHost.getDirectories(s); + host.addScript = (fileName: string, content: string, isRootFile: boolean): void => { + const canonical = this.getCanonicalFileName(fileName); + host.fileNameToScript[canonical] = new Harness.LanguageService.ScriptInfo(canonical, content, isRootFile); + } + ts.forEach(files, file => { + host.addScript(file, this.virtualFs[file], looksLikeRootFile(file)); + }); + + return adapter; + + function looksLikeRootFile(file: string) { + return ts.endsWith(file, ".ts") && !ts.endsWith(file, ".d.ts") && (file.indexOf("node_modules") === -1); + } + } + + makeMockLSHost(files: string[], options: ts.CompilerOptions) { + const adapter = this.makeLSMockAdapter(files, options); + return adapter.getHost(); }; getTraces(): string[] { @@ -289,153 +294,199 @@ class ExtensionRunner extends RunnerBase { */ private runTest(caseName: string) { const caseNameNoExtension = caseName.replace(/\.json$/, ""); - const shortCasePath = caseName.substring(this.scenarioPath.length + 1).replace(/\.json$/, ""); - const testConfigText = Harness.IO.readFile(caseName); - const testConfig: ExtensionTestConfig = JSON.parse(testConfigText); - const inputSources: ts.Map = {}; - const inputTestFiles: Harness.Compiler.TestFile[] = []; - ts.forEach(testConfig.inputFiles, name => { - inputSources[name] = Harness.IO.readFile(ts.combinePaths(this.sourcePath, name)); - inputTestFiles.push({ - unitName: this.getCanonicalFileName(name), - content: inputSources[name] + describe(caseNameNoExtension, () => { + let shortCasePath: string; + let testConfigText: string; + let testConfig: ExtensionTestConfig; + let inputSources: ts.Map; + let inputTestFiles: Harness.Compiler.TestFile[]; + before(() => { + shortCasePath = caseName.substring(this.scenarioPath.length + 1).replace(/\.json$/, ""); + testConfigText = Harness.IO.readFile(caseName); + testConfig = JSON.parse(testConfigText); + inputSources = {}; + inputTestFiles = []; + ts.forEach(testConfig.inputFiles, name => { + inputSources[name] = Harness.IO.readFile(ts.combinePaths(this.sourcePath, name)); + inputTestFiles.push({ + unitName: this.getCanonicalFileName(name), + content: inputSources[name] + }); + }); + }); + + after(() => { + shortCasePath = undefined; + testConfigText = undefined; + testConfig = undefined; + inputSources = undefined; + inputTestFiles = undefined; }); - }); - ts.forEach(this.compileTargets, ([name, compileCb]) => { - describe(`${caseNameNoExtension} - ${name}`, () => { - this.traces = []; // Clear out any traces from tests which made traces, but didn't specify traceResolution or profileExtensions - const sources: ts.Map = {}; - ts.copyMap(inputSources, sources); - ts.forEach(testConfig.availableExtensions, ext => this.loadSetIntoFsAt(this.extensions[ext], `/node_modules/${ext}`)); - const result = this.buildMap(compileCb, sources, sources, testConfig.compilerOptions, /*shouldError*/false); - - const errorsTestName = `Correct errors`; - it(errorsTestName, () => { - Harness.Baseline.runBaseline(errorsTestName, `${name}/${shortCasePath}.errors.txt`, () => { - /* tslint:disable:no-null-keyword */ - if (result.errors.length === 0) return null; - /* tslint:enable:no-null-keyword */ - return Harness.Compiler.getErrorBaseline(inputTestFiles, result.errors); + ts.forEach(this.compileTargets, ([name, compileCb]) => { + describe(`${name}`, () => { + let sources: ts.Map; + let result: Harness.Compiler.CompilerResult; + before(() => { + this.traces = []; // Clear out any traces from tests which made traces, but didn't specify traceResolution or profileExtensions + this.virtualFs = {}; // In case a fourslash test was run last (which doesn't clear FS on end like buildMap does), clear the FS + sources = {}; + ts.copyMap(inputSources, sources); + ts.forEach(testConfig.availableExtensions, ext => this.loadSetIntoFsAt(this.extensions[ext], `/node_modules/${ext}`)); + result = this.buildMap(compileCb, sources, sources, testConfig.compilerOptions, /*shouldError*/false); }); - }); - const traceTestName = `Correct traces`; - it(traceTestName, () => { - if (!(testConfig.compilerOptions.traceResolution || testConfig.compilerOptions.profileExtensions)) { - return; - } - Harness.Baseline.runBaseline(traceTestName, `${name}/${shortCasePath}.trace.txt`, (): string => { - return (result.traceResults || []).join("\n"); + after(() => { + sources = undefined; + result = undefined; }); - }); - const sourcemapTestName = `Correct sourcemap content`; - it(sourcemapTestName, () => { - if (!(testConfig.compilerOptions.sourceMap || testConfig.compilerOptions.inlineSourceMap)) { - return; - } - Harness.Baseline.runBaseline(sourcemapTestName, `${name}/${shortCasePath}.sourcemap.txt`, () => { - const record = result.getSourceMapRecord(); - if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && record === undefined) { - // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + const errorsTestName = `Correct errors`; + it(errorsTestName, () => { + Harness.Baseline.runBaseline(errorsTestName, `${name}/${shortCasePath}.errors.txt`, () => { /* tslint:disable:no-null-keyword */ - return null; + if (result.errors.length === 0) return null; /* tslint:enable:no-null-keyword */ - } - return record; + return Harness.Compiler.getErrorBaseline(inputTestFiles, result.errors); + }); }); - }); - const sourcemapOutputTestName = `Correct sourcemap output`; - it(sourcemapOutputTestName, () => { - if (testConfig.compilerOptions.inlineSourceMap) { - if (result.sourceMaps.length > 0) { - throw new Error("No sourcemap files should be generated if inlineSourceMaps was set."); - } - return; - } - else if (!testConfig.compilerOptions.sourceMap) { - return; - } - if (result.sourceMaps.length !== result.files.length) { - throw new Error("Number of sourcemap files should be same as js files."); - } - - Harness.Baseline.runBaseline(sourcemapOutputTestName, `${name}/${shortCasePath}.js.map`, () => { - if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { - // We need to return null here or the runBaseLine will actually create a empty file. - // Baselining isn't required here because there is no output. - /* tslint:disable:no-null-keyword */ - return null; - /* tslint:enable:no-null-keyword */ + const traceTestName = `Correct traces`; + it(traceTestName, () => { + if (!(testConfig.compilerOptions.traceResolution || testConfig.compilerOptions.profileExtensions)) { + return; } + Harness.Baseline.runBaseline(traceTestName, `${name}/${shortCasePath}.trace.txt`, (): string => { + return (result.traceResults || []).join("\n"); + }); + }); - let sourceMapCode = ""; - for (let i = 0; i < result.sourceMaps.length; i++) { - sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n"; - sourceMapCode += this.getByteOrderMarkText(result.sourceMaps[i]); - sourceMapCode += result.sourceMaps[i].code; + const sourcemapTestName = `Correct sourcemap content`; + it(sourcemapTestName, () => { + if (!(testConfig.compilerOptions.sourceMap || testConfig.compilerOptions.inlineSourceMap)) { + return; } - - return sourceMapCode; + Harness.Baseline.runBaseline(sourcemapTestName, `${name}/${shortCasePath}.sourcemap.txt`, () => { + const record = result.getSourceMapRecord(); + if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && record === undefined) { + // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + return record; + }); }); - }); - const emitOutputTestName = `Correct emit (JS/DTS)`; - it(emitOutputTestName, () => { - if (!ts.forEach(testConfig.inputFiles, name => !ts.endsWith(name, ".d.ts"))) { - return; - } - if (!testConfig.compilerOptions.noEmit && result.files.length === 0 && result.errors.length === 0) { - throw new Error("Expected at least one js file to be emitted or at least one error to be created."); - } - - // check js output - Harness.Baseline.runBaseline(emitOutputTestName, `${name}/${shortCasePath}.js`, () => { - let tsCode = ""; - const tsSources = inputTestFiles; - if (tsSources.length > 1) { - tsCode += "//// [" + caseNameNoExtension + "] ////\r\n\r\n"; + const sourcemapOutputTestName = `Correct sourcemap output`; + it(sourcemapOutputTestName, () => { + if (testConfig.compilerOptions.inlineSourceMap) { + if (result.sourceMaps.length > 0) { + throw new Error("No sourcemap files should be generated if inlineSourceMaps was set."); + } + return; } - for (let i = 0; i < tsSources.length; i++) { - tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n"; - tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : ""); + else if (!testConfig.compilerOptions.sourceMap) { + return; } - - let jsCode = ""; - for (let i = 0; i < result.files.length; i++) { - jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n"; - jsCode += this.getByteOrderMarkText(result.files[i]); - jsCode += result.files[i].code; + if (result.sourceMaps.length !== result.files.length) { + throw new Error("Number of sourcemap files should be same as js files."); } - if (result.declFilesCode.length > 0) { - jsCode += "\r\n\r\n"; - for (let i = 0; i < result.declFilesCode.length; i++) { - jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n"; - jsCode += this.getByteOrderMarkText(result.declFilesCode[i]); - jsCode += result.declFilesCode[i].code; + Harness.Baseline.runBaseline(sourcemapOutputTestName, `${name}/${shortCasePath}.js.map`, () => { + if (testConfig.compilerOptions.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { + // We need to return null here or the runBaseLine will actually create a empty file. + // Baselining isn't required here because there is no output. + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ } - } - if (jsCode.length > 0) { - return tsCode + "\r\n\r\n" + jsCode; + let sourceMapCode = ""; + for (let i = 0; i < result.sourceMaps.length; i++) { + sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n"; + sourceMapCode += this.getByteOrderMarkText(result.sourceMaps[i]); + sourceMapCode += result.sourceMaps[i].code; + } + + return sourceMapCode; + }); + }); + + const emitOutputTestName = `Correct emit (JS/DTS)`; + it(emitOutputTestName, () => { + if (!ts.forEach(testConfig.inputFiles, name => !ts.endsWith(name, ".d.ts"))) { + return; } - else { - /* tslint:disable:no-null-keyword */ - return null; - /* tslint:enable:no-null-keyword */ + if (!testConfig.compilerOptions.noEmit && result.files.length === 0 && result.errors.length === 0) { + throw new Error("Expected at least one js file to be emitted or at least one error to be created."); } + + // check js output + Harness.Baseline.runBaseline(emitOutputTestName, `${name}/${shortCasePath}.js`, () => { + let tsCode = ""; + const tsSources = inputTestFiles; + if (tsSources.length > 1) { + tsCode += "//// [" + caseNameNoExtension + "] ////\r\n\r\n"; + } + for (let i = 0; i < tsSources.length; i++) { + tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n"; + tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : ""); + } + + let jsCode = ""; + for (let i = 0; i < result.files.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n"; + jsCode += this.getByteOrderMarkText(result.files[i]); + jsCode += result.files[i].code; + } + + if (result.declFilesCode.length > 0) { + jsCode += "\r\n\r\n"; + for (let i = 0; i < result.declFilesCode.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n"; + jsCode += this.getByteOrderMarkText(result.declFilesCode[i]); + jsCode += result.declFilesCode[i].code; + } + } + + if (jsCode.length > 0) { + return tsCode + "\r\n\r\n" + jsCode; + } + else { + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + }); }); }); }); - }); - if (testConfig.fourslashTest) { - describe(`${caseNameNoExtension} - Fourslash`, () => { - // TODO + it("passes fourslash verification", () => { + if (testConfig.fourslashTest) { + this.virtualFs = {}; + const testFile = `${this.fourslashPath}/${testConfig.fourslashTest}`; + let testFileContents = Harness.IO.readFile(testFile); + testFileContents = testFileContents.replace(`/// `, ""); + const testContent = [`/// `, ""]; + ts.forEach(inputTestFiles, testFile => { + testContent.push(`// @Filename: ${testFile.unitName.substring(1)}`); // Drop leading / + testContent.push(...testFile.content.split("\n").map(s => `////${s}`)); + }); + testContent.push("// @Filename: tsconfig.json"); + testContent.push(`////${JSON.stringify(testConfig.compilerOptions)}`); + testContent.push(testFileContents); + const finishedTestContent = testContent.join("\n"); + + this.loadSetIntoFs(this.virtualLib); + ts.forEach(testConfig.availableExtensions, ext => this.loadSetIntoFsAt(this.extensions[ext], `/node_modules/${ext}`)); + + const adapterFactory = (token: ts.HostCancellationToken) => this.makeLSMockAdapter(ts.getKeys(this.virtualFs), testConfig.compilerOptions, token); + + FourSlash.runFourSlashTestContent(shortCasePath, adapterFactory, finishedTestContent, testFile); + } }); - } + }); } } \ No newline at end of file diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index a42abbbc60909..14f16eb09f2d6 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -242,7 +242,7 @@ namespace FourSlash { } } - constructor(private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) { + constructor(private basePath: string, private testType: FourSlashTestType | ((token: ts.HostCancellationToken) => Harness.LanguageService.LanguageServiceAdapter), public testData: FourSlashData) { // Create a new Services Adapter this.cancellationToken = new TestCancellationToken(); const compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions); @@ -250,7 +250,13 @@ namespace FourSlash { compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath)); } - const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions); + let languageServiceAdapter: Harness.LanguageService.LanguageServiceAdapter; + if (typeof testType === "number") { + languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions); + } + else { + languageServiceAdapter = testType(this.cancellationToken); + } this.languageServiceAdapterHost = languageServiceAdapter.getHost(); this.languageService = languageServiceAdapter.getLanguageService(); @@ -2266,7 +2272,7 @@ namespace FourSlash { runFourSlashTestContent(basePath, testType, content, fileName); } - export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void { + export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType | ((token: ts.HostCancellationToken) => Harness.LanguageService.LanguageServiceAdapter), content: string, fileName: string): void { // Parse out the files and their metadata const testData = parseTestData(basePath, content, fileName); diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index b2f3b1031d6d5..d39e6ef483d0d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -123,7 +123,7 @@ namespace Harness.LanguageService { } export class LanguageServiceAdapterHost { - protected fileNameToScript: ts.Map = {}; + public fileNameToScript: ts.Map = {}; constructor(protected cancellationToken = DefaultHostCancellationToken.Instance, protected settings = ts.getDefaultCompilerOptions()) { diff --git a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js +++ b/tests/baselines/reference/CompilerHost/languageServiceExtensions/can-add-program-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js +++ b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt index 61243deabf4b3..6ec0aa5f7ee8e 100644 --- a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -9,7 +9,7 @@ warning test-errors[Throws2](THROWS2): Not allowed. !!! warning test-errors: Not allowed. !!! warning test-errors[Throws2](THROWS2): Not allowed. ==== /hello.ts (4 errors) ==== - console.log("Hello, world!"); + console.log("Hello, world!");/*EOL*/ ~~~~~~~ !!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt index b8eeda0cb4527..7d6ee017a2a6b 100644 --- a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.errors.txt @@ -5,4 +5,4 @@ error TS6151: Extension loading failed with error 'Error: Host could not locate !!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. !!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. ==== /hello.ts (0 errors) ==== - console.log("Hello, world!"); \ No newline at end of file + console.log("Hello, world!");/*EOL*/ \ No newline at end of file diff --git a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js +++ b/tests/baselines/reference/CompilerHost/reportsFailedLoads/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js index 359dd9ef1ec96..21b4721f1a6ed 100644 --- a/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/CompilerHost/syntacticLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt index c2bff29a61d9c..86ceab8437d30 100644 --- a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.errors.txt @@ -3,4 +3,4 @@ message test-plugin-loaded: Test language service plugin loaded! !!! message test-plugin-loaded: Test language service plugin loaded! ==== /hello.ts (0 errors) ==== - console.log("Hello, world!"); \ No newline at end of file + console.log("Hello, world!");/*EOL*/ \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js +++ b/tests/baselines/reference/LanguageServiceHost/languageServiceExtensions/can-add-program-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt index 90d89805927db..9069e84844866 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.trace.txt @@ -1,18 +1,18 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt index 90d89805927db..9069e84844866 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/no-diagnostics.trace.txt @@ -1,18 +1,18 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt index 90d89805927db..9069e84844866 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.trace.txt @@ -1,18 +1,18 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt index 90d89805927db..9069e84844866 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/syntactic-diagnostics.trace.txt @@ -1,18 +1,18 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js +++ b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt index 61243deabf4b3..6ec0aa5f7ee8e 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -9,7 +9,7 @@ warning test-errors[Throws2](THROWS2): Not allowed. !!! warning test-errors: Not allowed. !!! warning test-errors[Throws2](THROWS2): Not allowed. ==== /hello.ts (4 errors) ==== - console.log("Hello, world!"); + console.log("Hello, world!");/*EOL*/ ~~~~~~~ !!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt index b8eeda0cb4527..7d6ee017a2a6b 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.errors.txt @@ -5,4 +5,4 @@ error TS6151: Extension loading failed with error 'Error: Host could not locate !!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-semantic-lint'.'. !!! error TS6151: Extension loading failed with error 'Error: Host could not locate extension 'test-syntactic-lint'.'. ==== /hello.ts (0 errors) ==== - console.log("Hello, world!"); \ No newline at end of file + console.log("Hello, world!");/*EOL*/ \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js +++ b/tests/baselines/reference/LanguageServiceHost/reportsFailedLoads/test.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt index cb8ddfddb2a00..acf7782714e0c 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/no-diagnostics.trace.txt @@ -1,9 +1,9 @@ -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt index cb8ddfddb2a00..acf7782714e0c 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.trace.txt @@ -1,9 +1,9 @@ -======== Resolving module 'test-semantic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-semantic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-semantic-lint' from 'node_modules' folder. -File 'node_modules/test-semantic-lint.js' does not exist. -File 'node_modules/test-semantic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-semantic-lint/package.json'. -'package.json' has 'main' field 'main.js' that references 'node_modules/test-semantic-lint/main.js'. -File 'node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. -======== Module name 'test-semantic-lint' was successfully resolved to 'node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file +File '/node_modules/test-semantic-lint.js' does not exist. +File '/node_modules/test-semantic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-semantic-lint/package.json'. +'package.json' has 'main' field 'main.js' that references '/node_modules/test-semantic-lint/main.js'. +File '/node_modules/test-semantic-lint/main.js' exist - use it as a name resolution result. +======== Module name 'test-semantic-lint' was successfully resolved to '/node_modules/test-semantic-lint/main.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js index 18c9f14991232..b9f140e37bdde 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.js @@ -1,5 +1,5 @@ //// [hello.ts] -console.log("Hello, world!"); +console.log("Hello, world!");/*EOL*/ //// [hello.js] -console.log("Hello, world!"); +console.log("Hello, world!"); /*EOL*/ diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt index 19b1c83eb2e85..76f57ec088c21 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/no-diagnostics.trace.txt @@ -1,9 +1,9 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt index 19b1c83eb2e85..76f57ec088c21 100644 --- a/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt +++ b/tests/baselines/reference/LanguageServiceHost/syntacticLintLoads/w-diagnostics.trace.txt @@ -1,9 +1,9 @@ -======== Resolving module 'test-syntactic-lint' from 'tsconfig.json'. ======== +======== Resolving module 'test-syntactic-lint' from '/tsconfig.json'. ======== Module resolution kind is not specified, using 'NodeJs'. Loading module 'test-syntactic-lint' from 'node_modules' folder. -File 'node_modules/test-syntactic-lint.js' does not exist. -File 'node_modules/test-syntactic-lint.jsx' does not exist. -Found 'package.json' at 'node_modules/test-syntactic-lint/package.json'. -'package.json' has 'main' field 'index.js' that references 'node_modules/test-syntactic-lint/index.js'. -File 'node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. -======== Module name 'test-syntactic-lint' was successfully resolved to 'node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file +File '/node_modules/test-syntactic-lint.js' does not exist. +File '/node_modules/test-syntactic-lint.jsx' does not exist. +Found 'package.json' at '/node_modules/test-syntactic-lint/package.json'. +'package.json' has 'main' field 'index.js' that references '/node_modules/test-syntactic-lint/index.js'. +File '/node_modules/test-syntactic-lint/index.js' exist - use it as a name resolution result. +======== Module name 'test-syntactic-lint' was successfully resolved to '/node_modules/test-syntactic-lint/index.js'. ======== \ No newline at end of file diff --git a/tests/cases/extensions/fourslash/test.ts b/tests/cases/extensions/fourslash/test.ts new file mode 100644 index 0000000000000..ee1f6094e6e4e --- /dev/null +++ b/tests/cases/extensions/fourslash/test.ts @@ -0,0 +1,5 @@ +/// + +goTo.file("hello.ts"); +goTo.marker("EOL"); +verify.caretAtMarker("EOL"); \ No newline at end of file diff --git a/tests/cases/extensions/scenarios/languageServiceExtensions/can-add-program-diagnostics.json b/tests/cases/extensions/scenarios/languageServiceExtensions/can-add-program-diagnostics.json index afae43dbcb76d..842c7d267eae7 100644 --- a/tests/cases/extensions/scenarios/languageServiceExtensions/can-add-program-diagnostics.json +++ b/tests/cases/extensions/scenarios/languageServiceExtensions/can-add-program-diagnostics.json @@ -5,5 +5,6 @@ "availableExtensions": ["test-language-service"], "compilerOptions": { "extensions": ["test-language-service"] - } + }, + "fourslashTest": "test.ts" } \ No newline at end of file diff --git a/tests/cases/extensions/source/hello.ts b/tests/cases/extensions/source/hello.ts index 06f320c59b9b0..97d87624465a4 100644 --- a/tests/cases/extensions/source/hello.ts +++ b/tests/cases/extensions/source/hello.ts @@ -1 +1 @@ -console.log("Hello, world!"); \ No newline at end of file +console.log("Hello, world!");/*EOL*/ \ No newline at end of file From b5b781761f9f6f6fabc68b7c3c6b2f0c9c03195b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Jul 2016 22:21:27 -0700 Subject: [PATCH 37/49] Semicolon. --- src/harness/extensionRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index 54ac8cd957b96..b1771e2590356 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -124,7 +124,7 @@ class ExtensionRunner extends RunnerBase { host.addScript = (fileName: string, content: string, isRootFile: boolean): void => { const canonical = this.getCanonicalFileName(fileName); host.fileNameToScript[canonical] = new Harness.LanguageService.ScriptInfo(canonical, content, isRootFile); - } + }; ts.forEach(files, file => { host.addScript(file, this.virtualFs[file], looksLikeRootFile(file)); }); From 84c683e97cc6c9fa306c1b0ebc030589ea078317 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Jul 2016 14:58:47 -0700 Subject: [PATCH 38/49] Add meaningful fourslash test covering much of the LS extension surface --- .../available/test-service-filters/index.ts | 18 ++++++++++++------ .../available/test-service-overrides/index.ts | 18 ++++++++++++------ .../fourslash/verify-overridden-diagnostics.ts | 15 +++++++++++++++ .../can-filter-all-functions.json | 3 ++- .../can-override-all-functions.json | 3 ++- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 tests/cases/extensions/fourslash/verify-overridden-diagnostics.ts diff --git a/tests/cases/extensions/available/test-service-filters/index.ts b/tests/cases/extensions/available/test-service-filters/index.ts index 6db979e5e5bd1..43feaf6bc0983 100644 --- a/tests/cases/extensions/available/test-service-filters/index.ts +++ b/tests/cases/extensions/available/test-service-filters/index.ts @@ -50,12 +50,12 @@ export default class extends LanguageServiceProvider { return { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{name: fileName, kind: "", kindModifiers: "", sortText: fileName}] + entries: [{name: "fakeCompletion", kind: "", kindModifiers: "", sortText: "fakeCompletion"}] }; } getCompletionEntryDetailsFilter(fileName, position, entryName, previous) { return { - name: fileName, + name: "fakeCompletion", kind: position.toString(), kindModifiers: entryName, displayParts: [], @@ -72,7 +72,13 @@ export default class extends LanguageServiceProvider { return {}; } getSignatureHelpItemsFilter(fileName, position, previous) { - return {}; + return { + items: [], + applicableSpan: undefined, + selectedItemIndex: undefined, + argumentIndex: 0, + argumentCount: 0, + }; } getRenameInfoFilter(fileName, position, previous) { return {}; @@ -105,10 +111,10 @@ export default class extends LanguageServiceProvider { return {}; } getTodoCommentsFilter(fileName, descriptors, previous) { - return {}; + return []; } getBraceMatchingAtPositionFilter(fileName, position, previous) { - return {}; + return []; } getIndentationAtPositionFilter(fileName, position, options, previous) { return {}; @@ -123,6 +129,6 @@ export default class extends LanguageServiceProvider { return {}; } getDocCommentTemplateAtPositionFilter(fileName, position, previous) { - return {}; + return {newText: "/********Yes.*********/", caretOffset: 9}; } } \ No newline at end of file diff --git a/tests/cases/extensions/available/test-service-overrides/index.ts b/tests/cases/extensions/available/test-service-overrides/index.ts index c32bbb5c8a6b1..f206583f0a029 100644 --- a/tests/cases/extensions/available/test-service-overrides/index.ts +++ b/tests/cases/extensions/available/test-service-overrides/index.ts @@ -49,12 +49,12 @@ export default class extends LanguageServiceProvider { return { isMemberCompletion: false, isNewIdentifierLocation: false, - entries: [{name: fileName, kind: "", kindModifiers: "", sortText: fileName}] + entries: [{name: "fakeCompletion", kind: "", kindModifiers: "", sortText: "fakeCompletion"}] }; } getCompletionEntryDetails(fileName, position, entryName) { return { - name: fileName, + name: "fakeCompletion", kind: position.toString(), kindModifiers: entryName, displayParts: [], @@ -71,7 +71,13 @@ export default class extends LanguageServiceProvider { return {}; } getSignatureHelpItems(fileName, position) { - return {}; + return { + items: [], + applicableSpan: undefined, + selectedItemIndex: undefined, + argumentIndex: 0, + argumentCount: 0, + }; } getRenameInfo(fileName, position) { return {}; @@ -104,10 +110,10 @@ export default class extends LanguageServiceProvider { return {}; } getTodoComments(fileName, descriptors) { - return {}; + return []; } getBraceMatchingAtPosition(fileName, position) { - return {}; + return []; } getIndentationAtPosition(fileName, position, options) { return {}; @@ -122,6 +128,6 @@ export default class extends LanguageServiceProvider { return {}; } getDocCommentTemplateAtPosition(fileName, position) { - return {}; + return {newText: "/********Yes.*********/", caretOffset: 9}; } } \ No newline at end of file diff --git a/tests/cases/extensions/fourslash/verify-overridden-diagnostics.ts b/tests/cases/extensions/fourslash/verify-overridden-diagnostics.ts new file mode 100644 index 0000000000000..5d3ca5220fd06 --- /dev/null +++ b/tests/cases/extensions/fourslash/verify-overridden-diagnostics.ts @@ -0,0 +1,15 @@ +/// + +goTo.file("atotc.ts"); +verify.getSemanticDiagnostics(JSON.stringify([{message: "Semantic diagnostics replaced!", category: "message", code: "semantic-diagnostics-replaced"}], undefined, 2)); +verify.getSyntacticDiagnostics(JSON.stringify([{message: "Syntactic diagnostics replaced!", category: "message", code: "syntactic-diagnostics-replaced"}], undefined, 2)); +verify.completionListContains("fakeCompletion", "", undefined, ""); +verify.completionEntryDetailIs("fakeCompletion", "", undefined, "0"); +verify.quickInfoIs(undefined, undefined); +verify.nameOrDottedNameSpanTextIs(""); +verify.signatureHelpArgumentCountIs(0); +verify.definitionCountIs(0); +verify.referencesAre([]); +verify.todoCommentsInCurrentFile([]); +verify.noMatchingBracePositionInCurrentFile(0); +verify.DocCommentTemplate("/********Yes.*********/", 9); diff --git a/tests/cases/extensions/scenarios/languageServiceExtensions/can-filter-all-functions.json b/tests/cases/extensions/scenarios/languageServiceExtensions/can-filter-all-functions.json index f2b469bef5f30..c33c6b1be8eb5 100644 --- a/tests/cases/extensions/scenarios/languageServiceExtensions/can-filter-all-functions.json +++ b/tests/cases/extensions/scenarios/languageServiceExtensions/can-filter-all-functions.json @@ -5,5 +5,6 @@ "availableExtensions": ["test-service-filters"], "compilerOptions": { "extensions": ["test-service-filters"] - } + }, + "fourslashTest": "verify-overridden-diagnostics.ts" } \ No newline at end of file diff --git a/tests/cases/extensions/scenarios/languageServiceExtensions/can-override-all-functions.json b/tests/cases/extensions/scenarios/languageServiceExtensions/can-override-all-functions.json index dfed40e01ccb5..d557d8bb5ed01 100644 --- a/tests/cases/extensions/scenarios/languageServiceExtensions/can-override-all-functions.json +++ b/tests/cases/extensions/scenarios/languageServiceExtensions/can-override-all-functions.json @@ -5,5 +5,6 @@ "availableExtensions": ["test-service-overrides"], "compilerOptions": { "extensions": ["test-service-overrides"] - } + }, + "fourslashTest": "verify-overridden-diagnostics.ts" } \ No newline at end of file From 5d2618bb312d01fa77424c96d735b57874fb5a4e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 12 Jul 2016 11:05:56 -0700 Subject: [PATCH 39/49] Fix comments by @sandersn --- src/compiler/core.ts | 10 +++++----- src/compiler/extensions.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index b4f4dc720e90f..f98a3da68dacd 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -186,12 +186,12 @@ namespace ts { export function groupBy(array: T[], classifier: (item: T) => (string | number)): {[index: string]: T[], [index: number]: T[]} { if (!array || !array.length) return undefined; const ret: {[index: string]: T[], [index: number]: T[]} = {}; - for (let i = 0, len = array.length; i < len; i++) { - const result = classifier(array[i]); - if (!ret[result]) { - ret[result] = []; + for (const elem of array) { + const key = classifier(elem); + if (!ret[key]) { + ret[key] = []; } - ret[result].push(array[i]); + ret[key].push(elem); } return ret; } diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 558a48f9bf08c..9aff4eb961a08 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -1,10 +1,37 @@ namespace ts { export type LintErrorMethod = { + /** + * @param {string} err The error message to report + */ (err: string): void; + /** + * @param {string} err The error message to report + * @param {Node} span The node on which to position the error + */ (err: string, span: Node): void; + /** + * @param {string} err The error message to report + * @param {number} start The start position of the error span + * @param {number} length The length of the error span + */ (err: string, start: number, length: number): void; + /** + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + */ (shortname: string, err: string): void; + /** + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + * @param {Node} span The node on which to position the error + */ (shortname: string, err: string, span: Node): void; + /** + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + * @param {number} start The start position of the error span + * @param {number} length The length of the error span + */ (shortname: string, err: string, start: number, length: number): void; }; export type LintStopMethod = () => void; From 67063cc3427fb559d2092f299a938a86fcd718bf Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 12 Jul 2016 13:04:42 -0700 Subject: [PATCH 40/49] Convert kind anotations to actual kind overrides --- src/compiler/extensions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index 9aff4eb961a08..bfb99a7771c96 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -100,18 +100,18 @@ namespace ts { length?: Timestamp; } - // @kind(ExtensionKind.SyntacticLint) export interface SyntacticLintExtension extends ExtensionBase { + kind: ExtensionKind.SyntacticLint; ctor: SyntacticLintProviderStatic; } - // @kind(ExtensionKind.SemanticLint) export interface SemanticLintExtension extends ExtensionBase { + kind: ExtensionKind.SemanticLint; ctor: SemanticLintProviderStatic; } - // @kind(ExtensionKind.LanguageService) export interface LanguageServiceExtension extends ExtensionBase { + kind: ExtensionKind.LanguageService; ctor: LanguageServiceProviderStatic; } From 50735ae85c3841fef930de2ee771825309943635 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 12 Jul 2016 15:45:28 -0700 Subject: [PATCH 41/49] Add after visit, more error overloads, more robust error handling --- src/compiler/extensions.ts | 75 ++++- src/compiler/program.ts | 279 +++++++++++++----- src/compiler/utilities.ts | 9 +- .../test.errors.txt | 98 +++++- .../test.errors.txt | 98 +++++- .../available/extension-api/index.ts | 4 +- .../extensions/available/test-errors/index.ts | 92 +++++- .../test-extension-arguments/index.ts | 2 +- .../available/test-multi-extension/index.ts | 8 +- .../available/test-multierrors/index.ts | 4 +- .../available/test-semantic-lint/main.ts | 2 +- .../available/test-syntactic-lint/index.ts | 2 +- 12 files changed, 563 insertions(+), 110 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index bfb99a7771c96..a7305b24844d0 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -33,15 +33,64 @@ namespace ts { * @param {number} length The length of the error span */ (shortname: string, err: string, start: number, length: number): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} err The error message to report + */ + (level: DiagnosticCategory, err: string): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} err The error message to report + * @param {Node} span The node on which to position the error + */ + (level: DiagnosticCategory, err: string, span: Node): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} err The error message to report + * @param {number} start The start position of the error span + * @param {number} length The length of the error span + */ + (level: DiagnosticCategory, err: string, start: number, length: number): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + */ + (level: DiagnosticCategory, shortname: string, err: string): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + * @param {Node} span The node on which to position the error + */ + (level: DiagnosticCategory, shortname: string, err: string, span: Node): void; + /** + * @param {DiagnosticCategory} level The error level to report this error as (Message, Warning, or Error) + * @param {string} shortname A short code uniquely identifying the error within the lint + * @param {string} err The error message to report + * @param {number} start The start position of the error span + * @param {number} length The length of the error span + */ + (level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; }; - export type LintStopMethod = () => void; /* * Walkers call stop to halt recursion into the node's children * Walkers call error to add errors to the output. */ export interface LintWalker { - visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void; + /** + * @param {Node} node The current node being visited (starts at every SourceFile and recurs into their children) + * @param {LintErrorMethod} error A callback to add errors to the output + * @returns boolean true if this lint no longer needs to recur into the active node + */ + visit(node: Node, error: LintErrorMethod): boolean | void; + /** + * Yar + * @param {Node} node The current node which has just finished being visited + * @param {LintErrorMethod} error A callback to add errors to the output + */ + afterVisit?(node: Node, error: LintErrorMethod): void; } export interface BaseProviderStatic { @@ -168,12 +217,12 @@ namespace ts { export const perfTraces: Map = {}; - function getExtensionRootName(ext: ExtensionBase) { - return ext.name.substring(0, ext.name.indexOf("[")) || ext.name; + function getExtensionRootName(qualifiedName: string) { + return qualifiedName.substring(0, qualifiedName.indexOf("[")) || qualifiedName; } - function createTaskName(ext: ExtensionBase, task: string) { - return `${task}|${ext.name}`; + function createTaskName(qualifiedName: string, task: string) { + return `${task}|${qualifiedName}`; } export function startProfile(key: string, bucket?: string) { @@ -190,19 +239,19 @@ namespace ts { perfTraces[key].length = getTimestampMs(perfTraces[key].start); } - export function startExtensionProfile(level: ProfileLevel, ext: ExtensionBase, task: string, trace?: (s: string) => void) { + export function startExtensionProfile(level: ProfileLevel, qualifiedName: string, task: string, trace?: (s: string) => void) { if (!level) return; - if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, ext.name, task); - const longTask = createTaskName(ext, task); - startProfile(longTask, getExtensionRootName(ext)); + if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, qualifiedName, task); + const longTask = createTaskName(qualifiedName, task); + startProfile(longTask, getExtensionRootName(qualifiedName)); } - export function completeExtensionProfile(level: ProfileLevel, ext: ExtensionBase, task: string, trace?: (s: string) => void) { + export function completeExtensionProfile(level: ProfileLevel, qualifiedName: string, task: string, trace?: (s: string) => void) { if (!level) return; - const longTask = createTaskName(ext, task); + const longTask = createTaskName(qualifiedName, task); completeProfile(longTask); - if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, ext.name, task, perfTraces[longTask].length.toPrecision(5)); + if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, qualifiedName, task, perfTraces[longTask].length.toPrecision(5)); } export function createExtensionCache(options: CompilerOptions, host: ExtensionHost, resolvedExtensionNames?: Map): ExtensionCache { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 586cfc0f62e06..1890c895f50ce 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1513,21 +1513,36 @@ namespace ts { if (!lints || !lints.length) { return; } - type UniqueLint = {name: string, walker: LintWalker, accepted: boolean}; - const initializedLints = new Array(lints.length); + type UniqueLint = {name: string, walker: LintWalker, accepted: boolean, errored: boolean}; + const initializedLints: UniqueLint[] = []; const diagnostics: Diagnostic[] = []; let activeLint: UniqueLint; let parent: Node | undefined = undefined; const profileLevel = options.profileExtensions; - for (let i = 0; i < lints.length; i++) { - startExtensionProfile(profileLevel, lints[i], "construct", host.trace); + for (const {name, args, ctor} of lints) { + let walker: LintWalker; if (kind === ExtensionKind.SemanticLint) { - initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SemanticLintProviderStatic)({ ts, checker: getTypeChecker(), args: lints[i].args, host, program }), accepted: true }; + const checker = getTypeChecker(); + startExtensionProfile(profileLevel, name, "construct", host.trace); + try { + walker = new (ctor as SemanticLintProviderStatic)({ ts, checker, args, host, program }); + } + catch (e) { + diagnostics.push(createExtensionDiagnostic(name, `Lint construction failed: ${(e as Error).message}`, sourceFile, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + completeExtensionProfile(profileLevel, name, "construct", host.trace); } else if (kind === ExtensionKind.SyntacticLint) { - initializedLints[i] = { name: lints[i].name, walker: new (lints[i].ctor as SyntacticLintProviderStatic)({ ts, args: lints[i].args, host, program }), accepted: true }; + startExtensionProfile(profileLevel, name, "construct", host.trace); + try { + walker = new (ctor as SyntacticLintProviderStatic)({ ts, args, host, program }); + } + catch (e) { + diagnostics.push(createExtensionDiagnostic(name, `Lint construction failed: ${(e as Error).message}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + completeExtensionProfile(profileLevel, name, "construct", host.trace); } - completeExtensionProfile(profileLevel, lints[i], "construct", host.trace); + if (walker) initializedLints.push({ name, walker, accepted: true, errored: false }); } let nodesVisited = 0; @@ -1536,17 +1551,25 @@ namespace ts { return diagnostics; function visitNode(node: Node) { + node.parent = parent; nodesVisited++; let oneAccepted = false; const oldParent = parent; const needsReset: Map = {}; for (let i = 0; i < initializedLints.length; i++) { - if (initializedLints[i].accepted) { - activeLint = initializedLints[i]; - node.parent = parent; - startExtensionProfile(profileLevel, lints[i], `visitNode|${nodesVisited}`, host.trace); - activeLint.walker.visit(node, stop, error); - completeExtensionProfile(profileLevel, lints[i], `visitNode|${nodesVisited}`, host.trace); + activeLint = initializedLints[i]; + if (activeLint.accepted) { + if (!activeLint.errored) { + startExtensionProfile(profileLevel, activeLint.name, `visitNode|${nodesVisited}`, host.trace); + try { + activeLint.accepted = !activeLint.walker.visit(node, error); + } + catch (e) { + activeLint.errored = true; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `visit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + completeExtensionProfile(profileLevel, activeLint.name, `visitNode|${nodesVisited}`, host.trace); + } if (activeLint.accepted) { oneAccepted = true; } @@ -1561,15 +1584,26 @@ namespace ts { } parent = oldParent; for (let i = 0; i < initializedLints.length; i++) { - if (needsReset[i]) { - initializedLints[i].accepted = true; + activeLint = initializedLints[i]; + if (!needsReset[i]) { + activeLint.accepted = true; needsReset[i] = false; } + if (!activeLint.errored && activeLint.walker.afterVisit) { + try { + activeLint.walker.afterVisit(node, error); + } + catch (e) { + activeLint.errored = true; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `afterVisit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + } } } - function stop() { - activeLint.accepted = false; + function errorQualifiedName(shortname?: string) { + if (!shortname) return activeLint.name; + return `${activeLint.name}(${shortname})`; } function error(err: string): void; @@ -1578,66 +1612,179 @@ namespace ts { function error(shortname: string, err: string): void; function error(shortname: string, err: string, span: Node): void; function error(shortname: string, err: string, start: number, length: number): void; - function error(errOrShortname: string, errOrNodeOrStart?: string | Node | number, lengthOrNodeOrStart?: Node | number, length?: number): void { + function error(level: DiagnosticCategory, err: string): void; + function error(level: DiagnosticCategory, err: string, node: Node): void; + function error(level: DiagnosticCategory, err: string, start: number, length: number): void; + function error(level: DiagnosticCategory, shortname: string, err: string): void; + function error(level: DiagnosticCategory, shortname: string, err: string, span: Node): void; + function error(level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; + function error( + levelErrOrShortname: DiagnosticCategory | string, + errShortnameSpanOrStart?: string | Node | number, + errSpanStartOrLength?: string | Node | number, + startSpanOrLength?: number | Node, + length?: number): void { + if (typeof levelErrOrShortname === "undefined") { + Debug.fail("You must at least provide an error message to error."); + return; + } + if (typeof errShortnameSpanOrStart === "undefined") { + if (typeof levelErrOrShortname !== "string") { + Debug.fail("If only one argument is passed to error, it must be the error message string."); + return; + } + // error(err: string): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), levelErrOrShortname)); + return; + } + if (typeof errSpanStartOrLength === "undefined") { + error2Arguments(levelErrOrShortname, errShortnameSpanOrStart); + return; + } + if (typeof startSpanOrLength === "undefined") { + error3Arguments(levelErrOrShortname, errShortnameSpanOrStart, errSpanStartOrLength); + return; + } if (typeof length === "undefined") { - // 3 or fewer arguments - if (typeof lengthOrNodeOrStart === "undefined") { - // 2 or fewer arguments - if (typeof errOrNodeOrStart === "undefined") { - // 1 argument - // (err: string) - return void diagnostics.push(createExtensionDiagnostic(activeLint.name, errOrShortname)); - } - else { - // Exactly 2 arguments - if (typeof errOrNodeOrStart === "number") { - // No corresponding overloads - } - else if (typeof errOrNodeOrStart === "string") { - // (shortname: string, err: string) - return void diagnostics.push(createExtensionDiagnostic(`${activeLint.name}(${errOrShortname})`, errOrNodeOrStart)); - } - else { - // (err: string, node: Node) - return void diagnostics.push(createExtensionDiagnosticForNode(errOrNodeOrStart, activeLint.name, errOrShortname)); - } - } + error4Arguments(levelErrOrShortname, errShortnameSpanOrStart, errSpanStartOrLength, startSpanOrLength); + return; + } + if (typeof levelErrOrShortname !== "number") { + Debug.fail("When five arguments are passed to error, the first must be the diagnostic category of the error."); + return; + } + if (typeof errShortnameSpanOrStart !== "string") { + Debug.fail("When five arguments are passed to error, the second argument must be the shortname of the error."); + return; + } + if (typeof errSpanStartOrLength !== "string") { + Debug.fail("When five arguments are passed to error, the third argument must be the error message."); + return; + } + if (typeof startSpanOrLength !== "number") { + Debug.fail("When five arguments are passed to error, the fourth argument must be the start position of the error span."); + return; + } + if (typeof length !== "number") { + Debug.fail("When five arguments are passed to error, the fifth argument must be the length of the error span."); + return; + } + // error(level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(errShortnameSpanOrStart), errSpanStartOrLength, sourceFile, startSpanOrLength, length, levelErrOrShortname)); + } + + function error2Arguments(errShortnameOrLevel: string | DiagnosticCategory, spanOrErr: Node | string | number): void { + if (typeof errShortnameOrLevel === "string") { + if (typeof spanOrErr === "string") { + // error(shortname: string, err: string): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(errShortnameOrLevel), spanOrErr)); + } + else if (typeof spanOrErr === "object") { + // error(err: string, node: Node): void; + diagnostics.push(createExtensionDiagnosticForNode(spanOrErr, errorQualifiedName(), errShortnameOrLevel)); } else { - // Exactly 3 arguments - if (typeof lengthOrNodeOrStart === "number") { - if (typeof errOrNodeOrStart !== "number") { - // No corresponding overloads - } - else { - // (err: string, start: number, length: number) - return void diagnostics.push(createExtensionDiagnostic(activeLint.name, errOrShortname, sourceFile, errOrNodeOrStart, lengthOrNodeOrStart)); - } - } - else { - if (typeof errOrNodeOrStart !== "string") { - // No corresponding overloads - } - else { - // (shortname: string, err: string, span: Node) - return void diagnostics.push(createExtensionDiagnosticForNode(lengthOrNodeOrStart, `${activeLint.name}(${errOrShortname})`, errOrNodeOrStart)); - } - } + Debug.fail("When two arguments are passed to error and the first argument is either the error message or error shortname, the second argument must either be an error message string or the node the error is on."); + } + } + else if (typeof errShortnameOrLevel === "number") { + if (typeof spanOrErr !== "string") { + Debug.fail("When two arguments are passed to error and the first is a DiagnosticCategory, the second must be the error message string."); + return; } + // error(level: DiagnosticCategory, err: string): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), spanOrErr, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); } else { - if (typeof errOrNodeOrStart !== "string") { - // No corresponding overloads + Debug.fail("When two arguments are passed to error, the first argument must be either the error message, the error shortname, or the DiagnosticCategory of the error."); + } + } + + function error3Arguments(errShortnameOrLevel: string | DiagnosticCategory, startErrOrShortname: number | string | Node, lengthSpanOrErr: number | Node | string) { + if (typeof errShortnameOrLevel === "number") { + if (typeof startErrOrShortname !== "string") { + Debug.fail("When three arguments are passed to error and the first is a diagnostic category, the second argument must be either an error message or shortcode."); + return; + } + if (typeof lengthSpanOrErr === "string") { + // error(level: DiagnosticCategory, shortname: string, err: string): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(startErrOrShortname), lengthSpanOrErr, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); + } + else if (typeof lengthSpanOrErr === "object") { + // error(level: DiagnosticCategory, err: string, node: Node): void; + diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr, errorQualifiedName(), startErrOrShortname, errShortnameOrLevel)); } else { - if (typeof lengthOrNodeOrStart !== "number") { - // No corresponding overloads + Debug.fail("When three arguments are passed to error and the first is a diagnostic category, the third argument must either be an error message or the node errored on."); + } + } + else if (typeof errShortnameOrLevel === "string") { + if (typeof startErrOrShortname === "number") { + if (typeof lengthSpanOrErr !== "number") { + Debug.fail("When three arguments are passed to error and the first is an error message, the third must be the message length."); + return; } - else { - // (shortname: string, err: string, start: number, length: number) - return void diagnostics.push(createExtensionDiagnostic(`${activeLint.name}(${errOrShortname})`, errOrNodeOrStart, sourceFile, lengthOrNodeOrStart, length)); + // error(err: string, start: number, length: number): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errShortnameOrLevel, sourceFile, startErrOrShortname, lengthSpanOrErr)); + } + else if (typeof startErrOrShortname === "string") { + if (typeof lengthSpanOrErr !== "object") { + Debug.fail("When three arguments are passed to error and the first is an error shortcode, the third must be the node errored on."); + return; } + // error(shortname: string, err: string, span: Node): void; + diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr, errorQualifiedName(errShortnameOrLevel), startErrOrShortname)); } + else { + Debug.fail("When three arguments are passed to error and the first is an error shortcode or message, the second must be either an error message or a span start number, respectively."); + } + } + else { + Debug.fail("When three arguments are passed to error, the first argument must be either a diagnostic category, a error shortname, or an error message."); + } + } + + function error4Arguments(levelOrShortname: DiagnosticCategory | string, errOrShortname: string | number | Node, startOrErr: string | number | Node, lengthOrSpan: number | Node) { + if (typeof errOrShortname !== "string") { + Debug.fail("When four arguments are passed to error, the second argument must either be an error message string or an error shortcode."); + return; + } + if (typeof levelOrShortname === "number") { + if (typeof startOrErr === "string") { + if (typeof lengthOrSpan !== "object") { + Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the fourth argument must be the node errored on."); + return; + } + // error(level: DiagnosticCategory, shortname: string, err: string, span: Node): void; + diagnostics.push(createExtensionDiagnosticForNode(lengthOrSpan, errorQualifiedName(errOrShortname), startOrErr, levelOrShortname)); + } + else if (typeof startOrErr === "number") { + if (typeof lengthOrSpan !== "number") { + Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the fourth argument must be the error span length."); + return; + } + // error(level: DiagnosticCategory, err: string, start: number, length: number): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errOrShortname, sourceFile, startOrErr, lengthOrSpan, levelOrShortname)); + } + else { + Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the third argument must be the error message."); + return; + } + } + else if (typeof levelOrShortname === "string") { + if (typeof startOrErr !== "number") { + Debug.fail("When four arguments are passed to error and the first is a error shortname string, the third argument must be the error span start."); + return; + } + if (typeof lengthOrSpan !== "number") { + Debug.fail("When four arguments are passed to error and the first is a error shortname string, the third argument must be the error span length."); + return; + } + // error(shortname: string, err: string, start: number, length: number): void; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(levelOrShortname), errOrShortname, sourceFile, startOrErr, lengthOrSpan)); + } + else { + Debug.fail("When four arguments are passed to error, the first argument must be either a DiagnosticCategory or a error shortname string."); } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index afc3f92f8465e..b145f36e94980 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -456,20 +456,21 @@ namespace ts { return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2); } - export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string, isError?: boolean): Diagnostic { + export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string, category?: DiagnosticCategory): Diagnostic { const sourceFile = getSourceFileOfNode(node); const span = getErrorSpanForNode(sourceFile, node); - return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length, isError); + return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length, category); } - export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number, isError?: boolean): Diagnostic { + export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number, category?: DiagnosticCategory): Diagnostic { + Debug.assert(file ? typeof start === "number" && typeof length === "number" : true, "File, start, and length must all be specified or unspecified."); return { file: file, messageText: message, code: extension, start: start, length: length, - category: isError ? DiagnosticCategory.Error : DiagnosticCategory.Warning + category: typeof category !== "undefined" ? category : DiagnosticCategory.Warning }; } diff --git a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt index 6ec0aa5f7ee8e..9e6fc2a47ab5c 100644 --- a/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -1,20 +1,114 @@ warning test-errors: Not allowed. warning test-errors[Throws2](THROWS2): Not allowed. +error test-errors[Throws7]: Not allowed. +error test-errors[Throws8](THROWS8): Not allowed. +error test-errors[ThrowsOnAfterVisit](!!!): afterVisit failed with error: Error: Throws on afterVisit +error test-errors[ThrowsOnConstruct]: Lint construction failed: Throws on construct +error test-errors[ThrowsOnVisit](!!!): visit failed with error: Error: Throws on visit +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. /hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. /hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws10](THROWS10): Not allowed. +/hello.ts(1,1): error test-errors[Throws12]: Not allowed. /hello.ts(1,1): warning test-errors[Throws4](THROWS4): Not allowed. /hello.ts(1,1): warning test-errors[Throws6]: Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,9): error test-errors[Throws11]: Not allowed. +/hello.ts(1,9): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,9): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,9): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,13): error test-errors[Throws11]: Not allowed. +/hello.ts(1,13): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,13): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,13): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,37): error test-errors[Throws11]: Not allowed. +/hello.ts(1,37): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,37): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,37): error test-errors[Throws9](THROWS9): Not allowed. !!! warning test-errors: Not allowed. !!! warning test-errors[Throws2](THROWS2): Not allowed. -==== /hello.ts (4 errors) ==== +!!! error test-errors[Throws7]: Not allowed. +!!! error test-errors[Throws8](THROWS8): Not allowed. +!!! error test-errors[ThrowsOnAfterVisit](!!!): afterVisit failed with error: Error: Throws on afterVisit +!!! error test-errors[ThrowsOnConstruct]: Lint construction failed: Throws on construct +!!! error test-errors[ThrowsOnVisit](!!!): visit failed with error: Error: Throws on visit +==== /hello.ts (32 errors) ==== console.log("Hello, world!");/*EOL*/ ~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~ !!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ !!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~ +!!! error test-errors[Throws10](THROWS10): Not allowed. + ~~~~~~~~~~ +!!! error test-errors[Throws12]: Not allowed. ~~~~~~~~~~ !!! warning test-errors[Throws4](THROWS4): Not allowed. ~~~~~~~~~~ -!!! warning test-errors[Throws6]: Not allowed. \ No newline at end of file +!!! warning test-errors[Throws6]: Not allowed. + ~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + +!!! error test-errors[Throws11]: Not allowed. + +!!! warning test-errors[Throws3](THROWS3): Not allowed. + +!!! warning test-errors[Throws5]: Not allowed. + +!!! error test-errors[Throws9](THROWS9): Not allowed. \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt index 6ec0aa5f7ee8e..9e6fc2a47ab5c 100644 --- a/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/reportsAllDIagnosticsFormats/test.errors.txt @@ -1,20 +1,114 @@ warning test-errors: Not allowed. warning test-errors[Throws2](THROWS2): Not allowed. +error test-errors[Throws7]: Not allowed. +error test-errors[Throws8](THROWS8): Not allowed. +error test-errors[ThrowsOnAfterVisit](!!!): afterVisit failed with error: Error: Throws on afterVisit +error test-errors[ThrowsOnConstruct]: Lint construction failed: Throws on construct +error test-errors[ThrowsOnVisit](!!!): visit failed with error: Error: Throws on visit +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. /hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. /hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws10](THROWS10): Not allowed. +/hello.ts(1,1): error test-errors[Throws12]: Not allowed. /hello.ts(1,1): warning test-errors[Throws4](THROWS4): Not allowed. /hello.ts(1,1): warning test-errors[Throws6]: Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,1): error test-errors[Throws11]: Not allowed. +/hello.ts(1,1): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,1): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,1): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,9): error test-errors[Throws11]: Not allowed. +/hello.ts(1,9): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,9): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,9): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,13): error test-errors[Throws11]: Not allowed. +/hello.ts(1,13): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,13): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,13): error test-errors[Throws9](THROWS9): Not allowed. +/hello.ts(1,37): error test-errors[Throws11]: Not allowed. +/hello.ts(1,37): warning test-errors[Throws3](THROWS3): Not allowed. +/hello.ts(1,37): warning test-errors[Throws5]: Not allowed. +/hello.ts(1,37): error test-errors[Throws9](THROWS9): Not allowed. !!! warning test-errors: Not allowed. !!! warning test-errors[Throws2](THROWS2): Not allowed. -==== /hello.ts (4 errors) ==== +!!! error test-errors[Throws7]: Not allowed. +!!! error test-errors[Throws8](THROWS8): Not allowed. +!!! error test-errors[ThrowsOnAfterVisit](!!!): afterVisit failed with error: Error: Throws on afterVisit +!!! error test-errors[ThrowsOnConstruct]: Lint construction failed: Throws on construct +!!! error test-errors[ThrowsOnVisit](!!!): visit failed with error: Error: Throws on visit +==== /hello.ts (32 errors) ==== console.log("Hello, world!");/*EOL*/ ~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~ !!! warning test-errors[Throws3](THROWS3): Not allowed. ~~~~~~~ !!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~ +!!! error test-errors[Throws10](THROWS10): Not allowed. + ~~~~~~~~~~ +!!! error test-errors[Throws12]: Not allowed. ~~~~~~~~~~ !!! warning test-errors[Throws4](THROWS4): Not allowed. ~~~~~~~~~~ -!!! warning test-errors[Throws6]: Not allowed. \ No newline at end of file +!!! warning test-errors[Throws6]: Not allowed. + ~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + ~~~~~~~~~~~~~~~ +!!! error test-errors[Throws11]: Not allowed. + ~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws3](THROWS3): Not allowed. + ~~~~~~~~~~~~~~~ +!!! warning test-errors[Throws5]: Not allowed. + ~~~~~~~~~~~~~~~ +!!! error test-errors[Throws9](THROWS9): Not allowed. + +!!! error test-errors[Throws11]: Not allowed. + +!!! warning test-errors[Throws3](THROWS3): Not allowed. + +!!! warning test-errors[Throws5]: Not allowed. + +!!! error test-errors[Throws9](THROWS9): Not allowed. \ No newline at end of file diff --git a/tests/cases/extensions/available/extension-api/index.ts b/tests/cases/extensions/available/extension-api/index.ts index 0dc791d5324d0..f46c222d83641 100644 --- a/tests/cases/extensions/available/extension-api/index.ts +++ b/tests/cases/extensions/available/extension-api/index.ts @@ -12,7 +12,7 @@ export abstract class SyntacticLintWalker implements tsi.LintWalker { this.host = state.host; this.program = state.program; } - abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; + abstract visit(node: tsi.Node, error: tsi.LintErrorMethod): boolean | void; } export abstract class SemanticLintWalker implements tsi.LintWalker { @@ -29,7 +29,7 @@ export abstract class SemanticLintWalker implements tsi.LintWalker { this.program = state.program; this.checker = state.checker; } - abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void; + abstract visit(node: tsi.Node, error: tsi.LintErrorMethod): boolean | void; } export abstract class LanguageServiceProvider implements tsi.LanguageServiceProvider { diff --git a/tests/cases/extensions/available/test-errors/index.ts b/tests/cases/extensions/available/test-errors/index.ts index 4548b4282db6b..1b4773d8f1583 100644 --- a/tests/cases/extensions/available/test-errors/index.ts +++ b/tests/cases/extensions/available/test-errors/index.ts @@ -2,48 +2,116 @@ import {SyntacticLintWalker} from "extension-api"; export default class Throws extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("Not allowed."); - stop(); + return false; } } export class Throws2 extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("THROWS2", "Not allowed."); - stop(); + return false; } } export class Throws3 extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("THROWS3", "Not allowed.", node); - stop(); + return false; } } export class Throws4 extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("THROWS4", "Not allowed.", 0, 10); - stop(); + return false; } } export class Throws5 extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("Not allowed.", node); - stop(); + return false; } } export class Throws6 extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { error("Not allowed.", 0, 10); - stop(); + return false; + } +} + +export class Throws7 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "Not allowed."); + return false; + } +} + +export class Throws8 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "THROWS8", "Not allowed."); + return false; + } +} + +export class Throws9 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "THROWS9", "Not allowed.", node); + return false; + } +} + +export class Throws10 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "THROWS10", "Not allowed.", 0, 10); + return false; + } +} + +export class Throws11 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "Not allowed.", node); + return false; + } +} + +export class Throws12 extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + error(this.ts.DiagnosticCategory.Error, "Not allowed.", 0, 10); + return false; + } +} + +export class ThrowsOnConstruct extends SyntacticLintWalker { + constructor(state) { super(state); throw new Error("Throws on construct"); } + visit(node, error) {} +} + +export class ThrowsOnVisit extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { + throw new Error("Throws on visit"); + } +} + +export class ThrowsOnAfterVisit extends SyntacticLintWalker { + constructor(state) { super(state); } + visit(node, error) { return false; } + afterVisit(node, error) { + throw new Error("Throws on afterVisit"); } } \ No newline at end of file diff --git a/tests/cases/extensions/available/test-extension-arguments/index.ts b/tests/cases/extensions/available/test-extension-arguments/index.ts index 2a1c7d8ff3b89..3f14d54d4b325 100644 --- a/tests/cases/extensions/available/test-extension-arguments/index.ts +++ b/tests/cases/extensions/available/test-extension-arguments/index.ts @@ -2,7 +2,7 @@ import {SyntacticLintWalker} from "extension-api"; export default class IsNamedX extends SyntacticLintWalker { constructor(state) { super(state); } - visit(node, stop, error) { + visit(node, error) { if (node.kind === this.ts.SyntaxKind.Identifier) { for (let i = 0; i Date: Fri, 15 Jul 2016 12:56:08 -0700 Subject: [PATCH 42/49] Feedback from pr --- src/compiler/tsc.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index de7694b876b95..42f05f8e8c988 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -591,14 +591,15 @@ namespace ts { reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); } - const perfTotals = reduceProperties(perfTraces, (aggregate, value, key) => { - if (!value.globalBucket) return aggregate; - if (typeof aggregate[value.globalBucket] !== "number") { - aggregate[value.globalBucket] = 0; - } - aggregate[value.globalBucket] += value.length; - return aggregate; - }, {} as {[index: string]: number}); + const perfTotals: Map = {}; + for (const key of getKeys(perfTraces)) { + const value = perfTraces[key]; + if (!value) continue; + if (typeof perfTotals[value.globalBucket] !== "number") { + perfTotals[value.globalBucket] = 0; + } + perfTotals[value.globalBucket] += value.length; + } forEachKey(perfTotals, (key) => { reportTimeStatistic(`'${key}' time`, perfTotals[key]); }); @@ -612,14 +613,14 @@ namespace ts { diagnostics = program.getSyntacticDiagnostics(); // Count warnings and ignore them for determining continued error reporting - const warningsCount = filter(diagnostics, d => d.category === DiagnosticCategory.Warning).length; + const warningsCount = countWhere(diagnostics, d => d.category === DiagnosticCategory.Warning); // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. if (diagnostics.length === warningsCount) { diagnostics = diagnostics.concat(program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics())); - const warningsCount = filter(diagnostics, d => d.category === DiagnosticCategory.Warning).length; + const warningsCount = countWhere(diagnostics, d => d.category === DiagnosticCategory.Warning); if (diagnostics.length === warningsCount) { diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); From 86fcfb42043b8f762cfbeea21683a712258974bb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 15 Jul 2016 13:07:33 -0700 Subject: [PATCH 43/49] Reexpose startsWith and endsWith --- src/compiler/core.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 3f21a820cde1d..4dc6e8543ab0f 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1,5 +1,16 @@ /// +namespace ts { + export function startsWith(str: string, prefix: string): boolean { + return str.lastIndexOf(prefix, 0) === 0; + } + + export function endsWith(str: string, suffix: string): boolean { + const expectedPos = str.length - suffix.length; + return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos; + } +} + /* @internal */ namespace ts { /** @@ -919,17 +930,6 @@ namespace ts { return true; } - /* @internal */ - export function startsWith(str: string, prefix: string): boolean { - return str.lastIndexOf(prefix, 0) === 0; - } - - /* @internal */ - export function endsWith(str: string, suffix: string): boolean { - const expectedPos = str.length - suffix.length; - return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos; - } - export function fileExtensionIs(path: string, extension: string): boolean { return path.length > extension.length && endsWith(path, extension); } From e173bc6b25bf457e9f5284a2d3d63a9ca9c4e482 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 15 Jul 2016 15:31:35 -0700 Subject: [PATCH 44/49] PR feedback --- src/compiler/extensions.ts | 83 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index a7305b24844d0..e5b9a34cea08f 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -329,49 +329,50 @@ namespace ts { }); const successfulExtensionLoadResults = filter(extensionLoadResults, res => !res.error); const preparedExtensionObjects = map(successfulExtensionLoadResults, res => { - if (res.result) { - return reduceProperties(res.result, (aggregate: Extension[], potentialExtension: BaseProviderStatic, key: string) => { - if (!potentialExtension) { - return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) - } - const annotatedKind = potentialExtension["extension-kind"]; - if (typeof annotatedKind === "string") { - const ext: ExtensionBase = { - name: key !== "default" ? `${res.name}[${key}]` : res.name, - args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], - kind: annotatedKind, - }; - switch (ext.kind) { - case ExtensionKind.SemanticLint: - case ExtensionKind.SyntacticLint: - case ExtensionKind.LanguageService: - if (typeof potentialExtension !== "function") { - diagnostics.push(createCompilerDiagnostic( - Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, - res.name, - key, - (ts as any).ExtensionKind[annotatedKind], - typeof potentialExtension, - "function" - )); - return; - } - (ext as (SemanticLintExtension | SyntacticLintExtension | LanguageServiceExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic | LanguageServiceProviderStatic); - break; - default: - // Include a default case which just puts the extension unchecked onto the base extension - // This can allow language service extensions to query for custom extension kinds - (ext as any).__extension = potentialExtension; - break; - } - aggregate.push(ext as Extension); - } - return aggregate; - }, []); - } - else { + if (!res.result) { return []; } + const aggregate: Extension[] = []; + forEachKey(res.result, key => { + const potentialExtension = res.result[key] as BaseProviderStatic; + if (!potentialExtension) { + return; // Avoid errors on explicitly exported null/undefined (why would someone do that, though?) + } + const annotatedKind = potentialExtension["extension-kind"]; + if (typeof annotatedKind !== "string") { + return; + } + const ext: ExtensionBase = { + name: key !== "default" ? `${res.name}[${key}]` : res.name, + args: extensionNames === extOptions ? undefined : (extOptions as Map)[res.name], + kind: annotatedKind, + }; + switch (ext.kind) { + case ExtensionKind.SemanticLint: + case ExtensionKind.SyntacticLint: + case ExtensionKind.LanguageService: + if (typeof potentialExtension !== "function") { + diagnostics.push(createCompilerDiagnostic( + Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected, + res.name, + key, + (ts as any).ExtensionKind[annotatedKind], + typeof potentialExtension, + "function" + )); + return; + } + (ext as (SemanticLintExtension | SyntacticLintExtension | LanguageServiceExtension)).ctor = potentialExtension as (SemanticLintProviderStatic | SyntacticLintProviderStatic | LanguageServiceProviderStatic); + break; + default: + // Include a default case which just puts the extension unchecked onto the base extension + // This can allow language service extensions to query for custom extension kinds + (ext as any).__extension = potentialExtension; + break; + } + aggregate.push(ext as Extension); + }); + return aggregate; }); return groupBy(flatten(preparedExtensionObjects), elem => elem.kind) || {}; } From b8ca16aaf6897de58833b3ada22b404cf8bd967e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 20 Jul 2016 11:39:32 -0700 Subject: [PATCH 45/49] Use new performance framework, remove extra compiler option, traces --- src/compiler/commandLineParser.ts | 13 +--- src/compiler/diagnosticMessages.json | 16 +--- src/compiler/extensions.ts | 76 +++++-------------- src/compiler/performance.ts | 5 +- src/compiler/program.ts | 14 ++-- src/compiler/types.ts | 7 -- src/harness/extensionRunner.ts | 4 +- .../profileExtensionsTraces/test.trace.txt | 74 ------------------ .../profileExtensionsTraces/test.trace.txt | 74 ------------------ 9 files changed, 35 insertions(+), 248 deletions(-) delete mode 100644 tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt delete mode 100644 tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 02e1a5ac33323..ee72e5e17bca0 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -139,12 +139,12 @@ namespace ts { { name: "noUnusedLocals", type: "boolean", - description: Diagnostics.Report_errors_on_unused_locals, + description: Diagnostics.Report_errors_on_unused_locals, }, { name: "noUnusedParameters", type: "boolean", - description: Diagnostics.Report_errors_on_unused_parameters, + description: Diagnostics.Report_errors_on_unused_parameters, }, { name: "noLib", @@ -436,15 +436,6 @@ namespace ts { type: "boolean", description: Diagnostics.Enable_strict_null_checks }, - { - name: "profileExtensions", - type: { - "none": ProfileLevel.None, - "summary": ProfileLevel.Summary, - "full": ProfileLevel.Full, - }, - description: Diagnostics.Set_extension_profiling_level_Colon, - } ]; /* @internal */ diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1eb74e246badb..8f7f7a27691b1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2800,11 +2800,11 @@ "category": "Error", "code": 6133 }, - "Report errors on unused locals.": { + "Report errors on unused locals.": { "category": "Message", "code": 6134 }, - "Report errors on unused parameters.": { + "Report errors on unused parameters.": { "category": "Message", "code": 6135 }, @@ -2825,18 +2825,6 @@ "category": "Error", "code": 6152 }, - "Set extension profiling level:": { - "category": "Message", - "code": 6153 - }, - "PROFILE: Extension '{0}' begin '{1}'": { - "category": "Message", - "code": 6154 - }, - "PROFILE: Extension '{0}' end '{1}' ({2} ms)": { - "category": "Message", - "code": 6155 - }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/extensions.ts b/src/compiler/extensions.ts index e5b9a34cea08f..a458b0a247a4f 100644 --- a/src/compiler/extensions.ts +++ b/src/compiler/extensions.ts @@ -141,12 +141,11 @@ namespace ts { kind: ExtensionKind; } - export type Timestamp = number & { __timestampBrand: void }; export interface ProfileData { globalBucket: string; task: string; - start: Timestamp; - length?: Timestamp; + start: number; + length?: number; } export interface SyntacticLintExtension extends ExtensionBase { @@ -187,34 +186,6 @@ namespace ts { getCompilerExtensions(): ExtensionCollectionMap; } - function profileTrace(trace: (s: string) => void | undefined, message: DiagnosticMessage, ...args: any[]) { - if (trace) { - trace(flattenDiagnosticMessageText(createCompilerDiagnostic(message, ...args).messageText, (sys && sys.newLine || "\n"))); - } - } - - declare var performance: { now?(): number }; // If we're running in a context with high resolution timers, make use of them - declare var process: { hrtime?(start?: [number, number]): [number, number] }; - - function getTimestampInternal(): number { - if (typeof performance !== "undefined" && performance.now) { - return performance.now(); - } - if (typeof process !== "undefined" && process.hrtime) { - const time = process.hrtime(); - return (time[0] * 1e9 + time[1]) / 1e6; - } - return +(new Date()); - } - - export function getTimestampMs(since?: Timestamp): Timestamp { - if (typeof since !== "number") { - return getTimestampInternal() as Timestamp; - } - - return (getTimestampInternal() - since) as Timestamp; - } - export const perfTraces: Map = {}; function getExtensionRootName(qualifiedName: string) { @@ -225,33 +196,34 @@ namespace ts { return `${task}|${qualifiedName}`; } - export function startProfile(key: string, bucket?: string) { + export function startProfile(enabled: boolean, key: string, bucket?: string) { + if (!enabled) return; + performance.emit(`start|${key}`); perfTraces[key] = { task: key, - start: getTimestampMs(), + start: performance.mark(), length: undefined, globalBucket: bucket }; } - export function completeProfile(key: string) { + export function completeProfile(enabled: boolean, key: string) { + if (!enabled) return; Debug.assert(!!perfTraces[key], "Completed profile did not have a corresponding start."); - perfTraces[key].length = getTimestampMs(perfTraces[key].start); + perfTraces[key].length = performance.measure(perfTraces[key].globalBucket, perfTraces[key].start); + performance.emit(`end|${key}`); } - export function startExtensionProfile(level: ProfileLevel, qualifiedName: string, task: string, trace?: (s: string) => void) { - if (!level) return; - if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_begin_1, qualifiedName, task); + export function startExtensionProfile(enabled: boolean, qualifiedName: string, task: string) { + if (!enabled) return; const longTask = createTaskName(qualifiedName, task); - startProfile(longTask, getExtensionRootName(qualifiedName)); + startProfile(/*enabled*/true, longTask, getExtensionRootName(qualifiedName)); } - export function completeExtensionProfile(level: ProfileLevel, qualifiedName: string, task: string, trace?: (s: string) => void) { - if (!level) return; + export function completeExtensionProfile(enabled: boolean, qualifiedName: string, task: string) { + if (!enabled) return; const longTask = createTaskName(qualifiedName, task); - completeProfile(longTask); - - if (level >= ProfileLevel.Full) profileTrace(trace, Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, qualifiedName, task, perfTraces[longTask].length.toPrecision(5)); + completeProfile(/*enabled*/true, longTask); } export function createExtensionCache(options: CompilerOptions, host: ExtensionHost, resolvedExtensionNames?: Map): ExtensionCache { @@ -278,10 +250,6 @@ namespace ts { }; return cache; - function trace(message: DiagnosticMessage, ...args: any[]) { - profileTrace(host.trace, message, ...args); - } - function resolveExtensionNames(): Map { const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ""; const extMap: Map = {}; @@ -295,7 +263,7 @@ namespace ts { } function collectCompilerExtensions(): ExtensionCollectionMap { - const profileLevel = options.profileExtensions; + const profilingEnabled = options.extendedDiagnostics; const extensionLoadResults = map(extensionNames, (name) => { const resolved = resolvedExtensionNames[name]; let result: any; @@ -305,15 +273,9 @@ namespace ts { } if (resolved && host.loadExtension) { try { - if (profileLevel) { - startProfile(name, name); - if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_begin_1, name, "load"); - } + startProfile(profilingEnabled, name, name); result = host.loadExtension(resolved); - if (profileLevel) { - completeProfile(name); - if (profileLevel >= ProfileLevel.Full) trace(Diagnostics.PROFILE_Colon_Extension_0_end_1_2_ms, name, "load", perfTraces[name].length.toPrecision(5)); - } + completeProfile(profilingEnabled, name); } catch (e) { error = e; diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts index f40b191a1a591..a41209aff1ca3 100644 --- a/src/compiler/performance.ts +++ b/src/compiler/performance.ts @@ -54,10 +54,11 @@ namespace ts { * @param measureName The name of the performance measurement. * @param marker The timestamp of the starting mark. */ - export function measure(measureName: string, marker: number) { + export function measure(measureName: string, marker: number): number { if (measures) { - measures[measureName] = (getProperty(measures, measureName) || 0) + (Date.now() - marker); + return measures[measureName] = (getProperty(measures, measureName) || 0) + (Date.now() - marker); } + return 0; } /** diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c340eb0a0e2e6..8ddc3f5ea865a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1535,29 +1535,29 @@ namespace ts { const diagnostics: Diagnostic[] = []; let activeLint: UniqueLint; let parent: Node | undefined = undefined; - const profileLevel = options.profileExtensions; + const profilingEnabled = options.extendedDiagnostics; for (const {name, args, ctor} of lints) { let walker: LintWalker; if (kind === ExtensionKind.SemanticLint) { const checker = getTypeChecker(); - startExtensionProfile(profileLevel, name, "construct", host.trace); + startExtensionProfile(profilingEnabled, name, "construct"); try { walker = new (ctor as SemanticLintProviderStatic)({ ts, checker, args, host, program }); } catch (e) { diagnostics.push(createExtensionDiagnostic(name, `Lint construction failed: ${(e as Error).message}`, sourceFile, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); } - completeExtensionProfile(profileLevel, name, "construct", host.trace); + completeExtensionProfile(profilingEnabled, name, "construct"); } else if (kind === ExtensionKind.SyntacticLint) { - startExtensionProfile(profileLevel, name, "construct", host.trace); + startExtensionProfile(profilingEnabled, name, "construct"); try { walker = new (ctor as SyntacticLintProviderStatic)({ ts, args, host, program }); } catch (e) { diagnostics.push(createExtensionDiagnostic(name, `Lint construction failed: ${(e as Error).message}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); } - completeExtensionProfile(profileLevel, name, "construct", host.trace); + completeExtensionProfile(profilingEnabled, name, "construct"); } if (walker) initializedLints.push({ name, walker, accepted: true, errored: false }); } @@ -1577,7 +1577,7 @@ namespace ts { activeLint = initializedLints[i]; if (activeLint.accepted) { if (!activeLint.errored) { - startExtensionProfile(profileLevel, activeLint.name, `visitNode|${nodesVisited}`, host.trace); + startExtensionProfile(profilingEnabled, activeLint.name, `visitNode|${nodesVisited}`); try { activeLint.accepted = !activeLint.walker.visit(node, error); } @@ -1585,7 +1585,7 @@ namespace ts { activeLint.errored = true; diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `visit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); } - completeExtensionProfile(profileLevel, activeLint.name, `visitNode|${nodesVisited}`, host.trace); + completeExtensionProfile(profilingEnabled, activeLint.name, `visitNode|${nodesVisited}`); } if (activeLint.accepted) { oneAccepted = true; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 94fe5ea46cf57..4ee340789b327 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2605,17 +2605,10 @@ namespace ts { /*@internal*/ version?: boolean; /*@internal*/ watch?: boolean; extensions?: string[] | Map; - profileExtensions?: ProfileLevel; [option: string]: CompilerOptionsValue | undefined; } - export const enum ProfileLevel { - None, - Summary, - Full - } - export interface TypingOptions { enableAutoDiscovery?: boolean; include?: string[]; diff --git a/src/harness/extensionRunner.ts b/src/harness/extensionRunner.ts index b1771e2590356..ca7ab8c4a6d9b 100644 --- a/src/harness/extensionRunner.ts +++ b/src/harness/extensionRunner.ts @@ -328,7 +328,7 @@ class ExtensionRunner extends RunnerBase { let sources: ts.Map; let result: Harness.Compiler.CompilerResult; before(() => { - this.traces = []; // Clear out any traces from tests which made traces, but didn't specify traceResolution or profileExtensions + this.traces = []; // Clear out any traces from tests which made traces, but didn't specify traceResolution this.virtualFs = {}; // In case a fourslash test was run last (which doesn't clear FS on end like buildMap does), clear the FS sources = {}; ts.copyMap(inputSources, sources); @@ -353,7 +353,7 @@ class ExtensionRunner extends RunnerBase { const traceTestName = `Correct traces`; it(traceTestName, () => { - if (!(testConfig.compilerOptions.traceResolution || testConfig.compilerOptions.profileExtensions)) { + if (!(testConfig.compilerOptions.traceResolution)) { return; } Harness.Baseline.runBaseline(traceTestName, `${name}/${shortCasePath}.trace.txt`, (): string => { diff --git a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt deleted file mode 100644 index 53405c1d07d9d..0000000000000 --- a/tests/baselines/reference/CompilerHost/profileExtensionsTraces/test.trace.txt +++ /dev/null @@ -1,74 +0,0 @@ -PROFILE: Extension 'test-multi-extension' begin 'load' -PROFILE: Extension 'test-multi-extension' end 'load' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|8' (REDACTED ms) \ No newline at end of file diff --git a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt b/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt deleted file mode 100644 index 53405c1d07d9d..0000000000000 --- a/tests/baselines/reference/LanguageServiceHost/profileExtensionsTraces/test.trace.txt +++ /dev/null @@ -1,74 +0,0 @@ -PROFILE: Extension 'test-multi-extension' begin 'load' -PROFILE: Extension 'test-multi-extension' end 'load' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsNamedFoo]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsNamedBar]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsNamedBar]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'construct' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'construct' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|1' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|1' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|2' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|2' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|3' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|3' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|4' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|4' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|5' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|5' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|6' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|6' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|7' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|7' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueFoo]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsValueFoo]' end 'visitNode|8' (REDACTED ms) -PROFILE: Extension 'test-multi-extension[IsValueBar]' begin 'visitNode|8' -PROFILE: Extension 'test-multi-extension[IsValueBar]' end 'visitNode|8' (REDACTED ms) \ No newline at end of file From ae66e997bd758b50065dbeeff94c33df7add416c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 21 Jul 2016 12:11:14 -0700 Subject: [PATCH 46/49] Cleanup performLintPass from feedback from @sandersn --- src/compiler/program.ts | 261 ++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 147 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8ddc3f5ea865a..0406fd4de6575 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1562,59 +1562,70 @@ namespace ts { if (walker) initializedLints.push({ name, walker, accepted: true, errored: false }); } - let nodesVisited = 0; - visitNode(sourceFile); - - return diagnostics; - function visitNode(node: Node) { - node.parent = parent; - nodesVisited++; let oneAccepted = false; - const oldParent = parent; const needsReset: Map = {}; + + // Ensure parent pointer is set + node.parent = parent; + + // For each lint, except those which have errored or have not accepted a parental node, call its rule for (let i = 0; i < initializedLints.length; i++) { activeLint = initializedLints[i]; + if (activeLint.errored || !activeLint.accepted) { + continue; + } + + startExtensionProfile(profilingEnabled, activeLint.name, "visit"); + try { + activeLint.accepted = !activeLint.walker.visit(node, error); + } + catch (e) { + activeLint.errored = true; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `visit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + completeExtensionProfile(profilingEnabled, activeLint.name, "visit"); + if (activeLint.accepted) { - if (!activeLint.errored) { - startExtensionProfile(profilingEnabled, activeLint.name, `visitNode|${nodesVisited}`); - try { - activeLint.accepted = !activeLint.walker.visit(node, error); - } - catch (e) { - activeLint.errored = true; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `visit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); - } - completeExtensionProfile(profilingEnabled, activeLint.name, `visitNode|${nodesVisited}`); - } - if (activeLint.accepted) { - oneAccepted = true; - } - else { - needsReset[i] = true; - } + oneAccepted = true; + } + else { + needsReset[i] = true; } } + + // Save the parent, then recur into the child nodes + const oldParent = parent; parent = node; if (oneAccepted) { forEachChild(node, visitNode); } parent = oldParent; + + // All this node's children have been processed, for each lint + // - If it set accepted to false during this node (needsReset), set it back to true + // - If it has an afterVisit method, call it for (let i = 0; i < initializedLints.length; i++) { activeLint = initializedLints[i]; + if (activeLint.errored) { + continue; + } if (!needsReset[i]) { activeLint.accepted = true; needsReset[i] = false; } - if (!activeLint.errored && activeLint.walker.afterVisit) { - try { - activeLint.walker.afterVisit(node, error); - } - catch (e) { - activeLint.errored = true; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `afterVisit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); - } + if (!activeLint.walker.afterVisit) { + continue; + } + startExtensionProfile(profilingEnabled, activeLint.name, "afterVisit"); + try { + activeLint.walker.afterVisit(node, error); } + catch (e) { + activeLint.errored = true; + diagnostics.push(createExtensionDiagnostic(errorQualifiedName("!!!"), `afterVisit failed with error: ${e}`, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, DiagnosticCategory.Error)); + } + completeExtensionProfile(profilingEnabled, activeLint.name, "afterVisit"); } } @@ -1623,74 +1634,19 @@ namespace ts { return `${activeLint.name}(${shortname})`; } - function error(err: string): void; - function error(err: string, node: Node): void; - function error(err: string, start: number, length: number): void; - function error(shortname: string, err: string): void; - function error(shortname: string, err: string, span: Node): void; - function error(shortname: string, err: string, start: number, length: number): void; - function error(level: DiagnosticCategory, err: string): void; - function error(level: DiagnosticCategory, err: string, node: Node): void; - function error(level: DiagnosticCategory, err: string, start: number, length: number): void; - function error(level: DiagnosticCategory, shortname: string, err: string): void; - function error(level: DiagnosticCategory, shortname: string, err: string, span: Node): void; - function error(level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; - function error( - levelErrOrShortname: DiagnosticCategory | string, - errShortnameSpanOrStart?: string | Node | number, - errSpanStartOrLength?: string | Node | number, - startSpanOrLength?: number | Node, - length?: number): void { - if (typeof levelErrOrShortname === "undefined") { - Debug.fail("You must at least provide an error message to error."); - return; - } - if (typeof errShortnameSpanOrStart === "undefined") { - if (typeof levelErrOrShortname !== "string") { - Debug.fail("If only one argument is passed to error, it must be the error message string."); - return; - } - // error(err: string): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), levelErrOrShortname)); - return; - } - if (typeof errSpanStartOrLength === "undefined") { - error2Arguments(levelErrOrShortname, errShortnameSpanOrStart); - return; - } - if (typeof startSpanOrLength === "undefined") { - error3Arguments(levelErrOrShortname, errShortnameSpanOrStart, errSpanStartOrLength); - return; - } - if (typeof length === "undefined") { - error4Arguments(levelErrOrShortname, errShortnameSpanOrStart, errSpanStartOrLength, startSpanOrLength); - return; + function ensure(param: any, paramName: string, istype: string) { + if (typeof param !== istype) { + Debug.fail(`${paramName} must be a ${istype}.`); } - if (typeof levelErrOrShortname !== "number") { - Debug.fail("When five arguments are passed to error, the first must be the diagnostic category of the error."); - return; - } - if (typeof errShortnameSpanOrStart !== "string") { - Debug.fail("When five arguments are passed to error, the second argument must be the shortname of the error."); - return; - } - if (typeof errSpanStartOrLength !== "string") { - Debug.fail("When five arguments are passed to error, the third argument must be the error message."); - return; - } - if (typeof startSpanOrLength !== "number") { - Debug.fail("When five arguments are passed to error, the fourth argument must be the start position of the error span."); - return; - } - if (typeof length !== "number") { - Debug.fail("When five arguments are passed to error, the fifth argument must be the length of the error span."); - return; - } - // error(level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(errShortnameSpanOrStart), errSpanStartOrLength, sourceFile, startSpanOrLength, length, levelErrOrShortname)); } - function error2Arguments(errShortnameOrLevel: string | DiagnosticCategory, spanOrErr: Node | string | number): void { + const errorOverloads: ((...args: any[]) => void)[] = [() => { + Debug.fail("You must at least provide an error message to the error function."); + }, + (err: string) => { + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), err)); + }, + (errShortnameOrLevel: string | DiagnosticCategory, spanOrErr: Node | string | number) => { if (typeof errShortnameOrLevel === "string") { if (typeof spanOrErr === "string") { // error(shortname: string, err: string): void; @@ -1705,31 +1661,26 @@ namespace ts { } } else if (typeof errShortnameOrLevel === "number") { - if (typeof spanOrErr !== "string") { - Debug.fail("When two arguments are passed to error and the first is a DiagnosticCategory, the second must be the error message string."); - return; - } + ensure(spanOrErr, "Error message", "string"); + // error(level: DiagnosticCategory, err: string): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), spanOrErr, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), spanOrErr as string, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); } else { Debug.fail("When two arguments are passed to error, the first argument must be either the error message, the error shortname, or the DiagnosticCategory of the error."); } - } - - function error3Arguments(errShortnameOrLevel: string | DiagnosticCategory, startErrOrShortname: number | string | Node, lengthSpanOrErr: number | Node | string) { + }, + (errShortnameOrLevel: string | DiagnosticCategory, startErrOrShortname: number | string | Node, lengthSpanOrErr: number | Node | string) => { if (typeof errShortnameOrLevel === "number") { - if (typeof startErrOrShortname !== "string") { - Debug.fail("When three arguments are passed to error and the first is a diagnostic category, the second argument must be either an error message or shortcode."); - return; - } + ensure(startErrOrShortname, "Error message or error shortcode", "string"); + if (typeof lengthSpanOrErr === "string") { // error(level: DiagnosticCategory, shortname: string, err: string): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(startErrOrShortname), lengthSpanOrErr, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(startErrOrShortname as string), lengthSpanOrErr, /*sourceFile*/undefined, /*start*/undefined, /*length*/undefined, errShortnameOrLevel)); } else if (typeof lengthSpanOrErr === "object") { // error(level: DiagnosticCategory, err: string, node: Node): void; - diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr, errorQualifiedName(), startErrOrShortname, errShortnameOrLevel)); + diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr, errorQualifiedName(), startErrOrShortname as string, errShortnameOrLevel)); } else { Debug.fail("When three arguments are passed to error and the first is a diagnostic category, the third argument must either be an error message or the node errored on."); @@ -1737,20 +1688,16 @@ namespace ts { } else if (typeof errShortnameOrLevel === "string") { if (typeof startErrOrShortname === "number") { - if (typeof lengthSpanOrErr !== "number") { - Debug.fail("When three arguments are passed to error and the first is an error message, the third must be the message length."); - return; - } + ensure(lengthSpanOrErr, "Error span length", "number"); + // error(err: string, start: number, length: number): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errShortnameOrLevel, sourceFile, startErrOrShortname, lengthSpanOrErr)); + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errShortnameOrLevel, sourceFile, startErrOrShortname, lengthSpanOrErr as number)); } else if (typeof startErrOrShortname === "string") { - if (typeof lengthSpanOrErr !== "object") { - Debug.fail("When three arguments are passed to error and the first is an error shortcode, the third must be the node errored on."); - return; - } + ensure(lengthSpanOrErr, "Error node", "object"); + // error(shortname: string, err: string, span: Node): void; - diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr, errorQualifiedName(errShortnameOrLevel), startErrOrShortname)); + diagnostics.push(createExtensionDiagnosticForNode(lengthSpanOrErr as Node, errorQualifiedName(errShortnameOrLevel), startErrOrShortname)); } else { Debug.fail("When three arguments are passed to error and the first is an error shortcode or message, the second must be either an error message or a span start number, respectively."); @@ -1759,29 +1706,22 @@ namespace ts { else { Debug.fail("When three arguments are passed to error, the first argument must be either a diagnostic category, a error shortname, or an error message."); } - } + }, + (levelOrShortname: DiagnosticCategory | string, errOrShortname: string | number | Node, startOrErr: string | number | Node, lengthOrSpan: number | Node) => { + ensure(errOrShortname, "Error message or error shortcode", "string"); - function error4Arguments(levelOrShortname: DiagnosticCategory | string, errOrShortname: string | number | Node, startOrErr: string | number | Node, lengthOrSpan: number | Node) { - if (typeof errOrShortname !== "string") { - Debug.fail("When four arguments are passed to error, the second argument must either be an error message string or an error shortcode."); - return; - } if (typeof levelOrShortname === "number") { if (typeof startOrErr === "string") { - if (typeof lengthOrSpan !== "object") { - Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the fourth argument must be the node errored on."); - return; - } + ensure(lengthOrSpan, "Error node", "object"); + // error(level: DiagnosticCategory, shortname: string, err: string, span: Node): void; - diagnostics.push(createExtensionDiagnosticForNode(lengthOrSpan, errorQualifiedName(errOrShortname), startOrErr, levelOrShortname)); + diagnostics.push(createExtensionDiagnosticForNode(lengthOrSpan as Node, errorQualifiedName(errOrShortname as string), startOrErr, levelOrShortname)); } else if (typeof startOrErr === "number") { - if (typeof lengthOrSpan !== "number") { - Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the fourth argument must be the error span length."); - return; - } + ensure(lengthOrSpan, "Error span length", "number"); + // error(level: DiagnosticCategory, err: string, start: number, length: number): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errOrShortname, sourceFile, startOrErr, lengthOrSpan, levelOrShortname)); + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(), errOrShortname as string, sourceFile, startOrErr, lengthOrSpan as number, levelOrShortname)); } else { Debug.fail("When four arguments are passed to error and the first is a DiagnosticCategory, the third argument must be the error message."); @@ -1789,21 +1729,48 @@ namespace ts { } } else if (typeof levelOrShortname === "string") { - if (typeof startOrErr !== "number") { - Debug.fail("When four arguments are passed to error and the first is a error shortname string, the third argument must be the error span start."); - return; - } - if (typeof lengthOrSpan !== "number") { - Debug.fail("When four arguments are passed to error and the first is a error shortname string, the third argument must be the error span length."); - return; - } + ensure(startOrErr, "Error span start", "number"); + ensure(lengthOrSpan, "Error span length", "number"); + // error(shortname: string, err: string, start: number, length: number): void; - diagnostics.push(createExtensionDiagnostic(errorQualifiedName(levelOrShortname), errOrShortname, sourceFile, startOrErr, lengthOrSpan)); + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(levelOrShortname), errOrShortname as string, sourceFile, startOrErr as number, lengthOrSpan as number)); } else { Debug.fail("When four arguments are passed to error, the first argument must be either a DiagnosticCategory or a error shortname string."); } + }, + (level: DiagnosticCategory, shortname: string, err: string, start: number, length: number) => { + ensure(level, "Diagnostic level", "number"); + ensure(shortname, "Error shortcode", "string"); + ensure(err, "Error message", "string"); + ensure(start, "Error span start", "number"); + ensure(length, "Error span length", "number"); + + diagnostics.push(createExtensionDiagnostic(errorQualifiedName(shortname), err, sourceFile, start, length, level)); + }]; + + function tooManyArguments(length: number, found: number) { + return () => Debug.fail(`Too many arguments provided to error (Expected up to ${length}, but found ${found}).`); } + + function error(err: string): void; + function error(err: string, node: Node): void; + function error(err: string, start: number, length: number): void; + function error(shortname: string, err: string): void; + function error(shortname: string, err: string, span: Node): void; + function error(shortname: string, err: string, start: number, length: number): void; + function error(level: DiagnosticCategory, err: string): void; + function error(level: DiagnosticCategory, err: string, node: Node): void; + function error(level: DiagnosticCategory, err: string, start: number, length: number): void; + function error(level: DiagnosticCategory, shortname: string, err: string): void; + function error(level: DiagnosticCategory, shortname: string, err: string, span: Node): void; + function error(level: DiagnosticCategory, shortname: string, err: string, start: number, length: number): void; + function error(): void { + (errorOverloads[arguments.length] || tooManyArguments(errorOverloads.length - 1, arguments.length)).apply(/*thisArg*/undefined, arguments); + } + + visitNode(sourceFile); + return diagnostics; } function getSyntacticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { From 842d3c3580ca117479a0870b2c01e10c07fafd3c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 21 Jul 2016 14:21:38 -0700 Subject: [PATCH 47/49] Fix typo --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index f58288a69c7a9..8510041bddb97 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1255,7 +1255,7 @@ namespace ts { // Overrides // A plugin can implement one of the override methods to replace the results that would - // be returned by the TypeScript language service. If a plugin returns a defined results + // be returned by the TypeScript language service. If a plugin returns a defined result // (that is, is not undefined) then that result is used instead of invoking the // corresponding TypeScript method. If multiple plugins are registered, they are // consulted in the order they are returned from the program. The first defined result From 40b35c413e92482d5a83cd6bee30fbe6579318b9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 1 Aug 2016 14:53:19 -0700 Subject: [PATCH 48/49] Fix baselines with new AST, semantic lint test uses type instead of node --- .../multiLintLoads/both-diagnostics.errors.txt | 5 ++++- .../multiLintLoads/semantic-diagnostics.errors.txt | 5 ++++- .../multipleRulesFoundInSingleExtension/test.errors.txt | 8 +++++++- .../semanticLintLoads/w-diagnostics.errors.txt | 5 ++++- .../multiLintLoads/both-diagnostics.errors.txt | 5 ++++- .../multiLintLoads/semantic-diagnostics.errors.txt | 5 ++++- .../multipleRulesFoundInSingleExtension/test.errors.txt | 8 +++++++- .../semanticLintLoads/w-diagnostics.errors.txt | 5 ++++- .../extensions/available/test-multi-extension/index.ts | 5 +++-- .../cases/extensions/available/test-semantic-lint/main.ts | 3 ++- 10 files changed, 43 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt index 3468d669f3056..1cb72fb0e9434 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/both-diagnostics.errors.txt @@ -1,13 +1,16 @@ /foo-interface-const.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-interface-const.ts(2,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-interface-const.ts(2,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-interface-const.ts (3 errors) ==== +==== /foo-interface-const.ts (4 errors) ==== interface Foo {a; b;} ~~~ !!! warning test-syntactic-lint: Identifier 'foo' is forbidden. const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt index fedeb2199df77..7b4b32f665de6 100644 --- a/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -1,9 +1,12 @@ +/foo-const.ts(1,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-const.ts (2 errors) ==== +==== /foo-const.ts (3 errors) ==== const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt index 48d30107e5b3d..f2f78f412a2cb 100644 --- a/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt +++ b/tests/baselines/reference/CompilerHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -1,12 +1,14 @@ /foo-bar-const-interface.ts(1,11): warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. /foo-bar-const-interface.ts(2,11): warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,7): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. /foo-bar-const-interface.ts(3,10): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. /foo-bar-const-interface.ts(3,18): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,5): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. /foo-bar-const-interface.ts(4,8): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. /foo-bar-const-interface.ts(4,16): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. -==== /foo-bar-const-interface.ts (6 errors) ==== +==== /foo-bar-const-interface.ts (8 errors) ==== interface Foo {b;} ~~~ !!! warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. @@ -14,11 +16,15 @@ ~~~ !!! warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. const f: "foo" = "foo"; + ~ +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. let b: "bar" = "bar"; + ~ +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt index fedeb2199df77..7b4b32f665de6 100644 --- a/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/CompilerHost/semanticLintLoads/w-diagnostics.errors.txt @@ -1,9 +1,12 @@ +/foo-const.ts(1,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-const.ts (2 errors) ==== +==== /foo-const.ts (3 errors) ==== const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt index 3468d669f3056..1cb72fb0e9434 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/both-diagnostics.errors.txt @@ -1,13 +1,16 @@ /foo-interface-const.ts(1,11): warning test-syntactic-lint: Identifier 'foo' is forbidden. +/foo-interface-const.ts(2,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-interface-const.ts(2,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-interface-const.ts(2,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-interface-const.ts (3 errors) ==== +==== /foo-interface-const.ts (4 errors) ==== interface Foo {a; b;} ~~~ !!! warning test-syntactic-lint: Identifier 'foo' is forbidden. const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt index fedeb2199df77..7b4b32f665de6 100644 --- a/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multiLintLoads/semantic-diagnostics.errors.txt @@ -1,9 +1,12 @@ +/foo-const.ts(1,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-const.ts (2 errors) ==== +==== /foo-const.ts (3 errors) ==== const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt index 48d30107e5b3d..f2f78f412a2cb 100644 --- a/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/multipleRulesFoundInSingleExtension/test.errors.txt @@ -1,12 +1,14 @@ /foo-bar-const-interface.ts(1,11): warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. /foo-bar-const-interface.ts(2,11): warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. +/foo-bar-const-interface.ts(3,7): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. /foo-bar-const-interface.ts(3,10): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. /foo-bar-const-interface.ts(3,18): warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. +/foo-bar-const-interface.ts(4,5): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. /foo-bar-const-interface.ts(4,8): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. /foo-bar-const-interface.ts(4,16): warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. -==== /foo-bar-const-interface.ts (6 errors) ==== +==== /foo-bar-const-interface.ts (8 errors) ==== interface Foo {b;} ~~~ !!! warning test-multi-extension[IsNamedFoo]: Identifier 'foo' is forbidden. @@ -14,11 +16,15 @@ ~~~ !!! warning test-multi-extension[IsNamedBar]: Identifier 'bar' is forbidden. const f: "foo" = "foo"; + ~ +!!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueFoo]: String literal type 'foo' is forbidden. let b: "bar" = "bar"; + ~ +!!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ !!! warning test-multi-extension[IsValueBar]: String literal type 'bar' is forbidden. ~~~~~ diff --git a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt index fedeb2199df77..7b4b32f665de6 100644 --- a/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt +++ b/tests/baselines/reference/LanguageServiceHost/semanticLintLoads/w-diagnostics.errors.txt @@ -1,9 +1,12 @@ +/foo-const.ts(1,7): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,10): warning test-semantic-lint: String literal type 'foo' is forbidden. /foo-const.ts(1,18): warning test-semantic-lint: String literal type 'foo' is forbidden. -==== /foo-const.ts (2 errors) ==== +==== /foo-const.ts (3 errors) ==== const s: "foo" = "foo"; + ~ +!!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ !!! warning test-semantic-lint: String literal type 'foo' is forbidden. ~~~~~ diff --git a/tests/cases/extensions/available/test-multi-extension/index.ts b/tests/cases/extensions/available/test-multi-extension/index.ts index 488ff8d165e20..c5dcc727fac05 100644 --- a/tests/cases/extensions/available/test-multi-extension/index.ts +++ b/tests/cases/extensions/available/test-multi-extension/index.ts @@ -1,4 +1,5 @@ import {SyntacticLintWalker, SemanticLintWalker} from "extension-api"; +import {LiteralType} from "typescript"; export class IsNamedFoo extends SyntacticLintWalker { constructor(state) { super(state); } @@ -27,7 +28,7 @@ export class IsValueFoo extends SemanticLintWalker { visit(node, error) { const type = this.checker.getTypeAtLocation(node); if (type.flags & this.ts.TypeFlags.StringLiteral) { - if (node.text === "foo") { + if ((type as LiteralType).text === "foo") { error("String literal type 'foo' is forbidden.", node); } } @@ -39,7 +40,7 @@ export class IsValueBar extends SemanticLintWalker { visit(node, error) { const type = this.checker.getTypeAtLocation(node); if (type.flags & this.ts.TypeFlags.StringLiteral) { - if (node.text === "bar") { + if ((type as LiteralType).text === "bar") { error("String literal type 'bar' is forbidden.", node); } } diff --git a/tests/cases/extensions/available/test-semantic-lint/main.ts b/tests/cases/extensions/available/test-semantic-lint/main.ts index db730f9e57381..292a904827b4f 100644 --- a/tests/cases/extensions/available/test-semantic-lint/main.ts +++ b/tests/cases/extensions/available/test-semantic-lint/main.ts @@ -1,11 +1,12 @@ import {SemanticLintWalker} from "extension-api"; +import {LiteralType} from "typescript"; export default class IsValueFoo extends SemanticLintWalker { constructor(state) { super(state); } visit(node, error) { const type = this.checker.getTypeAtLocation(node); if (type.flags & this.ts.TypeFlags.StringLiteral) { - if (node.text === "foo") { + if ((type as LiteralType).text === "foo") { error("String literal type 'foo' is forbidden.", node); } } From e5c342a7c7ec91a3483b9c54642a2593df07872b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 1 Aug 2016 14:53:44 -0700 Subject: [PATCH 49/49] Make filters always run --- src/services/services.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 255aa69d77bb3..c245be0fedca0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3115,16 +3115,18 @@ namespace ts { function wrap(key: string): Function { if (extensionCount) { return (...args: any[]) => { + let result: any; for (let i = 0; i < extensionCount; i++) { const extension = instantiatedExtensions[i]; if ((extension as any)[key]) { const temp = (extension as any)[key](...args); if (temp !== undefined) { - return temp; + result = temp; + break; } } } - let result: any = (baseService as any)[key](...args); + result = result !== undefined ? result : (baseService as any)[key](...args); const filterKey = `${key}Filter`; for (let i = 0; i < extensionCount; i++) { const extension = instantiatedExtensions[i];