From 4b1b651424bb40eaa306b09799ef4972280a5e85 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 19 Nov 2019 14:39:16 -0800 Subject: [PATCH] Add tests for exceptions in user-code --- src/compiler/debug.ts | 211 ++++++++++++++++++ src/compiler/diagnosticMessages.json | 8 +- src/compiler/emitter.ts | 7 + src/compiler/plugin.ts | 111 ++++++++- src/compiler/program.ts | 36 +-- src/compiler/transformer.ts | 14 +- src/compiler/types.ts | 5 + src/compiler/utilities.ts | 5 + src/harness/compiler.ts | 39 +++- src/harness/harness.ts | 54 +---- .../reference/plugin.doesNotExist.errors.txt | 14 ++ .../plugin.throwsOnActivate.errors.txt | 39 ++++ .../reference/plugin.throwsOnActivate.js | 24 ++ .../reference/plugin.throwsOnLoad.errors.txt | 35 +++ .../reference/plugin.throwsOnLoad.js | 20 ++ .../plugin.throwsOnPreEmit.errors.txt | 37 +++ .../reference/plugin.throwsOnPreEmit.js | 22 ++ ...plugin.throwsOnPreEmitTransform.errors.txt | 42 ++++ .../plugin.throwsOnPreEmitTransform.js | 27 +++ .../plugin.throwsOnPreParse.errors.txt | 37 +++ .../reference/plugin.throwsOnPreParse.js | 22 ++ ...lugin.throwsOnPreParseTransform.errors.txt | 42 ++++ .../plugin.throwsOnPreParseTransform.js | 27 +++ .../plugins/plugin.doesNotExist.ts | 12 + .../plugins/plugin.throwsOnActivate.ts | 29 +++ .../plugins/plugin.throwsOnLoad.ts | 25 +++ .../plugins/plugin.throwsOnPreEmit.ts | 27 +++ .../plugin.throwsOnPreEmitTransform.ts | 32 +++ .../plugins/plugin.throwsOnPreParse.ts | 27 +++ .../plugin.throwsOnPreParseTransform.ts | 32 +++ 30 files changed, 980 insertions(+), 82 deletions(-) create mode 100644 tests/baselines/reference/plugin.doesNotExist.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnActivate.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnActivate.js create mode 100644 tests/baselines/reference/plugin.throwsOnLoad.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnLoad.js create mode 100644 tests/baselines/reference/plugin.throwsOnPreEmit.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnPreEmit.js create mode 100644 tests/baselines/reference/plugin.throwsOnPreEmitTransform.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnPreEmitTransform.js create mode 100644 tests/baselines/reference/plugin.throwsOnPreParse.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnPreParse.js create mode 100644 tests/baselines/reference/plugin.throwsOnPreParseTransform.errors.txt create mode 100644 tests/baselines/reference/plugin.throwsOnPreParseTransform.js create mode 100644 tests/cases/conformance/plugins/plugin.doesNotExist.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnActivate.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnLoad.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnPreEmit.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnPreEmitTransform.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnPreParse.ts create mode 100644 tests/cases/conformance/plugins/plugin.throwsOnPreParseTransform.ts diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index ee2b233b444..0c59d5023f7 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -371,5 +371,216 @@ namespace ts { const deprecation = createDeprecation(getFunctionName(func), options); return wrapFunction(deprecation, func); } + + export interface FilterStackOptions { + stackTraceLimit?: number; + exclude?: (frame: StackFrame) => boolean; + excludeNode?: boolean; + excludeTypeScript?: boolean; + excludeMocha?: boolean; + excludeBuiltin?: boolean; + rewriteFrame?: (frame: StackFrame) => StackFrame; + } + + export interface StackFrame { + typeName?: string; + functionName?: string; + methodName?: string; + fileName?: string; + lineNumber?: number; + columnNumber?: number; + evalOrigin?: StackFrame; + isConstructor?: boolean; + isAsync?: boolean; + } + + export function filterStack(stack: string, options: FilterStackOptions): string; + export function filterStack(error: Error, options: FilterStackOptions): Error; + export function filterStack(error: Error | string, { stackTraceLimit = Infinity, exclude, excludeBuiltin, excludeNode, excludeMocha, excludeTypeScript, rewriteFrame = filterStack.defaultRewriteFrame }: FilterStackOptions) { + const stack = typeof error === "string" ? error : error.stack; + if (stack) { + const lines = stack.split(/\r\n?|\n/g); + const filtered: string[] = []; + let frameCount = 0; + let lastFrameWasExcluded = false; + let excludedFrameCount = 0; + let lastExcludedFrame: string | undefined; + for (let line of lines) { + let frame = parseStackFrame(line); + if (frame) { + if (frame.fileName && frame.fileName !== "native" && frame.fileName !== "unknown location" && frame.fileName !== "") { + frame.fileName = frame.fileName.replace(/\bfile:\/\/\/(.*?)(?=(:\d+)*($|\)))/, (_, path) => ts.sys.resolvePath(path)); + if (rewriteFrame) { + frame = rewriteFrame(frame); + } + } + if (frameCount >= stackTraceLimit || + excludeNode && isNodeStackFrame(frame) || + excludeMocha && isMochaStackFrame(frame) || + excludeTypeScript && isTypeScriptStackFrame(frame) || + excludeBuiltin && isBuiltinStackFrame(frame) || + exclude && exclude(frame)) { + if (lastFrameWasExcluded) { + excludedFrameCount++; + lastExcludedFrame = formatStackFrame(frame); + continue; + } + lastFrameWasExcluded = true; + } + else { + if (excludedFrameCount > 0) { + filtered.push(` ... skipping ${excludedFrameCount} frame${excludedFrameCount > 1 ? "s" : ""} ...`); + excludedFrameCount = 0; + } + lastFrameWasExcluded = false; + } + frameCount++; + line = formatStackFrame(frame); + } + filtered.push(line); + } + if (excludedFrameCount > 0) { + excludedFrameCount--; + if (excludedFrameCount > 0) { + filtered.push(` ... skipping ${excludedFrameCount} frame${excludedFrameCount > 1 ? "s" : ""} ...`); + } + if (lastExcludedFrame) { + filtered.push(lastExcludedFrame); + } + } + + if (typeof error === "string") { + error = filtered.join("\n"); + } + else { + error.stack = filtered.join("\n"); + } + } + + return error; + } + + export namespace filterStack { + export let defaultRewriteFrame = (frame: StackFrame) => frame; + } + + const evalLocationRegExp = /^eval at (.*)$/; + const fileLocationRegExp = /^(native|unknown location||(?:(?:[a-zA-Z]|file|https?):)?[^:]+)(?::(\d+)(?::(\d+))?)?$/; + const positionRegExp = /^(async )?(new )?((?:[^.]+\.)+)?((?:(?! [\[(]).)*)(?: \[as ([^\]]+)\])? \((.*)\)$/; + + function parseStackFrameLocation(location: string): StackFrame | undefined { + // location format: + // fileName:lineNumber:columnNumber + // native + // unknown location + // + let match: RegExpExecArray | null; + if (match = evalLocationRegExp.exec(location)) { + const evalOrigin = parseStackFrame(match[1]); + return evalOrigin && { evalOrigin }; + } + if (match = fileLocationRegExp.exec(location)) { + const [, fileName, line, character] = match; + return { + fileName, + lineNumber: line !== undefined ? parseInt(line, 10) - 1 : undefined, + columnNumber: character !== undefined ? parseInt(character, 10) - 1 : undefined + }; + } + } + + function parseStackFrame(line: string): StackFrame | undefined { + // https://v8.dev/docs/stack-trace-api + // + // frame format: + // at {position} + // position format: + // {async |new }{thisType.}{functionName}{ [as methodName]} ({location}) + // {location} + let match = /^ at (.*)$/.exec(line); + if (!match) return undefined; + + const position = match[1]; + if (match = positionRegExp.exec(position)) { + const [, asyncModifier, newModifier, typeName, functionName, methodName, locationPart] = match; + const isAsync = !!asyncModifier; + const isConstructor = !!newModifier; + const location = parseStackFrameLocation(locationPart); + return { typeName: typeName && typeName.slice(0, -1), functionName, methodName, ...location, isConstructor, isAsync }; + } + + const location = parseStackFrameLocation(position); + if (location && (location.evalOrigin || location.fileName && isRootedDiskPath(location.fileName))) { + return location; + } + } + + function formatStackFrame(frame: StackFrame) { + let s = " at "; + if (frame.functionName) { + if (frame.isAsync) { + s += "async "; + } + else if (frame.isConstructor) { + s += "new "; + } + if (frame.typeName) { + s += `${frame.typeName}.`; + } + s += frame.functionName; + if (frame.methodName) { + s += ` [as ${frame.methodName}]`; + } + s += ` (${formatLocation(frame)})`; + } + else { + s += formatLocation(frame); + } + return s; + } + + function formatLocation(frame: StackFrame) { + if (frame.fileName) { + let s = frame.fileName; + if (frame.lineNumber !== undefined) { + s += `:${frame.lineNumber + 1}`; + if (frame.columnNumber !== undefined) { + s += `:${frame.columnNumber + 1}`; + } + } + return s; + } + else if (frame.evalOrigin) { + return `eval at ${formatStackFrame(frame.evalOrigin)}`; + } + else { + return "unknown location"; + } + } + + function isMochaStackFrame(frame: StackFrame) { + return !!frame.fileName && /[/](node_modules|components)[/]mocha(js)?[/]|[/]mocha\.js$/.test(normalizeSlashes(frame.fileName)); + } + + function isNodeStackFrame(frame: StackFrame) { + return !!frame.fileName && /(timers|events|node|module)\.js$/.test(frame.fileName); + } + + function isTypeScriptStackFrame(frame: StackFrame) { + if (frame.fileName) { + const file = normalizeSlashes(frame.fileName); + if (/([/]|^)(built[/]local|lib)[/](cancellationToken|tsc|tsserver(library)?|typescript(Services)?|typingsInstaller|watchGuard|run)\.js/.test(file)) { + return true; + } + if (/([/]|^)src[/](compat|compiler|harness|server|services|shims|testRunner|tsc|tsserver|tsserverlibrary|typescriptServices|typingsInstaller(Core)?|watchGuard)[/]/.test(file)) { + return true; + } + } + return false; + } + + function isBuiltinStackFrame(frame: StackFrame) { + return (frame.fileName === "native" || frame.fileName === "") && !!frame.functionName; + } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9c47c9df0b4..d9fca91a06d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3192,7 +3192,7 @@ "category": "Error", "code": 5078 }, - "Plugin '{0}' could not be loaded": { + "Plugin '{0}' could not be loaded: {1}": { "category": "Error", "code": 5079 }, @@ -3200,10 +3200,14 @@ "category": "Error", "code": 5080 }, - "Plugins are not supported in the current host environment.": { + "Plugin '{0}' failed while executing a transformer provided by the '{1}' hook: {2}": { "category": "Error", "code": 5081 }, + "Plugins are not supported in the current host environment.": { + "category": "Error", + "code": 5082 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 26e0d3bfe86..1926545afc8 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -313,6 +313,13 @@ namespace ts { } // Transform the source files const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false); + if (transform.diagnostics) { + emitterDiagnostics.addRange(transform.diagnostics); + } + + if (transform.compilerDiagnostics) { + emitterDiagnostics.addRange(transform.compilerDiagnostics); + } const printerOptions: PrinterOptions = { removeComments: compilerOptions.removeComments, diff --git a/src/compiler/plugin.ts b/src/compiler/plugin.ts index a9c4fec4729..9705c401b36 100644 --- a/src/compiler/plugin.ts +++ b/src/compiler/plugin.ts @@ -10,7 +10,7 @@ namespace ts { type HookReturnType = HookReturnTypes[K]; type HostHook = Exclude; type HostHookReturnType = Replace, void, CompilerPluginResult>; - type HostHookAggregate = (state: HostHookReturnType, userCodeResult: HookReturnType, args: ArgumentsHolder) => HostHookReturnType; + type HostHookAggregate = (state: HostHookReturnType, userCodeResult: HookReturnType, args: ArgumentsHolder, compilerPlugin: CompilerPlugin, hook: HostHook) => HostHookReturnType; interface ArgumentsHolder { arguments: HookParameters; @@ -37,7 +37,7 @@ namespace ts { /** * Resolves the supplied plugins (and their dependencies) relative to an initial directory. */ - export function getPlugins(host: ModuleLoaderHost, initialDir: string, plugins: ReadonlyArray) { + export function getPlugins(host: ModuleLoaderHost, initialDir: string, plugins: ReadonlyArray): GetPluginsResult { interface ResolvedModule { getModule(): RequireResult; moduleName: string; @@ -220,7 +220,10 @@ namespace ts { * Creates a `CompilerPluginHost` used to manage plugin lifetime. */ export function createPluginHost(compilerPlugins: ReadonlyArray, compilerHost: CompilerHost, compilerOptions: CompilerOptions): CompilerPluginHost { - interface Plugin { + /** + * Wrap a user-defined `TransformerFactory` so that we can catch errors during transformation and measure execution time. + */ + interface Plugin { state: "unloaded" | "inactive" | "active" | "active-failed" | "failed"; // Tracks whether the plugin has been activated. compilerPlugin: CompilerPlugin; context: CompilerPluginContext; @@ -237,11 +240,11 @@ namespace ts { return { deactivate, - preParse: (...args) => executeHostHook("preParse", args, (state, result, argsHolder) => { + preParse: (...args) => executeHostHook("preParse", args, (state, result, argsHolder, compilerPlugin) => { state.diagnostics = concatenate(state.diagnostics, result.diagnostics); state.rootNames = result.rootNames || state.rootNames; state.projectReferences = result.projectReferences || state.projectReferences; - state.preprocessors = concatenate(state.preprocessors, result.preprocessors); + state.preprocessors = concatenate(state.preprocessors, map(result.preprocessors, preprocessor => wrapTransformerFactory(preprocessor, compilerPlugin, "preParse"))); const previousArgs = argsHolder.arguments[0]; if (state.projectReferences !== previousArgs.projectReferences || state.rootNames !== previousArgs.rootNames) { @@ -252,9 +255,9 @@ namespace ts { } return state; }, {}), - preEmit: (...args) => executeHostHook("preEmit", args, (state, result) => { + preEmit: (...args) => executeHostHook("preEmit", args, (state, result, _, compilerPlugin) => { state.diagnostics = concatenate(state.diagnostics, result.diagnostics); - state.customTransformers = combineCustomTransformers(state.customTransformers, result.customTransformers); + state.customTransformers = combineCustomTransformers(state.customTransformers, result.customTransformers && wrapCustomTransformers(result.customTransformers, compilerPlugin, "preEmit")); return state; }, {}) }; @@ -402,20 +405,108 @@ namespace ts { state.diagnostics = concatenate(state.diagnostics, [userCodeResult.error]); } else if (userCodeResult.result) { - state = aggregate(state, userCodeResult.result, argsHolder); + state = aggregate(state, userCodeResult.result, argsHolder, plugin.compilerPlugin, hook); } } return state; } } + function formatPluginError(error: { message?: string, stack?: string }) { + return error.stack ? Debug.filterStack(error.stack, { excludeTypeScript: true, excludeMocha: true, excludeBuiltin: true, excludeNode: true }) : + error.message || error.toString(); + } + function createLoadDiagnostic(compilerPlugin: CompilerPlugin, error: { message?: string, stack?: string }) { debugger; - return createCompilerDiagnostic(Diagnostics.Plugin_0_could_not_be_loaded, compilerPlugin.name, error.stack || error.message || error.toString()); + return createCompilerDiagnostic(Diagnostics.Plugin_0_could_not_be_loaded_Colon_1, compilerPlugin.name, formatPluginError(error)); } function createUserCodeDiagnostic(compilerPlugin: CompilerPlugin, hook: Hook, error: { message?: string, stack?: string }) { debugger; - return createCompilerDiagnostic(Diagnostics.Plugin_0_failed_while_executing_the_1_hook_Colon_2, compilerPlugin.name, hook, error.stack || error.message || error.toString()); + return createCompilerDiagnostic(Diagnostics.Plugin_0_failed_while_executing_the_1_hook_Colon_2, compilerPlugin.name, hook, formatPluginError(error)); + } + + function createTransformerDiagnostic(compilerPlugin: CompilerPlugin, hook: Hook, error: { message?: string, stack?: string }) { + debugger; + return createCompilerDiagnostic(Diagnostics.Plugin_0_failed_while_executing_a_transformer_provided_by_the_1_hook_Colon_2, compilerPlugin.name, hook, formatPluginError(error)); + } + + /** + * Wrap a user-defined `CustomTransformers` so that we can catch errors during transformation and measure execution time. + */ + function wrapCustomTransformers(customTransformers: CustomTransformers, compilerPlugin: CompilerPlugin, hook: Hook): CustomTransformers { + const result: CustomTransformers = {}; + if (customTransformers.before) { + result.before = customTransformers.before.map(transformer => wrapTransformerFactory(transformer, compilerPlugin, hook)); + } + if (customTransformers.after) { + result.after = customTransformers.after.map(transformer => wrapTransformerFactory(transformer, compilerPlugin, hook)); + } + if (customTransformers.afterDeclarations) { + result.afterDeclarations = customTransformers.afterDeclarations.map(transformer => wrapTransformerFactory(transformer, compilerPlugin, hook)); + } + return result; + } + + /** + * Wrap a user-defined `TransformerFactory` so that we can catch errors during transformation and measure execution time. + */ + function wrapTransformerFactory(factory: TransformerFactory, compilerPlugin: CompilerPlugin, hook: Hook): TransformerFactory; + function wrapTransformerFactory(factory: TransformerFactory | CustomTransformerFactory, compilerPlugin: CompilerPlugin, hook: Hook): TransformerFactory | CustomTransformerFactory; + function wrapTransformerFactory(factory: TransformerFactory | CustomTransformerFactory, compilerPlugin: CompilerPlugin, hook: Hook) { + return (context: TransformationContext): Transformer | CustomTransformer => { + try { + const transformer = factory(context); + return typeof transformer === "function" + ? wrapTransformer(transformer, context, compilerPlugin, hook) + : wrapCustomTransformer(transformer, context, compilerPlugin, hook); + } + catch (e) { + context.addCompilerDiagnostic(createTransformerDiagnostic(compilerPlugin, hook, e)); + return identity; + } + }; + } + + /** + * Wrap a user-defined `Transformer` so that we can catch errors during transformation and measure execution time. + */ + function wrapTransformer(transformer: Transformer, context: TransformationContext, compilerPlugin: CompilerPlugin, hook: Hook): Transformer { + return node => { + try { + return transformer(node); + } + catch (e) { + context.addCompilerDiagnostic(createTransformerDiagnostic(compilerPlugin, hook, e)); + return node; + } + }; + } + + /** + * Wrap a user-defined `CustomTransformer` so that we can catch errors during transformation and measure execution time. + */ + function wrapCustomTransformer(customTransformer: CustomTransformer, context: TransformationContext, compilerPlugin: CompilerPlugin, hook: Hook): CustomTransformer { + return { + transformBundle(node) { + try { + return customTransformer.transformBundle(node); + } + catch (e) { + context.addCompilerDiagnostic(createTransformerDiagnostic(compilerPlugin, hook, e)); + return node; + } + }, + transformSourceFile(node) { + try { + return customTransformer.transformSourceFile(node); + } + catch (e) { + context.addCompilerDiagnostic(createTransformerDiagnostic(compilerPlugin, hook, e)); + return node; + } + } + }; } } \ No newline at end of file diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ecb52feb1f3..ead4ec12097 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -323,9 +323,13 @@ namespace ts { const diagnostics = [ ...program.getConfigFileParsingDiagnostics(), ...program.getOptionsDiagnostics(cancellationToken), + ...getPluginPreParseDiagnostics(program, cancellationToken), + ...getPluginPreprocessDiagnostics(program, sourceFile, cancellationToken), ...program.getSyntacticDiagnostics(sourceFile, cancellationToken), ...program.getGlobalDiagnostics(cancellationToken), - ...program.getSemanticDiagnostics(sourceFile, cancellationToken) + ...getPluginPreEmitGlobalDiagnostics(program, cancellationToken), + ...program.getSemanticDiagnostics(sourceFile, cancellationToken), + ...getPluginPreEmitDiagnostics(program, sourceFile, cancellationToken) ]; if (getEmitDeclarations(program.getCompilerOptions())) { @@ -727,19 +731,19 @@ namespace ts { return result; } - function getPluginPreParseDiagnostics(program: BaseProgram, cancellationToken?: CancellationToken) { + function getPluginPreParseDiagnostics(program: BaseProgram | BuilderProgram, cancellationToken?: CancellationToken) { return isAsyncProgram(program) ? program.getPluginPreParseDiagnostics(cancellationToken) : emptyArray; } - function getPluginPreprocessDiagnostics(program: BaseProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken) { + function getPluginPreprocessDiagnostics(program: BaseProgram | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken) { return isAsyncProgram(program) ? program.getPluginPreprocessDiagnostics(sourceFile, cancellationToken) : emptyArray; } - function getPluginPreEmitGlobalDiagnostics(program: BaseProgram, cancellationToken?: CancellationToken) { + function getPluginPreEmitGlobalDiagnostics(program: BaseProgram | BuilderProgram, cancellationToken?: CancellationToken) { return isAsyncProgram(program) ? program.getPluginPreEmitGlobalDiagnostics(cancellationToken) : emptyArray; } - function getPluginPreEmitDiagnostics(program: BaseProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken) { + function getPluginPreEmitDiagnostics(program: BaseProgram | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken) { return isAsyncProgram(program) ? program.getPluginPreEmitDiagnostics(sourceFile, cancellationToken) : emptyArray; } @@ -1620,11 +1624,6 @@ namespace ts { // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we // get any preEmit diagnostics, not just the ones if (options.noEmitOnError) { - if (isAsyncProgram(program)) { - program.getPluginPreParseDiagnostics(cancellationToken); - program.getPluginPreprocessDiagnostics(sourceFile, cancellationToken); - program.getPluginPreEmitDiagnostics(sourceFile, cancellationToken); - } const diagnostics = [ ...program.getOptionsDiagnostics(cancellationToken), ...getPluginPreParseDiagnostics(program, cancellationToken), @@ -3421,6 +3420,7 @@ namespace ts { }); let preprocessDiagnostics: DiagnosticWithLocation[] | undefined; + let preprocessCompilerDiagnostics: Diagnostic[] | undefined; let preprocessTransformer: NodeTransformer | undefined; let preprocessedNodes: Node[] | undefined; if (preParseResult) { @@ -3441,6 +3441,7 @@ namespace ts { /*allowDtsFiles*/ true ); preprocessDiagnostics = preprocessTransformer.diagnostics; + preprocessCompilerDiagnostics = preprocessTransformer.compilerDiagnostics; preprocessedNodes = []; changeCompilerHostToUsePreprocessor(host, node => { disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node))); @@ -3453,9 +3454,11 @@ namespace ts { const { baseProgram, emitWorker, dropTypeCheckers } = createBaseProgram(createProgramOptions, host); if (preprocessDiagnostics) { - for (const diagnostic of preprocessDiagnostics) { - pluginPreprocessDiagnostics!.add(diagnostic); - } + pluginPreprocessDiagnostics!.addRange(preprocessDiagnostics); + } + + if (preprocessCompilerDiagnostics) { + pluginPreprocessDiagnostics!.addRange(preprocessCompilerDiagnostics); } const program = baseProgram as AsyncProgram; @@ -3485,7 +3488,10 @@ namespace ts { function getPluginPreprocessDiagnostics(sourceFile?: SourceFile) { if (!pluginHost) return emptyArray; - return getDiagnosticsHelper(program, sourceFile, getPluginPreprocessDiagnosticsForFile); + return concatenate( + pluginPreprocessDiagnostics!.getGlobalDiagnostics(), + getDiagnosticsHelper(program, sourceFile, getPluginPreprocessDiagnosticsForFile) + ); } function getPluginPreprocessDiagnosticsForFile(sourceFile: SourceFile) { @@ -3546,7 +3552,7 @@ namespace ts { } } - export function isAsyncProgram(baseProgram: BaseProgram | Program | AsyncProgram): baseProgram is AsyncProgram { + export function isAsyncProgram(baseProgram: BaseProgram | Program | AsyncProgram | BuilderProgram): baseProgram is AsyncProgram { return typeof (baseProgram as AsyncProgram).emitAsync === "function"; } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 3c2da4b5fb4..e7585e11315 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -132,6 +132,7 @@ namespace ts { export interface NodeTransformer { diagnostics: DiagnosticWithLocation[]; + /*@internal*/ compilerDiagnostics: Diagnostic[]; transformNodes(nodes: ReadonlyArray): T[]; transformNode(node: T): T; markComplete(): void; @@ -182,6 +183,7 @@ namespace ts { let onEmitNode: TransformationContext["onEmitNode"] = noEmitNotification; let state = TransformationState.Uninitialized; const diagnostics: DiagnosticWithLocation[] = []; + const compilerDiagnostics: Diagnostic[] = []; // The transformation context is provided to each transformer as part of transformer // initialization. @@ -216,9 +218,10 @@ namespace ts { onEmitNode = value; }, addDiagnostic(diag) { - if (diagnostics) { - diagnostics.push(diag); - } + diagnostics.push(diag); + }, + addCompilerDiagnostic(diag) { + compilerDiagnostics.push(diag); } }; @@ -236,6 +239,7 @@ namespace ts { return { diagnostics, + compilerDiagnostics, transformNode, transformNodes, markComplete: () => { state = TransformationState.Completed; }, @@ -510,7 +514,8 @@ namespace ts { substituteNode: tx.substituteNode, emitNodeWithNotification: tx.emitNodeWithNotification, dispose, - diagnostics: tx.diagnostics + diagnostics: tx.diagnostics, + compilerDiagnostics: tx.compilerDiagnostics, }; function dispose() { @@ -548,5 +553,6 @@ namespace ts { startLexicalEnvironment: noop, suspendLexicalEnvironment: noop, addDiagnostic: noop, + addCompilerDiagnostic: noop }; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e82233422b1..68b45a75ec5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6645,6 +6645,7 @@ namespace ts { onEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; /* @internal */ addDiagnostic(diag: DiagnosticWithLocation): void; + /* @internal */ addCompilerDiagnostic(diag: Diagnostic): void; } export interface TransformationResult { @@ -6654,6 +6655,9 @@ namespace ts { /** Gets diagnostics for the transformation. */ diagnostics?: DiagnosticWithLocation[]; + /*@internal*/ + compilerDiagnostics?: Diagnostic[]; + /** * Gets a substitute for a node, if one is available; otherwise, returns the original node. * @@ -7038,6 +7042,7 @@ namespace ts { export interface DiagnosticCollection { // Adds a diagnostic to this diagnostic collection. add(diagnostic: Diagnostic): void; + addRange(diagnostics: Diagnostic[]): void; // Returns the first existing diagnostic that is equivalent to the given one (sans related information) lookup(diagnostic: Diagnostic): Diagnostic | undefined; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3169d3f50ef..7ca3c16c059 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3100,6 +3100,7 @@ namespace ts { return { add, + addRange, lookup, getGlobalDiagnostics, getDiagnostics, @@ -3151,6 +3152,10 @@ namespace ts { insertSorted(diagnostics, diagnostic, compareDiagnostics); } + function addRange(diagnostics: Diagnostic[]) { + forEach(diagnostics, add); + } + function getGlobalDiagnostics(): Diagnostic[] { hasReadNonFileDiagnostics = true; return nonFileDiagnostics; diff --git a/src/harness/compiler.ts b/src/harness/compiler.ts index a621411fe15..1377ea79668 100644 --- a/src/harness/compiler.ts +++ b/src/harness/compiler.ts @@ -269,14 +269,35 @@ namespace compiler { if (compilerOptions.skipDefaultLibCheck === undefined) compilerOptions.skipDefaultLibCheck = true; if (compilerOptions.noErrorTruncation === undefined) compilerOptions.noErrorTruncation = true; - const program = await ts.createAsyncProgram({ - rootNames: project.fileNames || [], - options: compilerOptions, - host, - plugins - }); - const emitResult = await program.emitAsync(); - const errors = ts.getPreEmitDiagnostics(program); - return new CompilationResult(host, compilerOptions, program, emitResult, errors); + const defaultRewriteFrame = ts.Debug.filterStack.defaultRewriteFrame; + ts.Debug.filterStack.defaultRewriteFrame = frame => { + if (frame.fileName) { + frame.fileName = ts.normalizeSlashes(frame.fileName); + const file = frame.fileName + .replace(/^.*[/](src[/](?:compat|compiler|harness|server|services|shims|testRunner|tsc|tsserver(?:library)?|typescriptServices|typingsInstaller(?:Core)?|watchGuard)[/])/, "$1") + .replace(/^.*[/]((?:built[/]local|lib)[/])(?=(?:cancellationToken|tsc|tsserver(library)?|typescript(Services)?|typingsInstaller|watchGuard|run)\.js)/, "$1"); + if (file !== frame.fileName) { + // set positions to 0 so that we don't have to accept diff changes due to unrelated additions/subtractions to related files. + frame.fileName = file; + frame.lineNumber = 0; + frame.columnNumber = 0; + } + } + return frame; + }; + try { + const program = await ts.createAsyncProgram({ + rootNames: project.fileNames || [], + options: compilerOptions, + host, + plugins + }); + const emitResult = await program.emitAsync(); + const errors = ts.sortAndDeduplicateDiagnostics(ts.concatenate(ts.getPreEmitDiagnostics(program), emitResult.diagnostics)); + return new CompilationResult(host, compilerOptions, program, emitResult, errors); + } + finally { + ts.Debug.filterStack.defaultRewriteFrame = defaultRewriteFrame; + } } } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index db8760d376e..ac43a25e781 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -386,51 +386,21 @@ namespace Utils { const maxHarnessFrames = 1; export function filterStack(error: Error, stackTraceLimit = Infinity) { - const stack = (error).stack; - if (stack) { - const lines = stack.split(/\r\n?|\n/g); - const filtered: string[] = []; - let frameCount = 0; - let harnessFrameCount = 0; - for (let line of lines) { - if (isStackFrame(line)) { - if (frameCount >= stackTraceLimit - || isMocha(line) - || isNode(line)) { - continue; + let harnessFrameCount = 0; + return ts.Debug.filterStack(error, { + stackTraceLimit, + excludeNode: true, + excludeMocha: true, + exclude: frame => { + if (frame.fileName && isHarness(frame.fileName)) { + if (harnessFrameCount >= maxHarnessFrames) { + return true; } - - if (isHarness(line)) { - if (harnessFrameCount >= maxHarnessFrames) { - continue; - } - - harnessFrameCount++; - } - - line = line.replace(/\bfile:\/\/\/(.*?)(?=(:\d+)*($|\)))/, (_, path) => ts.sys.resolvePath(path)); - frameCount++; + harnessFrameCount++; } - - filtered.push(line); + return false; } - - (error).stack = filtered.join(Harness.IO.newLine()); - } - - return error; - } - - function isStackFrame(line: string) { - return /^\s+at\s/.test(line); - } - - function isMocha(line: string) { - return /[\\/](node_modules|components)[\\/]mocha(js)?[\\/]|[\\/]mocha\.js/.test(line); - } - - function isNode(line: string) { - return /\((timers|events|node|module)\.js:/.test(line); + }); } function isHarness(line: string) { diff --git a/tests/baselines/reference/plugin.doesNotExist.errors.txt b/tests/baselines/reference/plugin.doesNotExist.errors.txt new file mode 100644 index 00000000000..4c48c9deda4 --- /dev/null +++ b/tests/baselines/reference/plugin.doesNotExist.errors.txt @@ -0,0 +1,14 @@ +error TS5077: Plugin 'does-not-exist' could not be found: Could not resolve JS module 'typescript-plugin-does-not-exist' starting at 'tests/cases/conformance/plugins'. Looked in: tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist.js, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist.js, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/cases/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/node_modules/typescript-plugin-does-not-exist.js, tests/cases/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/node_modules/typescript-plugin-does-not-exist/package.json, tests/node_modules/typescript-plugin-does-not-exist.js, tests/node_modules/typescript-plugin-does-not-exist.jsx, tests/node_modules/typescript-plugin-does-not-exist/index.js, tests/node_modules/typescript-plugin-does-not-exist/index.jsx, node_modules/typescript-plugin-does-not-exist/package.json, node_modules/typescript-plugin-does-not-exist.js, node_modules/typescript-plugin-does-not-exist.jsx, node_modules/typescript-plugin-does-not-exist/index.js, node_modules/typescript-plugin-does-not-exist/index.jsx. + + +!!! error TS5077: Plugin 'does-not-exist' could not be found: Could not resolve JS module 'typescript-plugin-does-not-exist' starting at 'tests/cases/conformance/plugins'. Looked in: tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist.js, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/conformance/plugins/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist.js, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/conformance/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/cases/node_modules/typescript-plugin-does-not-exist/package.json, tests/cases/node_modules/typescript-plugin-does-not-exist.js, tests/cases/node_modules/typescript-plugin-does-not-exist.jsx, tests/cases/node_modules/typescript-plugin-does-not-exist/index.js, tests/cases/node_modules/typescript-plugin-does-not-exist/index.jsx, tests/node_modules/typescript-plugin-does-not-exist/package.json, tests/node_modules/typescript-plugin-does-not-exist.js, tests/node_modules/typescript-plugin-does-not-exist.jsx, tests/node_modules/typescript-plugin-does-not-exist/index.js, tests/node_modules/typescript-plugin-does-not-exist/index.jsx, node_modules/typescript-plugin-does-not-exist/package.json, node_modules/typescript-plugin-does-not-exist.js, node_modules/typescript-plugin-does-not-exist.jsx, node_modules/typescript-plugin-does-not-exist/index.js, node_modules/typescript-plugin-does-not-exist/index.jsx. +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "does-not-exist" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnActivate.errors.txt b/tests/baselines/reference/plugin.throwsOnActivate.errors.txt new file mode 100644 index 00000000000..bb6ff0459f8 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnActivate.errors.txt @@ -0,0 +1,39 @@ +error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'activate' hook: Error: Not yet implemented. + at Object.exports.activate (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) + at src/compiler/plugin.ts:1:1 + ... skipping 63 frames ... + at processImmediate (timers.js:658:5) + + +!!! error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'activate' hook: Error: Not yet implemented. +!!! error TS5080: at Object.exports.activate (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) +!!! error TS5080: at src/compiler/plugin.ts:1:1 +!!! error TS5080: ... skipping 63 frames ... +!!! error TS5080: at processImmediate (timers.js:658:5) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + exports.activate = function () { + throw new Error("Not yet implemented."); + }; + exports.preParse = function() { + }; + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnActivate.js b/tests/baselines/reference/plugin.throwsOnActivate.js new file mode 100644 index 00000000000..aeea7a9eeb8 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnActivate.js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnActivate.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +//// [index.js] +exports.activate = function () { + throw new Error("Not yet implemented."); +}; +exports.preParse = function() { +}; + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/baselines/reference/plugin.throwsOnLoad.errors.txt b/tests/baselines/reference/plugin.throwsOnLoad.errors.txt new file mode 100644 index 00000000000..f1e8a6efb12 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnLoad.errors.txt @@ -0,0 +1,35 @@ +error TS5079: Plugin 'typescript-plugin-transform' could not be loaded: Error: Not yet implemented. + at tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:1:6 + at ModuleLoader.require (src/harness/fakes.ts:1:1) + ... skipping 37 frames ... + at fulfilled (built/local/run.js:1:1) + + +!!! error TS5079: Plugin 'typescript-plugin-transform' could not be loaded: Error: Not yet implemented. +!!! error TS5079: at tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:1:6 +!!! error TS5079: at ModuleLoader.require (src/harness/fakes.ts:1:1) +!!! error TS5079: ... skipping 37 frames ... +!!! error TS5079: at fulfilled (built/local/run.js:1:1) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + throw new Error("Not yet implemented."); + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnLoad.js b/tests/baselines/reference/plugin.throwsOnLoad.js new file mode 100644 index 00000000000..b30dd0d186f --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnLoad.js @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnLoad.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +//// [index.js] +throw new Error("Not yet implemented."); + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/baselines/reference/plugin.throwsOnPreEmit.errors.txt b/tests/baselines/reference/plugin.throwsOnPreEmit.errors.txt new file mode 100644 index 00000000000..2abfbda6402 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreEmit.errors.txt @@ -0,0 +1,37 @@ +error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'preEmit' hook: Error: Not yet implemented. + at Object.exports.preEmit (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) + at src/compiler/plugin.ts:1:1 + ... skipping 9 frames ... + at fulfilled (built/local/run.js:1:1) + + +!!! error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'preEmit' hook: Error: Not yet implemented. +!!! error TS5080: at Object.exports.preEmit (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) +!!! error TS5080: at src/compiler/plugin.ts:1:1 +!!! error TS5080: ... skipping 9 frames ... +!!! error TS5080: at fulfilled (built/local/run.js:1:1) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + exports.preEmit = function () { + throw new Error("Not yet implemented."); + }; + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnPreEmit.js b/tests/baselines/reference/plugin.throwsOnPreEmit.js new file mode 100644 index 00000000000..4ff5dae32d1 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreEmit.js @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnPreEmit.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +//// [index.js] +exports.preEmit = function () { + throw new Error("Not yet implemented."); +}; + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/baselines/reference/plugin.throwsOnPreEmitTransform.errors.txt b/tests/baselines/reference/plugin.throwsOnPreEmitTransform.errors.txt new file mode 100644 index 00000000000..2651b9a0682 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreEmitTransform.errors.txt @@ -0,0 +1,42 @@ +error TS5081: Plugin 'typescript-plugin-transform' failed while executing a transformer provided by the 'preEmit' hook: Error: Not yet implemented. + at transform (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:6:15) + at src/compiler/plugin.ts:1:1 + ... skipping 13 frames ... + at fulfilled (built/local/run.js:1:1) + + +!!! error TS5081: Plugin 'typescript-plugin-transform' failed while executing a transformer provided by the 'preEmit' hook: Error: Not yet implemented. +!!! error TS5081: at transform (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:6:15) +!!! error TS5081: at src/compiler/plugin.ts:1:1 +!!! error TS5081: ... skipping 13 frames ... +!!! error TS5081: at fulfilled (built/local/run.js:1:1) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + exports.preEmit = function() { + return { + customTransformers: { after: [transform] } + }; + function transform() { + throw new Error("Not yet implemented."); + } + }; + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnPreEmitTransform.js b/tests/baselines/reference/plugin.throwsOnPreEmitTransform.js new file mode 100644 index 00000000000..06bbf92b59e --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreEmitTransform.js @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnPreEmitTransform.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +//// [index.js] +exports.preEmit = function() { + return { + customTransformers: { after: [transform] } + }; + function transform() { + throw new Error("Not yet implemented."); + } +}; + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/baselines/reference/plugin.throwsOnPreParse.errors.txt b/tests/baselines/reference/plugin.throwsOnPreParse.errors.txt new file mode 100644 index 00000000000..75f059d80d8 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreParse.errors.txt @@ -0,0 +1,37 @@ +error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'preParse' hook: Error: Not yet implemented. + at Object.exports.preParse (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) + at src/compiler/plugin.ts:1:1 + ... skipping 9 frames ... + at fulfilled (built/local/run.js:1:1) + + +!!! error TS5080: Plugin 'typescript-plugin-transform' failed while executing the 'preParse' hook: Error: Not yet implemented. +!!! error TS5080: at Object.exports.preParse (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:2:11) +!!! error TS5080: at src/compiler/plugin.ts:1:1 +!!! error TS5080: ... skipping 9 frames ... +!!! error TS5080: at fulfilled (built/local/run.js:1:1) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + exports.preParse = function() { + throw new Error("Not yet implemented."); + }; + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnPreParse.js b/tests/baselines/reference/plugin.throwsOnPreParse.js new file mode 100644 index 00000000000..0ebba38f470 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreParse.js @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnPreParse.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +//// [index.js] +exports.preParse = function() { + throw new Error("Not yet implemented."); +}; + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/baselines/reference/plugin.throwsOnPreParseTransform.errors.txt b/tests/baselines/reference/plugin.throwsOnPreParseTransform.errors.txt new file mode 100644 index 00000000000..cc7543755b0 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreParseTransform.errors.txt @@ -0,0 +1,42 @@ +error TS5081: Plugin 'typescript-plugin-transform' failed while executing a transformer provided by the 'preParse' hook: Error: Not yet implemented. + at preprocess (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:6:15) + at src/compiler/plugin.ts:1:1 + ... skipping 6 frames ... + at fulfilled (built/local/run.js:1:1) + + +!!! error TS5081: Plugin 'typescript-plugin-transform' failed while executing a transformer provided by the 'preParse' hook: Error: Not yet implemented. +!!! error TS5081: at preprocess (tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js:6:15) +!!! error TS5081: at src/compiler/plugin.ts:1:1 +!!! error TS5081: ... skipping 6 frames ... +!!! error TS5081: at fulfilled (built/local/run.js:1:1) +==== tests/cases/conformance/plugins/tsconfig.json (0 errors) ==== + { + "compilerOptions": {}, + "plugins": [ + "transform" + ] + } + +==== tests/cases/conformance/plugins/main.ts (0 errors) ==== + const a = undefined; +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/package.json (0 errors) ==== + { + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } + } + +==== tests/cases/conformance/plugins/node_modules/typescript-plugin-transform/index.js (0 errors) ==== + exports.preParse = function() { + return { + preprocessors: [preprocess] + }; + function preprocess() { + throw new Error("Not yet implemented."); + } + }; + \ No newline at end of file diff --git a/tests/baselines/reference/plugin.throwsOnPreParseTransform.js b/tests/baselines/reference/plugin.throwsOnPreParseTransform.js new file mode 100644 index 00000000000..8c44e88e586 --- /dev/null +++ b/tests/baselines/reference/plugin.throwsOnPreParseTransform.js @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/plugins/plugin.throwsOnPreParseTransform.ts] //// + +//// [package.json] +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +//// [index.js] +exports.preParse = function() { + return { + preprocessors: [preprocess] + }; + function preprocess() { + throw new Error("Not yet implemented."); + } +}; + +//// [main.ts] +const a = undefined; + +//// [main.js] +var a = undefined; diff --git a/tests/cases/conformance/plugins/plugin.doesNotExist.ts b/tests/cases/conformance/plugins/plugin.doesNotExist.ts new file mode 100644 index 00000000000..5794f252d36 --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.doesNotExist.ts @@ -0,0 +1,12 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "does-not-exist" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnActivate.ts b/tests/cases/conformance/plugins/plugin.throwsOnActivate.ts new file mode 100644 index 00000000000..3e1f6e9c28e --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnActivate.ts @@ -0,0 +1,29 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +exports.activate = function () { + throw new Error("Not yet implemented."); +}; +exports.preParse = function() { +}; + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnLoad.ts b/tests/cases/conformance/plugins/plugin.throwsOnLoad.ts new file mode 100644 index 00000000000..6ff23387316 --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnLoad.ts @@ -0,0 +1,25 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +throw new Error("Not yet implemented."); + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnPreEmit.ts b/tests/cases/conformance/plugins/plugin.throwsOnPreEmit.ts new file mode 100644 index 00000000000..b0805038c93 --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnPreEmit.ts @@ -0,0 +1,27 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +exports.preEmit = function () { + throw new Error("Not yet implemented."); +}; + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnPreEmitTransform.ts b/tests/cases/conformance/plugins/plugin.throwsOnPreEmitTransform.ts new file mode 100644 index 00000000000..52514512ff9 --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnPreEmitTransform.ts @@ -0,0 +1,32 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preEmit"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +exports.preEmit = function() { + return { + customTransformers: { after: [transform] } + }; + function transform() { + throw new Error("Not yet implemented."); + } +}; + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnPreParse.ts b/tests/cases/conformance/plugins/plugin.throwsOnPreParse.ts new file mode 100644 index 00000000000..396548cd3cd --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnPreParse.ts @@ -0,0 +1,27 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +exports.preParse = function() { + throw new Error("Not yet implemented."); +}; + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file diff --git a/tests/cases/conformance/plugins/plugin.throwsOnPreParseTransform.ts b/tests/cases/conformance/plugins/plugin.throwsOnPreParseTransform.ts new file mode 100644 index 00000000000..7651ea26683 --- /dev/null +++ b/tests/cases/conformance/plugins/plugin.throwsOnPreParseTransform.ts @@ -0,0 +1,32 @@ +// @noImplicitReferences: true +// @noTypesAndSymbols: true +// @filename: node_modules/typescript-plugin-transform/package.json +{ + "name": "typescript-plugin-transform", + "version": "1.0.0", + "main": "index.js", + "typescriptPlugin": { + "activationEvents": ["preParse"] + } +} + +// @filename: node_modules/typescript-plugin-transform/index.js +exports.preParse = function() { + return { + preprocessors: [preprocess] + }; + function preprocess() { + throw new Error("Not yet implemented."); + } +}; + +// @filename: tsconfig.json +{ + "compilerOptions": {}, + "plugins": [ + "transform" + ] +} + +// @filename: main.ts +const a = undefined; \ No newline at end of file