diff --git a/CHANGELOG.md b/CHANGELOG.md index 6936a691c..ef3c2229d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,35 @@ This change simplifies our codebase and opens a path to object accessors implementation +- Errors reported during transpilation now are created as TypeScript diagnostics, instead of being thrown as JavaScript errors. This makes TypeScriptToLua always try to generate valid code (even in presence of errors) and allows multiple errors to be reported in a single file: + + + ```ts + for (var x in []) {} + ``` + + ```shell + # Before + + $ tstl file.ts + file.ts:1:1 - error TSTL: Iterating over arrays with 'for ... in' is not allowed. + + $ cat file.lua + error("Iterating over arrays with 'for ... in' is not allowed.") + ``` + + ```shell + # Now + + $ tstl file.ts + file.ts:1:1 - error TSTL: Iterating over arrays with 'for ... in' is not allowed. + file.ts:1:6 - error TSTL: `var` declarations are not supported. Use `let` or `const` instead. + + $ cat file.lua + for x in pairs({}) do + end + ``` + ## 0.31.0 - **Breaking:** The old annotation syntax (`/* !varArg */`) **no longer works**, the only currently supported syntax is: diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 788f15d76..48c8abe82 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -1,4 +1,5 @@ import * as ts from "typescript"; +import * as diagnosticFactories from "./transpilation/diagnostics"; type KnownKeys = { [K in keyof T]: string extends K ? never : number extends K ? never : K } extends { [_ in keyof T]: infer U; @@ -47,37 +48,12 @@ export function validateOptions(options: CompilerOptions): ts.Diagnostic[] { const diagnostics: ts.Diagnostic[] = []; if (options.luaBundle && !options.luaBundleEntry) { - diagnostics.push(configErrorDiagnostic(`'luaBundleEntry' is required when 'luaBundle' is enabled.`)); + diagnostics.push(diagnosticFactories.luaBundleEntryIsRequired()); } if (options.luaBundle && options.luaLibImport === LuaLibImportKind.Inline) { - diagnostics.push( - configWarningDiagnostic( - `Using 'luaBundle' with 'luaLibImport: "inline"' might generate duplicate code. ` + - `It is recommended to use 'luaLibImport: "require"'` - ) - ); + diagnostics.push(diagnosticFactories.usingLuaBundleWithInlineMightGenerateDuplicateCode()); } return diagnostics; } - -const configErrorDiagnostic = (message: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: message, -}); - -const configWarningDiagnostic = (message: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Warning, - code: 0, - source: "typescript-to-lua", - messageText: message, -}); diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index d37179765..816bb1aea 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -4,7 +4,7 @@ import * as ts from "typescript"; import { CompilerOptions, LuaLibImportKind } from "./CompilerOptions"; import * as lua from "./LuaAST"; import { loadLuaLibFeatures, LuaLibFeature } from "./LuaLib"; -import { isValidLuaIdentifier, luaKeywords } from "./transformation/utils/safe-names"; +import { isValidLuaIdentifier } from "./transformation/utils/safe-names"; import { EmitHost } from "./transpilation"; import { trimExtension } from "./utils"; @@ -660,11 +660,7 @@ export class LuaPrinter { const value = this.printExpression(expression.value); if (expression.key) { - if ( - lua.isStringLiteral(expression.key) && - isValidLuaIdentifier(expression.key.value) && - !luaKeywords.has(expression.key.value) - ) { + if (lua.isStringLiteral(expression.key) && isValidLuaIdentifier(expression.key.value)) { chunks.push(expression.key.value, " = ", value); } else { chunks.push("[", this.printExpression(expression.key), "] = ", value); @@ -761,11 +757,7 @@ export class LuaPrinter { const chunks: SourceChunk[] = []; chunks.push(this.printExpressionInParenthesesIfNeeded(expression.table)); - if ( - lua.isStringLiteral(expression.index) && - isValidLuaIdentifier(expression.index.value) && - !luaKeywords.has(expression.index.value) - ) { + if (lua.isStringLiteral(expression.index) && isValidLuaIdentifier(expression.index.value)) { chunks.push(".", this.createSourceNode(expression.index, expression.index.value)); } else { chunks.push("[", this.printExpression(expression.index), "]"); diff --git a/src/cli/diagnostics.ts b/src/cli/diagnostics.ts index 9e950710f..e386fa391 100644 --- a/src/cli/diagnostics.ts +++ b/src/cli/diagnostics.ts @@ -1,16 +1,12 @@ import * as ts from "typescript"; +import { createSerialDiagnosticFactory, createDiagnosticFactoryWithCode } from "../utils"; -export const tstlOptionsAreMovingToTheTstlObject = (tstl: Record): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, +export const tstlOptionsAreMovingToTheTstlObject = createSerialDiagnosticFactory((tstl: Record) => ({ category: ts.DiagnosticCategory.Warning, - code: 0, - source: "typescript-to-lua", messageText: 'TSTL options are moving to the "tstl" object. Adjust your tsconfig to look like\n' + `"tstl": ${JSON.stringify(tstl, undefined, 4)}`, -}); +})); export const watchErrorSummary = (errorCount: number): ts.Diagnostic => ({ file: undefined, @@ -24,16 +20,8 @@ export const watchErrorSummary = (errorCount: number): ts.Diagnostic => ({ : `Found ${errorCount} errors. Watching for file changes.`, }); -const createCommandLineError = (code: number, getMessage: (...args: Args) => string) => ( - ...args: Args -): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code, - messageText: getMessage(...args), -}); +const createCommandLineError = (code: number, getMessage: (...args: TArgs) => string) => + createDiagnosticFactoryWithCode(code, (...args: TArgs) => ({ messageText: getMessage(...args) })); export const unknownCompilerOption = createCommandLineError( 5023, diff --git a/src/cli/report.ts b/src/cli/report.ts index 039ca069c..19fd02d1e 100644 --- a/src/cli/report.ts +++ b/src/cli/report.ts @@ -1,12 +1,9 @@ import * as ts from "typescript"; +export const prepareDiagnosticForFormatting = (diagnostic: ts.Diagnostic) => + diagnostic.source === "typescript-to-lua" ? { ...diagnostic, code: "TL" as any } : diagnostic; + export function createDiagnosticReporter(pretty: boolean, system = ts.sys): ts.DiagnosticReporter { const reporter = ts.createDiagnosticReporter(system, pretty); - return diagnostic => { - if (diagnostic.source === "typescript-to-lua") { - diagnostic = { ...diagnostic, code: ("TL" + diagnostic.code) as any }; - } - - reporter(diagnostic); - }; + return diagnostic => reporter(prepareDiagnosticForFormatting(diagnostic)); } diff --git a/src/index.ts b/src/index.ts index 8b0159a9c..c828369df 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,5 +6,4 @@ export * from "./LuaAST"; export { LuaLibFeature } from "./LuaLib"; export * from "./LuaPrinter"; export * from "./transformation/context"; -export { TranspileError } from "./transformation/utils/errors"; export * from "./transpilation"; diff --git a/src/transformation/builtins/array.ts b/src/transformation/builtins/array.ts index af4f674bd..41859e57c 100644 --- a/src/transformation/builtins/array.ts +++ b/src/transformation/builtins/array.ts @@ -1,14 +1,14 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; export function transformArrayPrototypeCall( context: TransformationContext, node: PropertyCallExpression -): lua.CallExpression { +): lua.CallExpression | undefined { const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); @@ -79,7 +79,7 @@ export function transformArrayPrototypeCall( case "flatMap": return transformLuaLibFunction(context, LuaLibFeature.ArrayFlatMap, node, caller, ...params); default: - throw UnsupportedProperty("array", expressionName, node); + context.diagnostics.push(unsupportedProperty(expression.name, "array", expressionName)); } } diff --git a/src/transformation/builtins/console.ts b/src/transformation/builtins/console.ts index 988aba1b3..af7ceb87e 100644 --- a/src/transformation/builtins/console.ts +++ b/src/transformation/builtins/console.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; const isStringFormatTemplate = (node: ts.Expression) => ts.isStringLiteral(node) && node.text.includes("%"); @@ -9,7 +9,7 @@ const isStringFormatTemplate = (node: ts.Expression) => ts.isStringLiteral(node) export function transformConsoleCall( context: TransformationContext, expression: PropertyCallExpression -): lua.Expression { +): lua.Expression | undefined { const method = expression.expression; const methodName = method.name.text; const signature = context.checker.getResolvedSignature(expression); @@ -61,6 +61,6 @@ export function transformConsoleCall( ); return lua.createCallExpression(lua.createIdentifier("print"), [debugTracebackCall]); default: - throw UnsupportedProperty("console", methodName, expression); + context.diagnostics.push(unsupportedProperty(method.name, "console", methodName)); } } diff --git a/src/transformation/builtins/function.ts b/src/transformation/builtins/function.ts index 2eefae340..3ba8c2aaa 100644 --- a/src/transformation/builtins/function.ts +++ b/src/transformation/builtins/function.ts @@ -1,6 +1,6 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty, UnsupportedSelfFunctionConversion } from "../utils/errors"; +import { unsupportedProperty, unsupportedSelfFunctionConversion } from "../utils/diagnostics"; import { ContextType, getFunctionContextType } from "../utils/function-context"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; @@ -8,11 +8,11 @@ import { PropertyCallExpression, transformArguments } from "../visitors/call"; export function transformFunctionPrototypeCall( context: TransformationContext, node: PropertyCallExpression -): lua.CallExpression { +): lua.CallExpression | undefined { const expression = node.expression; const callerType = context.checker.getTypeAtLocation(expression.expression); if (getFunctionContextType(context, callerType) === ContextType.Void) { - throw UnsupportedSelfFunctionConversion(node); + context.diagnostics.push(unsupportedSelfFunctionConversion(node)); } const signature = context.checker.getResolvedSignature(node); @@ -27,6 +27,6 @@ export function transformFunctionPrototypeCall( case "call": return transformLuaLibFunction(context, LuaLibFeature.FunctionCall, node, caller, ...params); default: - throw UnsupportedProperty("function", expressionName, node); + context.diagnostics.push(unsupportedProperty(expression.name, "function", expressionName)); } } diff --git a/src/transformation/builtins/index.ts b/src/transformation/builtins/index.ts index 0958d0145..8a23ed824 100644 --- a/src/transformation/builtins/index.ts +++ b/src/transformation/builtins/index.ts @@ -28,24 +28,22 @@ export function transformBuiltinPropertyAccessExpression( context: TransformationContext, node: ts.PropertyAccessExpression ): lua.Expression | undefined { - const type = context.checker.getTypeAtLocation(node.expression); - if (isStringType(context, type)) { + const ownerType = context.checker.getTypeAtLocation(node.expression); + + if (isStringType(context, ownerType)) { return transformStringProperty(context, node); - } else if (isArrayType(context, type)) { - const arrayPropertyAccess = transformArrayProperty(context, node); - if (arrayPropertyAccess) { - return arrayPropertyAccess; - } } - if (ts.isIdentifier(node.expression)) { - const ownerType = context.checker.getTypeAtLocation(node.expression); + if (isArrayType(context, ownerType)) { + return transformArrayProperty(context, node); + } - if (isStandardLibraryType(context, ownerType, "Math")) { - return transformMathProperty(node); - } else if (isStandardLibraryType(context, ownerType, "Symbol")) { - // Pull in Symbol lib - importLuaLibFeature(context, LuaLibFeature.Symbol); + if (ts.isIdentifier(node.expression) && isStandardLibraryType(context, ownerType, undefined)) { + switch (node.expression.text) { + case "Math": + return transformMathProperty(context, node); + case "Symbol": + importLuaLibFeature(context, LuaLibFeature.Symbol); } } } diff --git a/src/transformation/builtins/math.ts b/src/transformation/builtins/math.ts index 9f5b4a1a3..6ceae16bd 100644 --- a/src/transformation/builtins/math.ts +++ b/src/transformation/builtins/math.ts @@ -2,10 +2,13 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { LuaTarget } from "../../CompilerOptions"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; -export function transformMathProperty(node: ts.PropertyAccessExpression): lua.Expression { +export function transformMathProperty( + context: TransformationContext, + node: ts.PropertyAccessExpression +): lua.Expression | undefined { const name = node.name.text; switch (name) { case "PI": @@ -23,11 +26,14 @@ export function transformMathProperty(node: ts.PropertyAccessExpression): lua.Ex return lua.createNumericLiteral(Math[name], node); default: - throw UnsupportedProperty("Math", name, node); + context.diagnostics.push(unsupportedProperty(node.name, "Math", name)); } } -export function transformMathCall(context: TransformationContext, node: PropertyCallExpression): lua.Expression { +export function transformMathCall( + context: TransformationContext, + node: PropertyCallExpression +): lua.Expression | undefined { const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); @@ -93,6 +99,6 @@ export function transformMathCall(context: TransformationContext, node: Property } default: - throw UnsupportedProperty("Math", expressionName, expression); + context.diagnostics.push(unsupportedProperty(expression.name, "Math", expressionName)); } } diff --git a/src/transformation/builtins/number.ts b/src/transformation/builtins/number.ts index 9200be74a..227d82b23 100644 --- a/src/transformation/builtins/number.ts +++ b/src/transformation/builtins/number.ts @@ -1,13 +1,13 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; export function transformNumberPrototypeCall( context: TransformationContext, node: PropertyCallExpression -): lua.Expression { +): lua.Expression | undefined { const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); @@ -20,14 +20,14 @@ export function transformNumberPrototypeCall( ? lua.createCallExpression(lua.createIdentifier("tostring"), [caller], node) : transformLuaLibFunction(context, LuaLibFeature.NumberToString, node, caller, ...params); default: - throw UnsupportedProperty("number", expressionName, node); + context.diagnostics.push(unsupportedProperty(expression.name, "number", expressionName)); } } export function transformNumberConstructorCall( context: TransformationContext, expression: PropertyCallExpression -): lua.CallExpression { +): lua.CallExpression | undefined { const method = expression.expression; const parameters = transformArguments(context, expression.arguments); const methodName = method.name.text; @@ -37,6 +37,6 @@ export function transformNumberConstructorCall( case "isFinite": return transformLuaLibFunction(context, LuaLibFeature.NumberIsFinite, expression, ...parameters); default: - throw UnsupportedProperty("Number", methodName, expression); + context.diagnostics.push(unsupportedProperty(method.name, "Number", methodName)); } } diff --git a/src/transformation/builtins/object.ts b/src/transformation/builtins/object.ts index acd468bd4..358bebbf5 100644 --- a/src/transformation/builtins/object.ts +++ b/src/transformation/builtins/object.ts @@ -1,13 +1,13 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; export function transformObjectConstructorCall( context: TransformationContext, expression: PropertyCallExpression -): lua.Expression { +): lua.Expression | undefined { const method = expression.expression; const parameters = transformArguments(context, expression.arguments); const methodName = method.name.text; @@ -24,7 +24,7 @@ export function transformObjectConstructorCall( case "values": return transformLuaLibFunction(context, LuaLibFeature.ObjectValues, expression, ...parameters); default: - throw UnsupportedProperty("Object", methodName, expression); + context.diagnostics.push(unsupportedProperty(method.name, "Object", methodName)); } } diff --git a/src/transformation/builtins/string.ts b/src/transformation/builtins/string.ts index ea755b707..ac2005929 100644 --- a/src/transformation/builtins/string.ts +++ b/src/transformation/builtins/string.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { createExpressionPlusOne } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; @@ -18,7 +18,7 @@ function createStringCall(methodName: string, tsOriginal: ts.Node, ...params: lu export function transformStringPrototypeCall( context: TransformationContext, node: PropertyCallExpression -): lua.Expression { +): lua.Expression | undefined { const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); @@ -110,14 +110,14 @@ export function transformStringPrototypeCall( case "padEnd": return transformLuaLibFunction(context, LuaLibFeature.StringPadEnd, node, caller, ...params); default: - throw UnsupportedProperty("string", expressionName, node); + context.diagnostics.push(unsupportedProperty(expression.name, "string", expressionName)); } } export function transformStringConstructorCall( context: TransformationContext, node: PropertyCallExpression -): lua.Expression { +): lua.Expression | undefined { const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); @@ -132,19 +132,19 @@ export function transformStringConstructorCall( ); default: - throw UnsupportedProperty("String", expressionName, node); + context.diagnostics.push(unsupportedProperty(expression.name, "String", expressionName)); } } export function transformStringProperty( context: TransformationContext, node: ts.PropertyAccessExpression -): lua.UnaryExpression { +): lua.UnaryExpression | undefined { switch (node.name.text) { case "length": const expression = context.transformExpression(node.expression); return lua.createUnaryExpression(expression, lua.SyntaxKind.LengthOperator, node); default: - throw UnsupportedProperty("string", node.name.text, node); + context.diagnostics.push(unsupportedProperty(node.name, "string", node.name.text)); } } diff --git a/src/transformation/builtins/symbol.ts b/src/transformation/builtins/symbol.ts index 4a6e5e43f..04329e059 100644 --- a/src/transformation/builtins/symbol.ts +++ b/src/transformation/builtins/symbol.ts @@ -1,14 +1,13 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { UnsupportedProperty } from "../utils/errors"; +import { unsupportedProperty } from "../utils/diagnostics"; import { importLuaLibFeature, LuaLibFeature } from "../utils/lualib"; import { PropertyCallExpression, transformArguments } from "../visitors/call"; -// Transpile a Symbol._ property export function transformSymbolConstructorCall( context: TransformationContext, expression: PropertyCallExpression -): lua.CallExpression { +): lua.CallExpression | undefined { const method = expression.expression; const signature = context.checker.getResolvedSignature(expression); const parameters = transformArguments(context, expression.arguments, signature); @@ -21,6 +20,6 @@ export function transformSymbolConstructorCall( const functionIdentifier = lua.createIdentifier(`__TS__SymbolRegistry${upperMethodName}`); return lua.createCallExpression(functionIdentifier, parameters, expression); default: - throw UnsupportedProperty("Symbol", methodName, expression); + context.diagnostics.push(unsupportedProperty(method.name, "Symbol", methodName)); } } diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 0b34da260..ebc8dfea1 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -24,6 +24,7 @@ export interface DiagnosticsProducingTypeChecker extends ts.TypeChecker { } export class TransformationContext { + public readonly diagnostics: ts.Diagnostic[] = []; public readonly checker: DiagnosticsProducingTypeChecker = (this .program as any).getDiagnosticsProducingTypeChecker(); public readonly resolver: EmitResolver; @@ -52,7 +53,7 @@ export class TransformationContext { const nodeVisitors = this.visitorMap.get(node.kind); if (!nodeVisitors || nodeVisitors.length === 0) { - throw new Error(`${ts.SyntaxKind[node.kind]} is not supported`); + throw new Error(`Unsupported node kind: ${ts.SyntaxKind[node.kind]}.`); } const previousNodeVisitors = this.currentNodeVisitors; diff --git a/src/transformation/index.ts b/src/transformation/index.ts index a720a8ffd..69b098811 100644 --- a/src/transformation/index.ts +++ b/src/transformation/index.ts @@ -3,20 +3,9 @@ import * as lua from "../LuaAST"; import { LuaLibFeature } from "../LuaLib"; import { getOrUpdate } from "../utils"; import { ObjectVisitor, TransformationContext, VisitorMap, Visitors } from "./context"; -import { TranspileError } from "./utils/errors"; import { getUsedLuaLibFeatures } from "./utils/lualib"; import { standardVisitors } from "./visitors"; -const transpileErrorDiagnostic = (error: TranspileError): ts.Diagnostic => ({ - file: error.node.getSourceFile(), - start: error.node.getStart(), - length: error.node.getWidth(), - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: error.message, -}); - export function createVisitorMap(customVisitors: Visitors[]): VisitorMap { const visitorMap: VisitorMap = new Map(); for (const visitors of [standardVisitors, ...customVisitors]) { @@ -52,23 +41,11 @@ export function transformSourceFile( visitorMap: VisitorMap ): TransformSourceFileResult { const context = new TransformationContext(program, sourceFile, visitorMap); + const [luaAst] = context.transformNode(sourceFile) as [lua.Block]; - try { - const [luaAst] = context.transformNode(sourceFile) as [lua.Block]; - const luaLibFeatures = getUsedLuaLibFeatures(context); - - return { luaAst, luaLibFeatures, diagnostics: [] }; - } catch (error) { - if (!(error instanceof TranspileError)) throw error; - - return { - luaAst: lua.createBlock([ - lua.createExpressionStatement( - lua.createCallExpression(lua.createIdentifier("error"), [lua.createStringLiteral(error.message)]) - ), - ]), - luaLibFeatures: new Set(), - diagnostics: [transpileErrorDiagnostic(error)], - }; - } + return { + luaAst, + luaLibFeatures: getUsedLuaLibFeatures(context), + diagnostics: context.diagnostics, + }; } diff --git a/src/transformation/utils/assignment-validation.ts b/src/transformation/utils/assignment-validation.ts index a9944b260..05cfea467 100644 --- a/src/transformation/utils/assignment-validation.ts +++ b/src/transformation/utils/assignment-validation.ts @@ -1,30 +1,13 @@ import * as ts from "typescript"; import { getOrUpdate } from "../../utils"; import { TransformationContext } from "../context"; -import { AnnotationKind, getTypeAnnotations } from "./annotations"; import { - ForbiddenLuaTableUseException, - UnsupportedNoSelfFunctionConversion, - UnsupportedOverloadAssignment, - UnsupportedSelfFunctionConversion, -} from "./errors"; + unsupportedNoSelfFunctionConversion, + unsupportedOverloadAssignment, + unsupportedSelfFunctionConversion, +} from "./diagnostics"; import { ContextType, getFunctionContextType } from "./function-context"; -// TODO: Make validateAssignment check symbols? -// TODO: Move to LuaTable plugin? -export function validatePropertyAssignment( - context: TransformationContext, - node: ts.AssignmentExpression -): void { - if (!ts.isPropertyAccessExpression(node.left)) return; - - const leftType = context.checker.getTypeAtLocation(node.left.expression); - const annotations = getTypeAnnotations(leftType); - if (annotations.has(AnnotationKind.LuaTable) && node.left.name.text === "length") { - throw ForbiddenLuaTableUseException(`A LuaTable object's length cannot be re-assigned.`, node); - } -} - // TODO: Clear if types are reused between compilations const typeValidationCache = new WeakMap>(); @@ -114,12 +97,12 @@ function validateFunctionAssignment( const toContext = getFunctionContextType(context, toType); if (fromContext === ContextType.Mixed || toContext === ContextType.Mixed) { - throw UnsupportedOverloadAssignment(node, toName); + context.diagnostics.push(unsupportedOverloadAssignment(node, toName)); } else if (fromContext !== toContext && fromContext !== ContextType.None && toContext !== ContextType.None) { if (toContext === ContextType.Void) { - throw UnsupportedNoSelfFunctionConversion(node, toName); + context.diagnostics.push(unsupportedNoSelfFunctionConversion(node, toName)); } else { - throw UnsupportedSelfFunctionConversion(node, toName); + context.diagnostics.push(unsupportedSelfFunctionConversion(node, toName)); } } } diff --git a/src/transformation/utils/diagnostics.ts b/src/transformation/utils/diagnostics.ts new file mode 100644 index 000000000..5b7b2de38 --- /dev/null +++ b/src/transformation/utils/diagnostics.ts @@ -0,0 +1,126 @@ +import * as ts from "typescript"; +import { LuaTarget } from "../../CompilerOptions"; +import { createSerialDiagnosticFactory } from "../../utils"; +import { AnnotationKind } from "./annotations"; + +const createDiagnosticFactory = (message: string | ((...args: TArgs) => string)) => + createSerialDiagnosticFactory((node: ts.Node, ...args: TArgs) => ({ + file: node.getSourceFile(), + start: node.getStart(), + length: node.getWidth(), + messageText: typeof message === "string" ? message : message(...args), + })); + +export const forbiddenForIn = createDiagnosticFactory(`Iterating over arrays with 'for ... in' is not allowed.`); + +export const unsupportedNoSelfFunctionConversion = createDiagnosticFactory((name?: string) => { + const nameReference = name ? ` '${name}'` : ""; + return ( + `Unable to convert function with a 'this' parameter to function${nameReference} with no 'this'. ` + + `To fix, wrap in an arrow function, or declare with 'this: void'.` + ); +}); + +export const unsupportedSelfFunctionConversion = createDiagnosticFactory((name?: string) => { + const nameReference = name ? ` '${name}'` : ""; + return ( + `Unable to convert function with no 'this' parameter to function${nameReference} with 'this'. ` + + `To fix, wrap in an arrow function, or declare with 'this: any'.` + ); +}); + +export const unsupportedOverloadAssignment = createDiagnosticFactory((name?: string) => { + const nameReference = name ? ` to '${name}'` : ""; + return ( + `Unsupported assignment of function with different overloaded types for 'this'${nameReference}. ` + + "Overloads should all have the same type for 'this'." + ); +}); + +export const decoratorInvalidContext = createDiagnosticFactory(`Decorator function cannot have 'this: void'.`); + +export const annotationInvalidArgumentCount = createDiagnosticFactory( + (kind: AnnotationKind, got: number, expected: number) => `'@${kind}' expects ${expected} arguments, but got ${got}.` +); + +export const extensionCannotConstruct = createDiagnosticFactory( + "Cannot construct classes with '@extension' or '@metaExtension' annotation." +); + +export const extensionCannotExtend = createDiagnosticFactory( + `Cannot extend classes with '@extension' or '@metaExtension' annotation.` +); + +export const extensionCannotExport = createDiagnosticFactory( + `Cannot export classes with '@extension' or '@metaExtension' annotation.` +); + +export const extensionInvalidInstanceOf = createDiagnosticFactory( + `Cannot use instanceof on classes with '@extension' or '@metaExtension' annotation.` +); + +export const extensionAndMetaExtensionConflict = createDiagnosticFactory( + `Cannot use both '@extension' and '@metaExtension' annotations on the same class.` +); + +export const metaExtensionMissingExtends = createDiagnosticFactory( + `'@metaExtension' annotation requires the extension of the metatable class.` +); + +export const invalidForRangeCall = createDiagnosticFactory((message: string) => `Invalid @forRange call: ${message}.`); + +export const luaTableMustBeAmbient = createDiagnosticFactory( + "Classes with the '@luaTable' annotation must be ambient." +); + +export const luaTableCannotBeExtended = createDiagnosticFactory( + "Cannot extend classes with the '@luaTable' annotation." +); + +export const luaTableInvalidInstanceOf = createDiagnosticFactory( + "The instanceof operator cannot be used with a '@luaTable' class." +); + +export const luaTableCannotBeAccessedDynamically = createDiagnosticFactory("@luaTable cannot be accessed dynamically."); + +export const luaTableForbiddenUsage = createDiagnosticFactory( + (description: string) => `Invalid @luaTable usage: ${description}.` +); + +export const luaIteratorForbiddenUsage = createDiagnosticFactory( + "Unsupported use of lua iterator with '@tupleReturn' annotation in for...of statement. " + + "You must use a destructuring statement to catch results from a lua iterator with " + + "the '@tupleReturn' annotation." +); + +export const unsupportedAccessorInObjectLiteral = createDiagnosticFactory( + "Accessors in object literal are not supported." +); + +export const unsupportedNullishCoalescing = createDiagnosticFactory("Nullish coalescing is not supported."); + +export const unsupportedRightShiftOperator = createDiagnosticFactory( + "Right shift operator is not supported for target Lua 5.3. Use `>>>` instead." +); + +const getLuaTargetName = (version: LuaTarget) => (version === LuaTarget.LuaJIT ? "LuaJIT" : `Lua ${version}`); +export const unsupportedForTarget = createDiagnosticFactory( + (functionality: string, version: LuaTarget) => + `${functionality} is/are not supported for target ${getLuaTargetName(version)}.` +); + +export const unsupportedProperty = createDiagnosticFactory( + (parentName: string, property: string) => `${parentName}.${property} is unsupported.` +); + +export const invalidAmbientIdentifierName = createDiagnosticFactory( + (text: string) => `Invalid ambient identifier name '${text}'. Ambient identifiers must be valid lua identifiers.` +); + +export const unresolvableRequirePath = createDiagnosticFactory( + (path: string) => `Cannot create require path. Module '${path}' does not exist within --rootDir.` +); + +export const unsupportedVarDeclaration = createDiagnosticFactory( + "`var` declarations are not supported. Use `let` or `const` instead." +); diff --git a/src/transformation/utils/errors.ts b/src/transformation/utils/errors.ts deleted file mode 100644 index 370e27daa..000000000 --- a/src/transformation/utils/errors.ts +++ /dev/null @@ -1,143 +0,0 @@ -import * as ts from "typescript"; -import { LuaTarget } from "../../CompilerOptions"; - -export class TranspileError extends Error { - public name = "TranspileError"; - constructor(message: string, public node: ts.Node) { - super(message); - } -} - -const getLuaTargetName = (version: LuaTarget) => (version === LuaTarget.LuaJIT ? "LuaJIT" : `Lua ${version}`); - -export const ForbiddenForIn = (node: ts.Node) => - new TranspileError(`Iterating over arrays with 'for ... in' is not allowed.`, node); - -export const ForbiddenLuaTableNonDeclaration = (node: ts.Node) => - new TranspileError(`Classes with the '@luaTable' annotation must be declared.`, node); - -export const InvalidExtendsLuaTable = (node: ts.Node) => - new TranspileError(`Cannot extend classes with the '@luaTable' annotation.`, node); - -export const InvalidInstanceOfLuaTable = (node: ts.Node) => - new TranspileError(`The instanceof operator cannot be used with a '@luaTable' class.`, node); - -export const ForbiddenLuaTableUseException = (description: string, node: ts.Node) => - new TranspileError(`Invalid @luaTable usage: ${description}`, node); - -export const InvalidAnnotationArgumentNumber = (name: string, got: number, expected: number, node: ts.Node) => - new TranspileError(`'${name}' expects ${expected} argument(s) but got ${got}.`, node); - -export const InvalidDecoratorContext = (node: ts.Node) => - new TranspileError(`Decorator function cannot have 'this: void'.`, node); - -export const InvalidExtensionMetaExtension = (node: ts.Node) => - new TranspileError(`Cannot use both '@extension' and '@metaExtension' annotations on the same class.`, node); - -export const InvalidNewExpressionOnExtension = (node: ts.Node) => - new TranspileError(`Cannot construct classes with '@extension' or '@metaExtension' annotation.`, node); - -export const InvalidExportDeclaration = (declaration: ts.ExportDeclaration) => - new TranspileError("Encountered invalid export declaration without exports and without module.", declaration); - -export const InvalidExtendsExtension = (node: ts.Node) => - new TranspileError(`Cannot extend classes with '@extension' or '@metaExtension' annotation.`, node); - -export const InvalidExportsExtension = (node: ts.Node) => - new TranspileError(`Cannot export classes with '@extension' or '@metaExtension' annotation.`, node); - -export const InvalidInstanceOfExtension = (node: ts.Node) => - new TranspileError(`Cannot use instanceof on classes with '@extension' or '@metaExtension' annotation.`, node); - -export const InvalidJsonFileContent = (node: ts.Node) => new TranspileError("Invalid JSON file content", node); - -export const MissingClassName = (node: ts.Node) => new TranspileError(`Class declarations must have a name.`, node); - -export const MissingForOfVariables = (node: ts.Node) => - new TranspileError("Transpiled ForOf variable declaration list contains no declarations.", node); - -export const MissingFunctionName = (declaration: ts.FunctionLikeDeclaration) => - new TranspileError("Unsupported function declaration without name.", declaration); - -export const MissingMetaExtension = (node: ts.Node) => - new TranspileError(`'@metaExtension' annotation requires the extension of the metatable class.`, node); - -export const NonFlattenableDestructure = (node: ts.Node) => - new TranspileError(`This node cannot be destructured using a standard Lua assignment statement.`, node); - -export const UndefinedFunctionDefinition = (functionSymbolId: number) => - new Error(`Function definition for function symbol ${functionSymbolId} is undefined.`); - -export const UnsupportedForInVariable = (node: ts.Node) => - new TranspileError(`Unsupported for-in variable kind.`, node); - -export const UndefinedScope = () => new Error("Expected to pop a scope, but found undefined."); - -export const UndefinedTypeNode = (node: ts.Node) => new TranspileError("Failed to resolve required type node.", node); - -export const UnknownSuperType = (node: ts.Node) => - new TranspileError("Unable to resolve type of super expression.", node); - -export const UnsupportedImportType = (node: ts.Node) => new TranspileError(`Unsupported import type.`, node); - -export const UnsupportedKind = (description: string, kind: ts.SyntaxKind, node: ts.Node) => - new TranspileError(`Unsupported ${description} kind: ${ts.SyntaxKind[kind]}`, node); - -export const UnsupportedProperty = (parentName: string, property: string, node: ts.Node) => - new TranspileError(`Unsupported property on ${parentName}: ${property}`, node); - -export const UnsupportedForTarget = (functionality: string, version: LuaTarget, node: ts.Node) => - new TranspileError(`${functionality} is/are not supported for target ${getLuaTargetName(version)}.`, node); - -export const UnsupportedFunctionWithoutBody = (node: ts.FunctionLikeDeclaration) => - new TranspileError("Functions with undefined bodies are not supported.", node); - -export const UnsupportedNoSelfFunctionConversion = (node: ts.Node, name?: string) => { - const nameReference = name ? ` '${name}'` : ""; - return new TranspileError( - `Unable to convert function with a 'this' parameter to function${nameReference} with no 'this'. ` + - `To fix, wrap in an arrow function, or declare with 'this: void'.`, - node - ); -}; - -export const UnsupportedSelfFunctionConversion = (node: ts.Node, name?: string) => { - const nameReference = name ? ` '${name}'` : ""; - return new TranspileError( - `Unable to convert function with no 'this' parameter to function${nameReference} with 'this'. ` + - `To fix, wrap in an arrow function or declare with 'this: any'.`, - node - ); -}; - -export const UnsupportedOverloadAssignment = (node: ts.Node, name?: string) => { - const nameReference = name ? ` to '${name}'` : ""; - return new TranspileError( - `Unsupported assignment of function with different overloaded types for 'this'${nameReference}. ` + - "Overloads should all have the same type for 'this'.", - node - ); -}; - -export const UnsupportedNonDestructuringLuaIterator = (node: ts.Node) => - new TranspileError( - "Unsupported use of lua iterator with '@tupleReturn' annotation in for...of statement. " + - "You must use a destructuring statement to catch results from a lua iterator with " + - "the '@tupleReturn' annotation.", - node - ); - -export const UnresolvableRequirePath = (node: ts.Node, reason: string, path?: string) => - new TranspileError(`${reason}. TypeScript path: ${path}.`, node); - -export const InvalidAmbientIdentifierName = (node: ts.Identifier) => - new TranspileError( - `Invalid ambient identifier name "${node.text}". Ambient identifiers must be valid lua identifiers.`, - node - ); - -export const InvalidForRangeCall = (node: ts.Node, message: string) => - new TranspileError(`Invalid @forRange call: ${message}`, node); - -export const UnsupportedVarDeclaration = (node: ts.Node) => - new TranspileError("`var` declarations are not supported. Use `let` or `const` instead.", node); diff --git a/src/transformation/utils/lua-ast.ts b/src/transformation/utils/lua-ast.ts index c72ec2d74..318c4abaf 100644 --- a/src/transformation/utils/lua-ast.ts +++ b/src/transformation/utils/lua-ast.ts @@ -1,7 +1,7 @@ -import * as assert from "assert"; import * as ts from "typescript"; import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; +import { assert } from "../../utils"; import { TransformationContext } from "../context"; import { createExportedIdentifier, getIdentifierExportScope } from "./export"; import { peekScope, ScopeType } from "./scope"; diff --git a/src/transformation/utils/safe-names.ts b/src/transformation/utils/safe-names.ts index ed95f0d44..b10ed414f 100644 --- a/src/transformation/utils/safe-names.ts +++ b/src/transformation/utils/safe-names.ts @@ -1,9 +1,10 @@ import * as ts from "typescript"; import { TransformationContext } from "../context"; -import { InvalidAmbientIdentifierName } from "./errors"; -import { isAmbientNode } from "./typescript"; +import { invalidAmbientIdentifierName } from "./diagnostics"; import { isSymbolExported } from "./export"; +import { isAmbientNode } from "./typescript"; +export const isValidLuaIdentifier = (name: string) => !luaKeywords.has(name) && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name); export const luaKeywords: ReadonlySet = new Set([ "and", "break", @@ -29,7 +30,7 @@ export const luaKeywords: ReadonlySet = new Set([ "while", ]); -export const luaBuiltins: ReadonlySet = new Set([ +const luaBuiltins: ReadonlySet = new Set([ "_G", "assert", "coroutine", @@ -51,42 +52,50 @@ export const luaBuiltins: ReadonlySet = new Set([ "unpack", ]); -export const isValidLuaIdentifier = (str: string) => /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(str); +export const isUnsafeName = (name: string) => !isValidLuaIdentifier(name) || luaBuiltins.has(name); + +function checkName(context: TransformationContext, name: string, node: ts.Node): boolean { + const isInvalid = !isValidLuaIdentifier(name); + + if (isInvalid) { + // Empty identifier is a TypeScript error + if (name !== "") { + context.diagnostics.push(invalidAmbientIdentifierName(node, name)); + } + } -export const isUnsafeName = (name: string) => - luaKeywords.has(name) || luaBuiltins.has(name) || !isValidLuaIdentifier(name); + return isInvalid; +} export function hasUnsafeSymbolName( context: TransformationContext, symbol: ts.Symbol, tsOriginal: ts.Identifier ): boolean { - const isLuaKeyword = luaKeywords.has(symbol.name); - const isInvalidIdentifier = !isValidLuaIdentifier(symbol.name); const isAmbient = symbol.declarations && symbol.declarations.some(d => isAmbientNode(d)); - if ((isLuaKeyword || isInvalidIdentifier) && isAmbient) { - // Catch ambient declarations of identifiers with bad names - throw InvalidAmbientIdentifierName(tsOriginal); - } - if (isUnsafeName(symbol.name)) { - // only unsafe when non-ambient and not exported - return !isAmbient && !isSymbolExported(context, symbol); + // Catch ambient declarations of identifiers with bad names + if (isAmbient && checkName(context, symbol.name, tsOriginal)) { + return true; } - return false; + // only unsafe when non-ambient and not exported + return isUnsafeName(symbol.name) && !isAmbient && !isSymbolExported(context, symbol); } -export function hasUnsafeIdentifierName(context: TransformationContext, identifier: ts.Identifier): boolean { - const symbol = context.checker.getSymbolAtLocation(identifier); - - if (symbol !== undefined) { - return hasUnsafeSymbolName(context, symbol, identifier); - } else if (luaKeywords.has(identifier.text) || !isValidLuaIdentifier(identifier.text)) { - throw InvalidAmbientIdentifierName(identifier); +export function hasUnsafeIdentifierName( + context: TransformationContext, + identifier: ts.Identifier, + checkSymbol = true +): boolean { + if (checkSymbol) { + const symbol = context.checker.getSymbolAtLocation(identifier); + if (symbol) { + return hasUnsafeSymbolName(context, symbol, identifier); + } } - return false; + return checkName(context, identifier.text, identifier); } const fixInvalidLuaIdentifier = (name: string) => diff --git a/src/transformation/utils/scope.ts b/src/transformation/utils/scope.ts index 44430f763..2c9f267dd 100644 --- a/src/transformation/utils/scope.ts +++ b/src/transformation/utils/scope.ts @@ -1,9 +1,7 @@ -import * as assert from "assert"; import * as ts from "typescript"; import * as lua from "../../LuaAST"; -import { getOrUpdate, isNonNull } from "../../utils"; +import { assert, getOrUpdate, isNonNull } from "../../utils"; import { TransformationContext } from "../context"; -import { UndefinedFunctionDefinition, UndefinedScope } from "./errors"; import { getSymbolInfo } from "./symbols"; import { getFirstDeclarationInFile } from "./typescript"; @@ -65,9 +63,7 @@ export function markSymbolAsReferencedInCurrentScopes( export function peekScope(context: TransformationContext): Scope { const scopeStack = getScopeStack(context); const scope = scopeStack[scopeStack.length - 1]; - if (!scope) { - throw UndefinedScope(); - } + assert(scope); return scope; } @@ -90,9 +86,7 @@ export function pushScope(context: TransformationContext, scopeType: ScopeType): export function popScope(context: TransformationContext): Scope { const scopeStack = getScopeStack(context); const scope = scopeStack.pop(); - if (!scope) { - throw UndefinedScope(); - } + assert(scope); return scope; } @@ -123,9 +117,7 @@ function shouldHoistSymbol(context: TransformationContext, symbolId: lua.SymbolI if (scope.functionDefinitions) { for (const [functionSymbolId, functionDefinition] of scope.functionDefinitions) { - if (functionDefinition.definition === undefined) { - throw UndefinedFunctionDefinition(functionSymbolId); - } + assert(functionDefinition.definition); const { line, column } = lua.getOriginalPos(functionDefinition.definition); if (line !== undefined && column !== undefined) { @@ -196,9 +188,7 @@ function hoistFunctionDefinitions( const result = [...statements]; const hoistedFunctions: Array = []; for (const [functionSymbolId, functionDefinition] of scope.functionDefinitions) { - if (functionDefinition.definition === undefined) { - throw UndefinedFunctionDefinition(functionSymbolId); - } + assert(functionDefinition.definition); if (shouldHoistSymbol(context, functionSymbolId, scope)) { const index = result.indexOf(functionDefinition.definition); diff --git a/src/transformation/visitors/access.ts b/src/transformation/visitors/access.ts index 4043a56a0..3502e15e4 100644 --- a/src/transformation/visitors/access.ts +++ b/src/transformation/visitors/access.ts @@ -6,7 +6,7 @@ import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; import { createExpressionPlusOne } from "../utils/lua-ast"; import { isArrayType, isNumberType, isStringType } from "../utils/typescript"; import { tryGetConstEnumValue } from "./enum"; -import { transformLuaTableElementAccessExpression, transformLuaTablePropertyAccessExpression } from "./lua-table"; +import { transformLuaTablePropertyAccessExpression, validateLuaTableElementAccessExpression } from "./lua-table"; export function transformElementAccessArgument( context: TransformationContext, @@ -24,7 +24,7 @@ export function transformElementAccessArgument( } export const transformElementAccessExpression: FunctionVisitor = (expression, context) => { - transformLuaTableElementAccessExpression(context, expression); + validateLuaTableElementAccessExpression(context, expression); const constEnumValue = tryGetConstEnumValue(context, expression); if (constEnumValue) { diff --git a/src/transformation/visitors/binary-expression/assignments.ts b/src/transformation/visitors/binary-expression/assignments.ts index 6a5417b0f..6a785699a 100644 --- a/src/transformation/visitors/binary-expression/assignments.ts +++ b/src/transformation/visitors/binary-expression/assignments.ts @@ -3,12 +3,13 @@ import * as lua from "../../../LuaAST"; import { cast } from "../../../utils"; import { TransformationContext } from "../../context"; import { isTupleReturnCall } from "../../utils/annotations"; -import { validateAssignment, validatePropertyAssignment } from "../../utils/assignment-validation"; +import { validateAssignment } from "../../utils/assignment-validation"; import { createExportedIdentifier, getDependenciesOfSymbol, isSymbolExported } from "../../utils/export"; import { createImmediatelyInvokedFunctionExpression, createUnpackCall, wrapInTable } from "../../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { isArrayType, isDestructuringAssignment } from "../../utils/typescript"; import { transformElementAccessArgument } from "../access"; +import { transformLuaTablePropertyAccessInAssignment } from "../lua-table"; import { isArrayLength, transformDestructuringAssignment } from "./destructuring-assignments"; export function transformAssignmentLeftHandSideExpression( @@ -16,7 +17,9 @@ export function transformAssignmentLeftHandSideExpression( node: ts.Expression ): lua.AssignmentLeftHandSideExpression { const symbol = context.checker.getSymbolAtLocation(node); - const left = context.transformExpression(node); + const left = ts.isPropertyAccessExpression(node) + ? transformLuaTablePropertyAccessInAssignment(context, node) ?? context.transformExpression(node) + : context.transformExpression(node); return lua.isIdentifier(left) && symbol && isSymbolExported(context, symbol) ? createExportedIdentifier(context, left) @@ -67,7 +70,7 @@ export function transformAssignment( export function transformAssignmentExpression( context: TransformationContext, expression: ts.AssignmentExpression -): lua.CallExpression | lua.MethodCallExpression { +): lua.Expression { // Validate assignment const rightType = context.checker.getTypeAtLocation(expression.right); const leftType = context.checker.getTypeAtLocation(expression.left); @@ -119,6 +122,9 @@ export function transformAssignmentExpression( const objExpression = context.transformExpression(expression.left.expression); let indexExpression: lua.Expression; if (ts.isPropertyAccessExpression(expression.left)) { + // Called only for validation + transformLuaTablePropertyAccessInAssignment(context, expression.left); + // Property access indexExpression = lua.createStringLiteral(expression.left.name.text); } else { @@ -175,7 +181,6 @@ export function transformAssignmentStatement( const rightType = context.checker.getTypeAtLocation(expression.right); const leftType = context.checker.getTypeAtLocation(expression.left); validateAssignment(context, expression.right, rightType, leftType); - validatePropertyAssignment(context, expression); if (isDestructuringAssignment(expression)) { if (canBeTransformedToLuaAssignmentStatement(context, expression)) { diff --git a/src/transformation/visitors/binary-expression/bit.ts b/src/transformation/visitors/binary-expression/bit.ts index e8369e91d..ffdf410ec 100644 --- a/src/transformation/visitors/binary-expression/bit.ts +++ b/src/transformation/visitors/binary-expression/bit.ts @@ -1,11 +1,23 @@ import * as ts from "typescript"; import { LuaTarget } from "../../../CompilerOptions"; import * as lua from "../../../LuaAST"; +import { assertNever } from "../../../utils"; import { TransformationContext } from "../../context"; -import { UnsupportedForTarget, UnsupportedKind } from "../../utils/errors"; -import { transformBinaryOperator } from "../binary-expression"; +import { unsupportedForTarget, unsupportedRightShiftOperator } from "../../utils/diagnostics"; + +export type BitOperator = ts.ShiftOperator | ts.BitwiseOperator; +export const isBitOperator = (operator: ts.BinaryOperator): operator is BitOperator => + operator in bitOperatorToLibOperation; + +const bitOperatorToLibOperation: Record = { + [ts.SyntaxKind.AmpersandToken]: "band", + [ts.SyntaxKind.BarToken]: "bor", + [ts.SyntaxKind.CaretToken]: "bxor", + [ts.SyntaxKind.LessThanLessThanToken]: "lshift", + [ts.SyntaxKind.GreaterThanGreaterThanToken]: "arshift", + [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: "rshift", +}; -type BitOperator = ts.ShiftOperator | ts.BitwiseOperator; function transformBinaryBitLibOperation( node: ts.Node, left: lua.Expression, @@ -13,35 +25,33 @@ function transformBinaryBitLibOperation( operator: BitOperator, lib: string ): lua.Expression { - let bitFunction: string; + const functionName = bitOperatorToLibOperation[operator]; + return lua.createCallExpression( + lua.createTableIndexExpression(lua.createIdentifier(lib), lua.createStringLiteral(functionName)), + [left, right], + node + ); +} + +function transformBitOperatorToLuaOperator( + context: TransformationContext, + node: ts.Node, + operator: BitOperator +): lua.BinaryOperator { switch (operator) { - case ts.SyntaxKind.AmpersandToken: - bitFunction = "band"; - break; case ts.SyntaxKind.BarToken: - bitFunction = "bor"; - break; + return lua.SyntaxKind.BitwiseOrOperator; case ts.SyntaxKind.CaretToken: - bitFunction = "bxor"; - break; + return lua.SyntaxKind.BitwiseExclusiveOrOperator; + case ts.SyntaxKind.AmpersandToken: + return lua.SyntaxKind.BitwiseAndOperator; case ts.SyntaxKind.LessThanLessThanToken: - bitFunction = "lshift"; - break; - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - bitFunction = "rshift"; - break; + return lua.SyntaxKind.BitwiseLeftShiftOperator; case ts.SyntaxKind.GreaterThanGreaterThanToken: - bitFunction = "arshift"; - break; - default: - throw UnsupportedKind("binary bitwise operator", operator, node); + context.diagnostics.push(unsupportedRightShiftOperator(node)); + case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return lua.SyntaxKind.BitwiseRightShiftOperator; } - - return lua.createCallExpression( - lua.createTableIndexExpression(lua.createIdentifier(lib), lua.createStringLiteral(bitFunction)), - [left, right], - node - ); } export function transformBinaryBitOperation( @@ -53,16 +63,15 @@ export function transformBinaryBitOperation( ): lua.Expression { switch (context.luaTarget) { case LuaTarget.Lua51: - throw UnsupportedForTarget("Bitwise operations", LuaTarget.Lua51, node); - - case LuaTarget.Lua52: - return transformBinaryBitLibOperation(node, left, right, operator, "bit32"); + context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", LuaTarget.Lua51)); case LuaTarget.LuaJIT: return transformBinaryBitLibOperation(node, left, right, operator, "bit"); + case LuaTarget.Lua52: + return transformBinaryBitLibOperation(node, left, right, operator, "bit32"); default: - const luaOperator = transformBinaryOperator(context, node, operator); + const luaOperator = transformBitOperatorToLuaOperator(context, node, operator); return lua.createBinaryExpression(left, right, luaOperator, node); } } @@ -79,7 +88,7 @@ function transformUnaryBitLibOperation( bitFunction = "bnot"; break; default: - throw UnsupportedKind("unary bitwise operator", operator, node); + assertNever(operator); } return lua.createCallExpression( @@ -97,14 +106,14 @@ export function transformUnaryBitOperation( ): lua.Expression { switch (context.luaTarget) { case LuaTarget.Lua51: - throw UnsupportedForTarget("Bitwise operations", LuaTarget.Lua51, node); - - case LuaTarget.Lua52: - return transformUnaryBitLibOperation(node, expression, operator, "bit32"); + context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", LuaTarget.Lua51)); case LuaTarget.LuaJIT: return transformUnaryBitLibOperation(node, expression, operator, "bit"); + case LuaTarget.Lua52: + return transformUnaryBitLibOperation(node, expression, operator, "bit32"); + default: return lua.createUnaryExpression(expression, operator, node); } diff --git a/src/transformation/visitors/binary-expression/compound.ts b/src/transformation/visitors/binary-expression/compound.ts index c7ab11cdc..0eec44875 100644 --- a/src/transformation/visitors/binary-expression/compound.ts +++ b/src/transformation/visitors/binary-expression/compound.ts @@ -33,7 +33,22 @@ export function parseAccessExpressionWithEvaluationEffects( return []; } -const compoundToAssignmentTokens: Record = { +// TODO: `as const` doesn't work on enum members +type CompoundAssignmentToken = + | ts.SyntaxKind.BarToken + | ts.SyntaxKind.PlusToken + | ts.SyntaxKind.CaretToken + | ts.SyntaxKind.MinusToken + | ts.SyntaxKind.SlashToken + | ts.SyntaxKind.PercentToken + | ts.SyntaxKind.AsteriskToken + | ts.SyntaxKind.AmpersandToken + | ts.SyntaxKind.AsteriskAsteriskToken + | ts.SyntaxKind.LessThanLessThanToken + | ts.SyntaxKind.GreaterThanGreaterThanToken + | ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + +const compoundToAssignmentTokens: Record = { [ts.SyntaxKind.BarEqualsToken]: ts.SyntaxKind.BarToken, [ts.SyntaxKind.PlusEqualsToken]: ts.SyntaxKind.PlusToken, [ts.SyntaxKind.CaretEqualsToken]: ts.SyntaxKind.CaretToken, @@ -51,7 +66,7 @@ const compoundToAssignmentTokens: Record token in compoundToAssignmentTokens; -export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator) => +export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator): CompoundAssignmentToken => compoundToAssignmentTokens[token]; export function transformCompoundAssignmentExpression( @@ -60,7 +75,7 @@ export function transformCompoundAssignmentExpression( // TODO: Change type to ts.LeftHandSideExpression? lhs: ts.Expression, rhs: ts.Expression, - replacementOperator: ts.BinaryOperator, + operator: CompoundAssignmentToken, isPostfix: boolean ): lua.CallExpression { const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); @@ -85,18 +100,12 @@ export function transformCompoundAssignmentExpression( // local ____tmp = ____obj[____index]; // ____obj[____index] = ____tmp ${replacementOperator} ${right}; tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression); - const operatorExpression = transformBinaryOperation(context, tmp, right, replacementOperator, expression); + const operatorExpression = transformBinaryOperation(context, tmp, right, operator, expression); assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); } else { // local ____tmp = ____obj[____index] ${replacementOperator} ${right}; // ____obj[____index] = ____tmp; - const operatorExpression = transformBinaryOperation( - context, - accessExpression, - right, - replacementOperator, - expression - ); + const operatorExpression = transformBinaryOperation(context, accessExpression, right, operator, expression); tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression); assignStatement = lua.createAssignmentStatement(accessExpression, tmp); } @@ -113,13 +122,7 @@ export function transformCompoundAssignmentExpression( // return ____tmp const tmpIdentifier = lua.createIdentifier("____tmp"); const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, left); - const operatorExpression = transformBinaryOperation( - context, - tmpIdentifier, - right, - replacementOperator, - expression - ); + const operatorExpression = transformBinaryOperation(context, tmpIdentifier, right, operator, expression); const assignStatements = transformAssignment(context, lhs, operatorExpression); return createImmediatelyInvokedFunctionExpression( [tmpDeclaration, ...assignStatements], @@ -132,7 +135,7 @@ export function transformCompoundAssignmentExpression( // ${left} = ____tmp; // return ____tmp const tmpIdentifier = lua.createIdentifier("____tmp"); - const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, expression); + const operatorExpression = transformBinaryOperation(context, left, right, operator, expression); const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); const assignStatements = transformAssignment(context, lhs, tmpIdentifier); return createImmediatelyInvokedFunctionExpression( @@ -143,7 +146,7 @@ export function transformCompoundAssignmentExpression( } else { // Simple expressions // ${left} = ${right}; return ${right} - const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, expression); + const operatorExpression = transformBinaryOperation(context, left, right, operator, expression); const assignStatements = transformAssignment(context, lhs, operatorExpression); return createImmediatelyInvokedFunctionExpression(assignStatements, left, expression); } @@ -154,7 +157,7 @@ export function transformCompoundAssignmentStatement( node: ts.Node, lhs: ts.Expression, rhs: ts.Expression, - replacementOperator: ts.BinaryOperator + operator: CompoundAssignmentToken ): lua.Statement[] { const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); const right = context.transformExpression(rhs); @@ -171,20 +174,13 @@ export function transformCompoundAssignmentStatement( [context.transformExpression(objExpression), context.transformExpression(indexExpression)] ); const accessExpression = lua.createTableIndexExpression(obj, index); - const operatorExpression = transformBinaryOperation( - context, - accessExpression, - right, - replacementOperator, - node - ); + const operatorExpression = transformBinaryOperation(context, accessExpression, right, operator, node); const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); return [objAndIndexDeclaration, assignStatement]; } else { // Simple statements // ${left} = ${left} ${replacementOperator} ${right} - const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, node); - const assignmentStatements = transformAssignment(context, lhs, operatorExpression); - return assignmentStatements; + const operatorExpression = transformBinaryOperation(context, left, right, operator, node); + return transformAssignment(context, lhs, operatorExpression); } } diff --git a/src/transformation/visitors/binary-expression/destructuring-assignments.ts b/src/transformation/visitors/binary-expression/destructuring-assignments.ts index e255cbf70..567de4e6f 100644 --- a/src/transformation/visitors/binary-expression/destructuring-assignments.ts +++ b/src/transformation/visitors/binary-expression/destructuring-assignments.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; +import { assertNever } from "../../../utils"; import { TransformationContext } from "../../context"; -import { UnsupportedKind } from "../../utils/errors"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { isArrayType, isAssignmentPattern } from "../../utils/typescript"; import { transformPropertyName } from "../literal"; @@ -113,7 +113,10 @@ function transformArrayLiteralAssignmentPattern( case ts.SyntaxKind.ElementAccessExpression: return transformAssignment(context, element, indexedRoot); case ts.SyntaxKind.SpreadElement: - if (index !== node.elements.length - 1) return []; + if (index !== node.elements.length - 1) { + // TypeScript error + return []; + } const restElements = transformLuaLibFunction( context, @@ -127,7 +130,8 @@ function transformArrayLiteralAssignmentPattern( case ts.SyntaxKind.OmittedExpression: return []; default: - throw UnsupportedKind("Array Destructure Assignment Element", element.kind, element); + // TypeScript error + return []; } }); } @@ -150,8 +154,13 @@ function transformObjectLiteralAssignmentPattern( case ts.SyntaxKind.SpreadAssignment: result.push(...transformSpreadAssignment(context, property, root, node.properties)); break; + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.SetAccessor: + // TypeScript error + break; default: - throw UnsupportedKind("Object Destructure Property", property.kind, property); + assertNever(property); } } diff --git a/src/transformation/visitors/binary-expression/index.ts b/src/transformation/visitors/binary-expression/index.ts index d810adcf3..bbddf2eff 100644 --- a/src/transformation/visitors/binary-expression/index.ts +++ b/src/transformation/visitors/binary-expression/index.ts @@ -2,13 +2,17 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { InvalidInstanceOfExtension, InvalidInstanceOfLuaTable, UnsupportedKind } from "../../utils/errors"; +import { + extensionInvalidInstanceOf, + luaTableInvalidInstanceOf, + unsupportedNullishCoalescing, +} from "../../utils/diagnostics"; import { createImmediatelyInvokedFunctionExpression, wrapInToStringForConcat } from "../../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { isStandardLibraryType, isStringType } from "../../utils/typescript"; import { transformTypeOfBinaryExpression } from "../typeof"; import { transformAssignmentExpression, transformAssignmentStatement } from "./assignments"; -import { transformBinaryBitOperation } from "./bit"; +import { BitOperator, isBitOperator, transformBinaryBitOperation } from "./bit"; import { isCompoundAssignmentToken, transformCompoundAssignmentExpression, @@ -16,105 +20,66 @@ import { unwrapCompoundAssignmentToken, } from "./compound"; -export function transformBinaryOperator( - context: TransformationContext, - node: ts.Node, - operator: ts.BinaryOperator -): lua.BinaryOperator { - switch (operator) { - // Bitwise operators - case ts.SyntaxKind.BarToken: - return lua.SyntaxKind.BitwiseOrOperator; - case ts.SyntaxKind.CaretToken: - return lua.SyntaxKind.BitwiseExclusiveOrOperator; - case ts.SyntaxKind.AmpersandToken: - return lua.SyntaxKind.BitwiseAndOperator; - case ts.SyntaxKind.LessThanLessThanToken: - return lua.SyntaxKind.BitwiseLeftShiftOperator; - case ts.SyntaxKind.GreaterThanGreaterThanToken: - throw UnsupportedKind("right shift operator (use >>> instead)", operator, node); - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - return lua.SyntaxKind.BitwiseRightShiftOperator; - // Regular operators - case ts.SyntaxKind.AmpersandAmpersandToken: - return lua.SyntaxKind.AndOperator; - case ts.SyntaxKind.BarBarToken: - return lua.SyntaxKind.OrOperator; - case ts.SyntaxKind.MinusToken: - return lua.SyntaxKind.SubtractionOperator; - case ts.SyntaxKind.PlusToken: - if (ts.isBinaryExpression(node)) { - // Check is we need to use string concat operator - const typeLeft = context.checker.getTypeAtLocation(node.left); - const typeRight = context.checker.getTypeAtLocation(node.right); - if (isStringType(context, typeLeft) || isStringType(context, typeRight)) { - return lua.SyntaxKind.ConcatOperator; - } - } - - return lua.SyntaxKind.AdditionOperator; - case ts.SyntaxKind.AsteriskToken: - return lua.SyntaxKind.MultiplicationOperator; - case ts.SyntaxKind.AsteriskAsteriskToken: - return lua.SyntaxKind.PowerOperator; - case ts.SyntaxKind.SlashToken: - return lua.SyntaxKind.DivisionOperator; - case ts.SyntaxKind.PercentToken: - return lua.SyntaxKind.ModuloOperator; - case ts.SyntaxKind.GreaterThanToken: - return lua.SyntaxKind.GreaterThanOperator; - case ts.SyntaxKind.GreaterThanEqualsToken: - return lua.SyntaxKind.GreaterEqualOperator; - case ts.SyntaxKind.LessThanToken: - return lua.SyntaxKind.LessThanOperator; - case ts.SyntaxKind.LessThanEqualsToken: - return lua.SyntaxKind.LessEqualOperator; - case ts.SyntaxKind.EqualsEqualsToken: - case ts.SyntaxKind.EqualsEqualsEqualsToken: - return lua.SyntaxKind.EqualityOperator; - case ts.SyntaxKind.ExclamationEqualsToken: - case ts.SyntaxKind.ExclamationEqualsEqualsToken: - return lua.SyntaxKind.InequalityOperator; - default: - throw UnsupportedKind("binary operator", operator, node); - } -} +type SimpleOperator = + | ts.AdditiveOperatorOrHigher + | Exclude + | ts.EqualityOperator + | ts.LogicalOperator; + +const simpleOperatorsToLua: Record = { + [ts.SyntaxKind.AmpersandAmpersandToken]: lua.SyntaxKind.AndOperator, + [ts.SyntaxKind.BarBarToken]: lua.SyntaxKind.OrOperator, + [ts.SyntaxKind.PlusToken]: lua.SyntaxKind.AdditionOperator, + [ts.SyntaxKind.MinusToken]: lua.SyntaxKind.SubtractionOperator, + [ts.SyntaxKind.AsteriskToken]: lua.SyntaxKind.MultiplicationOperator, + [ts.SyntaxKind.AsteriskAsteriskToken]: lua.SyntaxKind.PowerOperator, + [ts.SyntaxKind.SlashToken]: lua.SyntaxKind.DivisionOperator, + [ts.SyntaxKind.PercentToken]: lua.SyntaxKind.ModuloOperator, + [ts.SyntaxKind.GreaterThanToken]: lua.SyntaxKind.GreaterThanOperator, + [ts.SyntaxKind.GreaterThanEqualsToken]: lua.SyntaxKind.GreaterEqualOperator, + [ts.SyntaxKind.LessThanToken]: lua.SyntaxKind.LessThanOperator, + [ts.SyntaxKind.LessThanEqualsToken]: lua.SyntaxKind.LessEqualOperator, + [ts.SyntaxKind.EqualsEqualsToken]: lua.SyntaxKind.EqualityOperator, + [ts.SyntaxKind.EqualsEqualsEqualsToken]: lua.SyntaxKind.EqualityOperator, + [ts.SyntaxKind.ExclamationEqualsToken]: lua.SyntaxKind.InequalityOperator, + [ts.SyntaxKind.ExclamationEqualsEqualsToken]: lua.SyntaxKind.InequalityOperator, +}; export function transformBinaryOperation( context: TransformationContext, left: lua.Expression, right: lua.Expression, - operator: ts.BinaryOperator, - tsOriginal: ts.Node + operator: BitOperator | SimpleOperator, + node: ts.Node ): lua.Expression { - switch (operator) { - case ts.SyntaxKind.AmpersandToken: - case ts.SyntaxKind.BarToken: - case ts.SyntaxKind.CaretToken: - case ts.SyntaxKind.LessThanLessThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - return transformBinaryBitOperation(context, tsOriginal, left, right, operator); - default: - const luaOperator = transformBinaryOperator(context, tsOriginal, operator); - if (luaOperator === lua.SyntaxKind.ConcatOperator) { - left = wrapInToStringForConcat(left); - right = wrapInToStringForConcat(right); - } + if (isBitOperator(operator)) { + return transformBinaryBitOperation(context, node, left, right, operator); + } - return lua.createBinaryExpression(left, right, luaOperator, tsOriginal); + let luaOperator = simpleOperatorsToLua[operator]; + + // Check if we need to use string concat operator + if (operator === ts.SyntaxKind.PlusToken && ts.isBinaryExpression(node)) { + const typeLeft = context.checker.getTypeAtLocation(node.left); + const typeRight = context.checker.getTypeAtLocation(node.right); + if (isStringType(context, typeLeft) || isStringType(context, typeRight)) { + left = wrapInToStringForConcat(left); + right = wrapInToStringForConcat(right); + luaOperator = lua.SyntaxKind.ConcatOperator; + } } + + return lua.createBinaryExpression(left, right, luaOperator, node); } export const transformBinaryExpression: FunctionVisitor = (node, context) => { + const operator = node.operatorToken.kind; + const typeOfResult = transformTypeOfBinaryExpression(context, node); if (typeOfResult) { return typeOfResult; } - const operator = node.operatorToken.kind; - - // Check if this is an assignment token, then handle accordingly if (isCompoundAssignmentToken(operator)) { return transformCompoundAssignmentExpression( context, @@ -126,39 +91,7 @@ export const transformBinaryExpression: FunctionVisitor = ( ); } - // Transpile operators switch (operator) { - case ts.SyntaxKind.AmpersandToken: - case ts.SyntaxKind.BarToken: - case ts.SyntaxKind.CaretToken: - case ts.SyntaxKind.LessThanLessThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - case ts.SyntaxKind.PlusToken: - case ts.SyntaxKind.AmpersandAmpersandToken: - case ts.SyntaxKind.BarBarToken: - case ts.SyntaxKind.MinusToken: - case ts.SyntaxKind.AsteriskToken: - case ts.SyntaxKind.AsteriskAsteriskToken: - case ts.SyntaxKind.SlashToken: - case ts.SyntaxKind.PercentToken: - - case ts.SyntaxKind.GreaterThanToken: - case ts.SyntaxKind.GreaterThanEqualsToken: - case ts.SyntaxKind.LessThanToken: - case ts.SyntaxKind.LessThanEqualsToken: - case ts.SyntaxKind.EqualsEqualsToken: - case ts.SyntaxKind.EqualsEqualsEqualsToken: - case ts.SyntaxKind.ExclamationEqualsToken: - case ts.SyntaxKind.ExclamationEqualsEqualsToken: - return transformBinaryOperation( - context, - context.transformExpression(node.left), - context.transformExpression(node.right), - operator, - node - ); - case ts.SyntaxKind.EqualsToken: return transformAssignmentExpression(context, node as ts.AssignmentExpression); @@ -181,12 +114,11 @@ export const transformBinaryExpression: FunctionVisitor = ( const annotations = getTypeAnnotations(rhsType); if (annotations.has(AnnotationKind.Extension) || annotations.has(AnnotationKind.MetaExtension)) { - // Cannot use instanceof on extension classes - throw InvalidInstanceOfExtension(node); + context.diagnostics.push(extensionInvalidInstanceOf(node)); } if (annotations.has(AnnotationKind.LuaTable)) { - throw InvalidInstanceOfLuaTable(node); + context.diagnostics.push(luaTableInvalidInstanceOf(node)); } if (isStandardLibraryType(context, rhsType, "ObjectConstructor")) { @@ -197,16 +129,31 @@ export const transformBinaryExpression: FunctionVisitor = ( } case ts.SyntaxKind.CommaToken: { - const rhs = context.transformExpression(node.right); return createImmediatelyInvokedFunctionExpression( context.transformStatements(ts.createExpressionStatement(node.left)), - rhs, + context.transformExpression(node.right), + node + ); + } + + case ts.SyntaxKind.QuestionQuestionToken: { + context.diagnostics.push(unsupportedNullishCoalescing(node.operatorToken)); + return lua.createBinaryExpression( + context.transformExpression(node.left), + context.transformExpression(node.right), + lua.SyntaxKind.OrOperator, node ); } default: - throw UnsupportedKind("binary operator", operator, node); + return transformBinaryOperation( + context, + context.transformExpression(node.left), + context.transformExpression(node.right), + operator, + node + ); } }; @@ -215,27 +162,26 @@ export function transformBinaryExpressionStatement( node: ts.ExpressionStatement ): lua.Statement[] | lua.Statement | undefined { const { expression } = node; - if (ts.isBinaryExpression(expression)) { - const operator = expression.operatorToken.kind; + if (!ts.isBinaryExpression(expression)) return; + const operator = expression.operatorToken.kind; - if (isCompoundAssignmentToken(operator)) { - // +=, -=, etc... - return transformCompoundAssignmentStatement( - context, - expression, - expression.left, - expression.right, - unwrapCompoundAssignmentToken(operator) - ); - } else if (operator === ts.SyntaxKind.EqualsToken) { - return transformAssignmentStatement(context, expression as ts.AssignmentExpression); - } else if (operator === ts.SyntaxKind.CommaToken) { - const statements = [ - ...context.transformStatements(ts.createExpressionStatement(expression.left)), - ...context.transformStatements(ts.createExpressionStatement(expression.right)), - ]; - - return lua.createDoStatement(statements, expression); - } + if (isCompoundAssignmentToken(operator)) { + // +=, -=, etc... + return transformCompoundAssignmentStatement( + context, + expression, + expression.left, + expression.right, + unwrapCompoundAssignmentToken(operator) + ); + } else if (operator === ts.SyntaxKind.EqualsToken) { + return transformAssignmentStatement(context, expression as ts.AssignmentExpression); + } else if (operator === ts.SyntaxKind.CommaToken) { + const statements = [ + ...context.transformStatements(ts.createExpressionStatement(expression.left)), + ...context.transformStatements(ts.createExpressionStatement(expression.right)), + ]; + + return lua.createDoStatement(statements, expression); } } diff --git a/src/transformation/visitors/break-continue.ts b/src/transformation/visitors/break-continue.ts index 49ead1ff6..bde4ddd52 100644 --- a/src/transformation/visitors/break-continue.ts +++ b/src/transformation/visitors/break-continue.ts @@ -2,16 +2,12 @@ import * as ts from "typescript"; import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; -import { UndefinedScope, UnsupportedForTarget } from "../utils/errors"; +import { unsupportedForTarget } from "../utils/diagnostics"; import { findScope, ScopeType } from "../utils/scope"; export const transformBreakStatement: FunctionVisitor = (breakStatement, context) => { const breakableScope = findScope(context, ScopeType.Loop | ScopeType.Switch); - if (breakableScope === undefined) { - throw UndefinedScope(); - } - - if (breakableScope.type === ScopeType.Switch) { + if (breakableScope?.type === ScopeType.Switch) { return lua.createGotoStatement(`____switch${breakableScope.id}_end`); } else { return lua.createBreakStatement(breakStatement); @@ -20,14 +16,14 @@ export const transformBreakStatement: FunctionVisitor = (brea export const transformContinueStatement: FunctionVisitor = (statement, context) => { if (context.luaTarget === LuaTarget.Lua51) { - throw UnsupportedForTarget("Continue statement", LuaTarget.Lua51, statement); + context.diagnostics.push(unsupportedForTarget(statement, "Continue statement", LuaTarget.Lua51)); } const scope = findScope(context, ScopeType.Loop); - if (scope === undefined) { - throw UndefinedScope(); + + if (scope) { + scope.loopContinued = true; } - scope.loopContinued = true; - return lua.createGotoStatement(`__continue${scope.id}`, statement); + return lua.createGotoStatement(`__continue${scope?.id ?? ""}`, statement); }; diff --git a/src/transformation/visitors/call.ts b/src/transformation/visitors/call.ts index 75e2a95b2..d7e339f2b 100644 --- a/src/transformation/visitors/call.ts +++ b/src/transformation/visitors/call.ts @@ -4,11 +4,10 @@ import { transformBuiltinCallExpression } from "../builtins"; import { FunctionVisitor, TransformationContext } from "../context"; import { isInTupleReturnFunction, isTupleReturnCall, isVarArgType } from "../utils/annotations"; import { validateAssignment } from "../utils/assignment-validation"; -import { UnsupportedKind } from "../utils/errors"; import { ContextType, getDeclarationContextType } from "../utils/function-context"; import { createImmediatelyInvokedFunctionExpression, createUnpackCall, wrapInTable } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { isValidLuaIdentifier, luaKeywords } from "../utils/safe-names"; +import { isValidLuaIdentifier } from "../utils/safe-names"; import { isArrayType, isExpressionWithEvaluationEffect, isInDestructingAssignment } from "../utils/typescript"; import { transformElementAccessArgument } from "./access"; import { transformIdentifier } from "./identifier"; @@ -47,12 +46,7 @@ export function transformContextualCallExpression( transformedArguments: lua.Expression[] ): lua.Expression { const left = ts.isCallExpression(node) ? node.expression : node.tag; - if ( - ts.isPropertyAccessExpression(left) && - ts.isIdentifier(left.name) && - !luaKeywords.has(left.name.text) && - isValidLuaIdentifier(left.name.text) - ) { + if (ts.isPropertyAccessExpression(left) && ts.isIdentifier(left.name) && isValidLuaIdentifier(left.name.text)) { // table:name() const table = context.transformExpression(left.expression); @@ -88,7 +82,7 @@ export function transformContextualCallExpression( const expression = context.transformExpression(left); return lua.createCallExpression(expression, transformedArguments, node); } else { - throw UnsupportedKind("Left Hand Side Call Expression", left.kind, left); + throw new Error(`Unsupported LeftHandSideExpression kind: ${ts.SyntaxKind[left.kind]}`); } } diff --git a/src/transformation/visitors/class/decorators.ts b/src/transformation/visitors/class/decorators.ts index 5c8406209..5cae0cf17 100644 --- a/src/transformation/visitors/class/decorators.ts +++ b/src/transformation/visitors/class/decorators.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; -import { InvalidDecoratorContext } from "../../utils/errors"; +import { decoratorInvalidContext } from "../../utils/diagnostics"; import { addExportToIdentifier } from "../../utils/export"; import { ContextType, getFunctionContextType } from "../../utils/function-context"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; @@ -26,7 +26,7 @@ export function createConstructorDecorationStatement( const type = context.checker.getTypeAtLocation(expression); const callContext = getFunctionContextType(context, type); if (callContext === ContextType.Void) { - throw InvalidDecoratorContext(decorator); + context.diagnostics.push(decoratorInvalidContext(decorator)); } return context.transformExpression(expression); diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index bf11c8748..33024923e 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -4,15 +4,13 @@ import { getOrUpdate, isNonNull } from "../../../utils"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; import { - ForbiddenLuaTableNonDeclaration, - InvalidExportsExtension, - InvalidExtendsExtension, - InvalidExtendsLuaTable, - InvalidExtensionMetaExtension, - MissingClassName, - MissingMetaExtension, - UnknownSuperType, -} from "../../utils/errors"; + extensionAndMetaExtensionConflict, + extensionCannotExport, + extensionCannotExtend, + metaExtensionMissingExtends, + luaTableMustBeAmbient, + luaTableCannotBeExtended, +} from "../../utils/diagnostics"; import { createDefaultExportIdentifier, createExportedIdentifier, @@ -61,16 +59,17 @@ export function transformClassAsExpression( return createImmediatelyInvokedFunctionExpression(classDeclaration, className, expression); } -const classStacks = new WeakMap(); +const classSuperInfos = new WeakMap(); +interface ClassSuperInfo { + className: lua.Identifier; + extendedTypeNode?: ts.ExpressionWithTypeArguments; +} export function transformClassDeclaration( classDeclaration: ts.ClassLikeDeclaration, context: TransformationContext, nameOverride?: lua.Identifier ): OneToManyVisitorResult { - const classStack = getOrUpdate(classStacks, context, () => []); - classStack.push(classDeclaration); - let className: lua.Identifier; let classNameText: string; if (nameOverride !== undefined) { @@ -85,7 +84,9 @@ export function transformClassDeclaration( return lua.createAssignmentStatement(left, right, classDeclaration); } else { - throw MissingClassName(classDeclaration); + // TypeScript error + className = lua.createAnonymousIdentifier(); + classNameText = className.text; } const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(classDeclaration)); @@ -96,17 +97,21 @@ export function transformClassDeclaration( const isMetaExtension = annotations.has(AnnotationKind.MetaExtension); if (isExtension && isMetaExtension) { - throw InvalidExtensionMetaExtension(classDeclaration); + context.diagnostics.push(extensionAndMetaExtensionConflict(classDeclaration)); } if ((isExtension || isMetaExtension) && getIdentifierExportScope(context, className) !== undefined) { // Cannot export extension classes - throw InvalidExportsExtension(classDeclaration); + context.diagnostics.push(extensionCannotExport(classDeclaration)); } // Get type that is extended + const extendedTypeNode = getExtendedNode(context, classDeclaration); const extendedType = getExtendedType(context, classDeclaration); + const superInfo = getOrUpdate(classSuperInfos, context, () => []); + superInfo.push({ className, extendedTypeNode }); + if (extendedType) { checkForLuaLibType(context, extendedType); } @@ -115,7 +120,7 @@ export function transformClassDeclaration( // Non-extensions cannot extend extension classes const extendsAnnotations = getTypeAnnotations(extendedType); if (extendsAnnotations.has(AnnotationKind.Extension) || extendsAnnotations.has(AnnotationKind.MetaExtension)) { - throw InvalidExtendsExtension(classDeclaration); + context.diagnostics.push(extensionCannotExtend(classDeclaration)); } } @@ -123,13 +128,12 @@ export function transformClassDeclaration( if (extendedType) { const annotations = getTypeAnnotations(extendedType); if (annotations.has(AnnotationKind.LuaTable)) { - throw InvalidExtendsLuaTable(classDeclaration); + context.diagnostics.push(luaTableCannotBeExtended(extendedTypeNode!)); } } - // LuaTable classes must be ambient if (annotations.has(AnnotationKind.LuaTable) && !isAmbientNode(classDeclaration)) { - throw ForbiddenLuaTableNonDeclaration(classDeclaration); + context.diagnostics.push(luaTableMustBeAmbient(classDeclaration)); } // Get all properties with value @@ -143,30 +147,30 @@ export function transformClassDeclaration( // Overwrite the original className with the class we are overriding for extensions if (isMetaExtension) { - if (!extendedType) { - throw MissingMetaExtension(classDeclaration); - } - - const extendsName = lua.createStringLiteral(extendedType.symbol.name as string); - className = lua.createIdentifier("__meta__" + extendsName.value); - - // local className = debug.getregistry()["extendsName"] - const assignDebugCallIndex = lua.createVariableDeclarationStatement( - className, - lua.createTableIndexExpression( - lua.createCallExpression( - lua.createTableIndexExpression( - lua.createIdentifier("debug"), - lua.createStringLiteral("getregistry") + if (extendedType) { + const extendsName = lua.createStringLiteral(extendedType.symbol.name); + className = lua.createIdentifier("__meta__" + extendsName.value); + + // local className = debug.getregistry()["extendsName"] + const assignDebugCallIndex = lua.createVariableDeclarationStatement( + className, + lua.createTableIndexExpression( + lua.createCallExpression( + lua.createTableIndexExpression( + lua.createIdentifier("debug"), + lua.createStringLiteral("getregistry") + ), + [] ), - [] + extendsName ), - extendsName - ), - classDeclaration - ); + classDeclaration + ); - result.push(assignDebugCallIndex); + result.push(assignDebugCallIndex); + } else { + context.diagnostics.push(metaExtensionMissingExtends(classDeclaration)); + } } if (extensionDirective !== undefined) { @@ -312,23 +316,22 @@ export function transformClassDeclaration( result.push(decorationStatement); } - classStack.pop(); + superInfo.pop(); return result; } export const transformSuperExpression: FunctionVisitor = (expression, context) => { - const classStack = getOrUpdate(classStacks, context, () => []); - const classDeclaration = classStack[classStack.length - 1]; - const extendedNode = getExtendedNode(context, classDeclaration); - if (extendedNode === undefined) { - throw UnknownSuperType(expression); - } + const superInfos = getOrUpdate(classSuperInfos, context, () => []); + const superInfo = superInfos[superInfos.length - 1]; + if (!superInfo) return lua.createAnonymousIdentifier(expression); + const { className, extendedTypeNode } = superInfo; - const extendsExpression = extendedNode.expression; + // Using `super` without extended type node is a TypeScript error + const extendsExpression = extendedTypeNode?.expression; let baseClassName: lua.AssignmentLeftHandSideExpression | undefined; - if (ts.isIdentifier(extendsExpression)) { + if (extendsExpression && ts.isIdentifier(extendsExpression)) { const symbol = context.checker.getSymbolAtLocation(extendsExpression); if (symbol && !isSymbolExported(context, symbol)) { // Use "baseClassName" if base is a simple identifier @@ -337,16 +340,8 @@ export const transformSuperExpression: FunctionVisitor = (ex } if (!baseClassName) { - if (classDeclaration.name === undefined) { - throw MissingClassName(expression); - } - // Use "className.____super" if the base is not a simple identifier - baseClassName = lua.createTableIndexExpression( - transformIdentifier(context, classDeclaration.name), - lua.createStringLiteral("____super"), - expression - ); + baseClassName = lua.createTableIndexExpression(className, lua.createStringLiteral("____super"), expression); } return lua.createTableIndexExpression(baseClassName, lua.createStringLiteral("prototype")); diff --git a/src/transformation/visitors/class/new.ts b/src/transformation/visitors/class/new.ts index d1181a284..da1c2f124 100644 --- a/src/transformation/visitors/class/new.ts +++ b/src/transformation/visitors/class/new.ts @@ -2,7 +2,7 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { InvalidAnnotationArgumentNumber, InvalidNewExpressionOnExtension } from "../../utils/errors"; +import { annotationInvalidArgumentCount, extensionCannotConstruct } from "../../utils/diagnostics"; import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { transformArguments } from "../call"; import { transformLuaTableNewExpression } from "../lua-table"; @@ -66,20 +66,27 @@ export const transformNewExpression: FunctionVisitor = (node, const annotations = getTypeAnnotations(type); if (annotations.has(AnnotationKind.Extension) || annotations.has(AnnotationKind.MetaExtension)) { - throw InvalidNewExpressionOnExtension(node); + context.diagnostics.push(extensionCannotConstruct(node)); } const customConstructorAnnotation = annotations.get(AnnotationKind.CustomConstructor); if (customConstructorAnnotation) { - if (customConstructorAnnotation.args[0] === undefined) { - throw InvalidAnnotationArgumentNumber("@customConstructor", 0, 1, node); + if (customConstructorAnnotation.args.length === 1) { + return lua.createCallExpression( + lua.createIdentifier(customConstructorAnnotation.args[0]), + transformArguments(context, node.arguments ?? []), + node + ); + } else { + context.diagnostics.push( + annotationInvalidArgumentCount( + node, + AnnotationKind.CustomConstructor, + customConstructorAnnotation.args.length, + 1 + ) + ); } - - return lua.createCallExpression( - lua.createIdentifier(customConstructorAnnotation.args[0]), - transformArguments(context, node.arguments ?? []), - node - ); } return transformLuaLibFunction(context, LuaLibFeature.New, node, name, ...params); diff --git a/src/transformation/visitors/class/setup.ts b/src/transformation/visitors/class/setup.ts index 3aec046a3..a4ffc5c75 100644 --- a/src/transformation/visitors/class/setup.ts +++ b/src/transformation/visitors/class/setup.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; +import { assert } from "../../../utils"; import { TransformationContext } from "../../context"; -import { UndefinedTypeNode } from "../../utils/errors"; import { createDefaultExportStringLiteral, createExportedIdentifier, @@ -63,10 +63,7 @@ export function createClassSetup( if (extendsType) { const extendedNode = getExtendedNode(context, statement); - if (extendedNode === undefined) { - throw UndefinedTypeNode(statement); - } - + assert(extendedNode); result.push( lua.createExpressionStatement( transformLuaLibFunction( diff --git a/src/transformation/visitors/function.ts b/src/transformation/visitors/function.ts index 1d81a0e45..005c63a5b 100644 --- a/src/transformation/visitors/function.ts +++ b/src/transformation/visitors/function.ts @@ -2,7 +2,6 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; import { isVarArgType } from "../utils/annotations"; -import { MissingFunctionName, UnsupportedFunctionWithoutBody } from "../utils/errors"; import { createDefaultExportStringLiteral, hasDefaultExportModifier } from "../utils/export"; import { ContextType, getFunctionContextType } from "../utils/function-context"; import { @@ -183,7 +182,8 @@ export function transformFunctionLikeDeclaration( let flags = lua.FunctionExpressionFlags.None; if (node.body === undefined) { - throw UnsupportedFunctionWithoutBody(node); + // This code can be reached only from object methods, which is TypeScript error + return lua.createNilLiteral(); } let body: ts.Block; @@ -257,18 +257,16 @@ export const transformFunctionDeclaration: FunctionVisitor = (statement, context) => { if (isArrayType(context, context.checker.getTypeAtLocation(statement.expression))) { - throw ForbiddenForIn(statement); + context.diagnostics.push(forbiddenForIn(statement)); } // Transpile expression @@ -19,33 +17,6 @@ export const transformForInStatement: FunctionVisitor = (stat const body = lua.createBlock(transformLoopBody(context, statement)); - // Transform iteration variable - // TODO: After the transformation pipeline refactor we should look at refactoring this together with the - // for-of initializer transformation. - let iterationVariable: lua.Identifier; - if (ts.isVariableDeclarationList(statement.initializer)) { - const binding = getVariableDeclarationBinding(statement.initializer); - if (!ts.isIdentifier(binding)) { - throw UnsupportedForInVariable(statement.initializer); - } - - iterationVariable = transformIdentifier(context, binding); - } else if (ts.isIdentifier(statement.initializer)) { - // Iteration variable becomes ____key - iterationVariable = lua.createIdentifier("____key"); - // Push variable = ____key to the start of the loop body to match TS scoping - const assignment = transformAssignment( - context, - statement.initializer, - iterationVariable, - statement.initializer - ); - - body.statements.unshift(...assignment); - } else { - // This should never occur - throw UnsupportedForInVariable(statement.initializer); - } - - return lua.createForInStatement(body, [iterationVariable], [pairsCall], statement); + const valueVariable = transformForInitializer(context, statement.initializer, body); + return lua.createForInStatement(body, [valueVariable], [pairsCall], statement); }; diff --git a/src/transformation/visitors/loops/for-of.ts b/src/transformation/visitors/loops/for-of.ts index 9c0596fb8..c682c042e 100644 --- a/src/transformation/visitors/loops/for-of.ts +++ b/src/transformation/visitors/loops/for-of.ts @@ -1,94 +1,65 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; -import { castEach } from "../../../utils"; +import { assert, castEach } from "../../../utils"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getTypeAnnotations, isForRangeType, isLuaIteratorType } from "../../utils/annotations"; -import { InvalidForRangeCall, MissingForOfVariables, UnsupportedNonDestructuringLuaIterator } from "../../utils/errors"; +import { invalidForRangeCall, luaIteratorForbiddenUsage } from "../../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; -import { isArrayType, isNumberType, isAssignmentPattern } from "../../utils/typescript"; +import { isArrayType, isNumberType } from "../../utils/typescript"; import { transformArguments } from "../call"; import { transformIdentifier } from "../identifier"; -import { - transformBindingPattern, - transformArrayBindingElement, - transformVariableDeclaration, -} from "../variable-declaration"; -import { getVariableDeclarationBinding, transformLoopBody } from "./utils"; -import { transformAssignment } from "../binary-expression/assignments"; -import { transformAssignmentPattern } from "../binary-expression/destructuring-assignments"; - -function transformForOfInitializer( - context: TransformationContext, - initializer: ts.ForInitializer, - expression: lua.Identifier -): lua.Statement[] { - if (ts.isVariableDeclarationList(initializer)) { - const binding = getVariableDeclarationBinding(initializer); - // Declaration of new variable - if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) { - return transformBindingPattern(context, binding, expression); - } - - const variableStatements = transformVariableDeclaration(context, initializer.declarations[0]); - if (variableStatements[0]) { - // we can safely assume that for vars are not exported and therefore declarationstatenents - return [ - lua.createVariableDeclarationStatement( - (variableStatements[0] as lua.VariableDeclarationStatement).left, - expression - ), - ]; - } else { - throw MissingForOfVariables(initializer); - } - } else { - // Assignment to existing variable(s) - - if (isAssignmentPattern(initializer)) { - return transformAssignmentPattern(context, initializer, expression); - } - - return transformAssignment(context, initializer, expression); - } -} +import { transformArrayBindingElement } from "../variable-declaration"; +import { getVariableDeclarationBinding, transformForInitializer, transformLoopBody } from "./utils"; function transformForRangeStatement( context: TransformationContext, statement: ts.ForOfStatement, block: lua.Block ): lua.Statement { - if (!ts.isCallExpression(statement.expression)) { - throw InvalidForRangeCall(statement.expression, "Expression must be a call expression."); - } + assert(ts.isCallExpression(statement.expression)); - if (statement.expression.arguments.length < 2 || statement.expression.arguments.length > 3) { - throw InvalidForRangeCall(statement.expression, "@forRange function must take 2 or 3 arguments."); + const callArguments = statement.expression.arguments; + if (callArguments.length !== 2 && callArguments.length !== 3) { + context.diagnostics.push( + invalidForRangeCall(statement.expression, `Expected 2-3 arguments, but got ${callArguments.length}`) + ); } if (statement.expression.arguments.some(a => !isNumberType(context, context.checker.getTypeAtLocation(a)))) { - throw InvalidForRangeCall(statement.expression, "@forRange arguments must be number types."); + context.diagnostics.push(invalidForRangeCall(statement.expression, "arguments must be numbers")); } - if (!ts.isVariableDeclarationList(statement.initializer)) { - throw InvalidForRangeCall(statement.initializer, "@forRange loop must declare its own control variable."); - } + const controlVariable = getControlVariable() ?? lua.createAnonymousIdentifier(); + function getControlVariable(): lua.Identifier | undefined { + if (!ts.isVariableDeclarationList(statement.initializer)) { + context.diagnostics.push( + invalidForRangeCall(statement.initializer, "loop must declare it's own control variable") + ); + return; + } - const binding = getVariableDeclarationBinding(statement.initializer); - if (!ts.isIdentifier(binding)) { - throw InvalidForRangeCall(statement.initializer, "@forRange loop cannot use destructuring."); - } + const binding = getVariableDeclarationBinding(context, statement.initializer); + if (!ts.isIdentifier(binding)) { + context.diagnostics.push(invalidForRangeCall(statement.initializer, "destructuring cannot be used")); + return; + } - if (!isNumberType(context, context.checker.getTypeAtLocation(binding))) { - throw InvalidForRangeCall( - statement.expression, - "@forRange function must return Iterable or Array." - ); + if (!isNumberType(context, context.checker.getTypeAtLocation(binding))) { + context.diagnostics.push( + invalidForRangeCall(statement.expression, "function must return Iterable") + ); + } + + return transformIdentifier(context, binding); } - const control = transformIdentifier(context, binding); - const signature = context.checker.getResolvedSignature(statement.expression); - const [start, limit, step] = transformArguments(context, statement.expression.arguments, signature); - return lua.createForStatement(block, control, start, limit, step, statement); + const [start = lua.createNumericLiteral(0), limit = lua.createNumericLiteral(0), step] = transformArguments( + context, + callArguments, + context.checker.getResolvedSignature(statement.expression) + ); + + return lua.createForStatement(block, controlVariable, start, limit, step, statement); } function transformForOfLuaIteratorStatement( @@ -99,72 +70,51 @@ function transformForOfLuaIteratorStatement( const luaIterator = context.transformExpression(statement.expression); const type = context.checker.getTypeAtLocation(statement.expression); const tupleReturn = getTypeAnnotations(type).has(AnnotationKind.TupleReturn); + let identifiers: lua.Identifier[] = []; + if (tupleReturn) { // LuaIterator + TupleReturn if (ts.isVariableDeclarationList(statement.initializer)) { // Variables declared in for loop // for ${initializer} in ${iterable} do - const binding = getVariableDeclarationBinding(statement.initializer); + const binding = getVariableDeclarationBinding(context, statement.initializer); + if (ts.isArrayBindingPattern(binding)) { - const identifiers = binding.elements.map(e => transformArrayBindingElement(context, e)); - if (identifiers.length === 0) { - identifiers.push(lua.createAnonymousIdentifier()); - } - return lua.createForInStatement(block, identifiers, [luaIterator]); + identifiers = binding.elements.map(e => transformArrayBindingElement(context, e)); } else { - // Single variable is not allowed - throw UnsupportedNonDestructuringLuaIterator(statement.initializer); + context.diagnostics.push(luaIteratorForbiddenUsage(binding)); } } else { // Variables NOT declared in for loop - catch iterator values in temps and assign // for ____value0 in ${iterable} do // ${initializer} = ____value0 if (ts.isArrayLiteralExpression(statement.initializer)) { - const tmps = statement.initializer.elements.map((_, i) => lua.createIdentifier(`____value${i}`)); - if (tmps.length > 0) { - const assign = lua.createAssignmentStatement( - castEach( - statement.initializer.elements.map(e => context.transformExpression(e)), - lua.isAssignmentLeftHandSideExpression - ), - tmps + identifiers = statement.initializer.elements.map((_, i) => lua.createIdentifier(`____value${i}`)); + if (identifiers.length > 0) { + block.statements.unshift( + lua.createAssignmentStatement( + castEach( + statement.initializer.elements.map(e => context.transformExpression(e)), + lua.isAssignmentLeftHandSideExpression + ), + identifiers + ) ); - block.statements.splice(0, 0, assign); - } else { - tmps.push(lua.createAnonymousIdentifier()); } - return lua.createForInStatement(block, tmps, [luaIterator]); } else { - // Single variable is not allowed - throw UnsupportedNonDestructuringLuaIterator(statement.initializer); + context.diagnostics.push(luaIteratorForbiddenUsage(statement.initializer)); } } } else { // LuaIterator (no TupleReturn) - if ( - ts.isVariableDeclarationList(statement.initializer) && - statement.initializer.declarations.length > 0 && - ts.isIdentifier(statement.initializer.declarations[0].name) - ) { - // Single variable declared in for loop - // for ${initializer} in ${iterator} do - return lua.createForInStatement( - block, - [transformIdentifier(context, statement.initializer.declarations[0].name)], - [luaIterator] - ); - } else { - // Destructuring or variable NOT declared in for loop - // for ____value in ${iterator} do - // local ${initializer} = unpack(____value) - const valueVariable = lua.createIdentifier("____value"); - const initializer = transformForOfInitializer(context, statement.initializer, valueVariable); - if (initializer) { - block.statements.splice(0, 0, ...initializer); - } - return lua.createForInStatement(block, [valueVariable], [luaIterator]); - } + identifiers.push(transformForInitializer(context, statement.initializer, block)); + } + + if (identifiers.length === 0) { + identifiers.push(lua.createAnonymousIdentifier()); } + + return lua.createForInStatement(block, identifiers, [luaIterator], statement); } function transformForOfArrayStatement( @@ -172,28 +122,7 @@ function transformForOfArrayStatement( statement: ts.ForOfStatement, block: lua.Block ): lua.Statement { - let valueVariable: lua.Identifier; - if (ts.isVariableDeclarationList(statement.initializer)) { - // Declaration of new variable - const binding = getVariableDeclarationBinding(statement.initializer); - if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) { - valueVariable = lua.createIdentifier("____values"); - const initializer = transformForOfInitializer(context, statement.initializer, valueVariable); - if (initializer) { - block.statements.unshift(...initializer); - } - } else { - valueVariable = transformIdentifier(context, binding); - } - } else { - // Assignment to existing variable - valueVariable = lua.createIdentifier("____value"); - const initializer = transformForOfInitializer(context, statement.initializer, valueVariable); - if (initializer) { - block.statements.unshift(...initializer); - } - } - + const valueVariable = transformForInitializer(context, statement.initializer, block); const ipairsCall = lua.createCallExpression(lua.createIdentifier("ipairs"), [ context.transformExpression(statement.expression), ]); @@ -206,35 +135,15 @@ function transformForOfIteratorStatement( statement: ts.ForOfStatement, block: lua.Block ): lua.Statement { - const iterable = context.transformExpression(statement.expression); - if ( - ts.isVariableDeclarationList(statement.initializer) && - statement.initializer.declarations.length > 0 && - ts.isIdentifier(statement.initializer.declarations[0].name) - ) { - // Single variable declared in for loop - // for ${initializer} in __TS__iterator(${iterator}) do - return lua.createForInStatement( - block, - [transformIdentifier(context, statement.initializer.declarations[0].name)], - [transformLuaLibFunction(context, LuaLibFeature.Iterator, statement.expression, iterable)] - ); - } else { - // Destructuring or variable NOT declared in for loop - // for ____value in __TS__iterator(${iterator}) do - // local ${initializer} = ____value - const valueVariable = lua.createIdentifier("____value"); - const initializer = transformForOfInitializer(context, statement.initializer, valueVariable); - if (initializer) { - block.statements.unshift(...initializer); - } - - return lua.createForInStatement( - block, - [valueVariable], - [transformLuaLibFunction(context, LuaLibFeature.Iterator, statement.expression, iterable)] - ); - } + const valueVariable = transformForInitializer(context, statement.initializer, block); + const iterable = transformLuaLibFunction( + context, + LuaLibFeature.Iterator, + statement.expression, + context.transformExpression(statement.expression) + ); + + return lua.createForInStatement(block, [valueVariable], [iterable], statement); } export const transformForOfStatement: FunctionVisitor = (node, context) => { diff --git a/src/transformation/visitors/loops/for.ts b/src/transformation/visitors/loops/for.ts index 970c2f045..f81a62199 100644 --- a/src/transformation/visitors/loops/for.ts +++ b/src/transformation/visitors/loops/for.ts @@ -9,7 +9,7 @@ export const transformForStatement: FunctionVisitor = (statemen if (statement.initializer) { if (ts.isVariableDeclarationList(statement.initializer)) { - checkVariableDeclarationList(statement.initializer); + checkVariableDeclarationList(context, statement.initializer); // local initializer = value result.push(...statement.initializer.declarations.flatMap(d => transformVariableDeclaration(context, d))); } else { diff --git a/src/transformation/visitors/loops/utils.ts b/src/transformation/visitors/loops/utils.ts index 639c0de95..8ee86f4ea 100644 --- a/src/transformation/visitors/loops/utils.ts +++ b/src/transformation/visitors/loops/utils.ts @@ -2,8 +2,12 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; import { performHoisting, popScope, pushScope, ScopeType } from "../../utils/scope"; +import { isAssignmentPattern } from "../../utils/typescript"; +import { transformAssignment } from "../binary-expression/assignments"; +import { transformAssignmentPattern } from "../binary-expression/destructuring-assignments"; import { transformBlockOrStatement } from "../block"; -import { checkVariableDeclarationList } from "../variable-declaration"; +import { transformIdentifier } from "../identifier"; +import { checkVariableDeclarationList, transformBindingPattern } from "../variable-declaration"; export function transformLoopBody( context: TransformationContext, @@ -25,8 +29,11 @@ export function transformLoopBody( return baseResult; } -export function getVariableDeclarationBinding(node: ts.VariableDeclarationList): ts.BindingName { - checkVariableDeclarationList(node); +export function getVariableDeclarationBinding( + context: TransformationContext, + node: ts.VariableDeclarationList +): ts.BindingName { + checkVariableDeclarationList(context, node); if (node.declarations.length === 0) { return ts.createIdentifier("____"); @@ -34,3 +41,33 @@ export function getVariableDeclarationBinding(node: ts.VariableDeclarationList): return node.declarations[0].name; } + +export function transformForInitializer( + context: TransformationContext, + initializer: ts.ForInitializer, + block: lua.Block +): lua.Identifier { + const valueVariable = lua.createIdentifier("____value"); + + if (ts.isVariableDeclarationList(initializer)) { + // Declaration of new variable + + const binding = getVariableDeclarationBinding(context, initializer); + if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) { + block.statements.unshift(...transformBindingPattern(context, binding, valueVariable)); + } else { + // Single variable declared in for loop + return transformIdentifier(context, binding); + } + } else { + // Assignment to existing variable(s) + + block.statements.unshift( + ...(isAssignmentPattern(initializer) + ? transformAssignmentPattern(context, initializer, valueVariable) + : transformAssignment(context, initializer, valueVariable)) + ); + } + + return valueVariable; +} diff --git a/src/transformation/visitors/lua-table.ts b/src/transformation/visitors/lua-table.ts index 471dba4e3..7647921c3 100644 --- a/src/transformation/visitors/lua-table.ts +++ b/src/transformation/visitors/lua-table.ts @@ -2,46 +2,58 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; -import { ForbiddenLuaTableUseException, UnsupportedKind, UnsupportedProperty } from "../utils/errors"; +import { luaTableCannotBeAccessedDynamically, luaTableForbiddenUsage, unsupportedProperty } from "../utils/diagnostics"; import { transformArguments } from "./call"; -function parseLuaTableExpression( - context: TransformationContext, - node: ts.LeftHandSideExpression -): [lua.Expression, string] { - if (ts.isPropertyAccessExpression(node)) { - return [context.transformExpression(node.expression), node.name.text]; - } else { - throw UnsupportedKind("LuaTable access expression", node.kind, node); - } -} +const parseLuaTableExpression = (context: TransformationContext, node: ts.PropertyAccessExpression) => + [context.transformExpression(node.expression), node.name.text] as const; -function validateLuaTableCall(methodName: string, callArguments: ts.NodeArray, original: ts.Node): void { - if (callArguments.some(argument => ts.isSpreadElement(argument))) { - throw ForbiddenLuaTableUseException("Arguments cannot be spread.", original); +function validateLuaTableCall( + context: TransformationContext, + node: ts.Node, + methodName: string, + callArguments: ts.NodeArray +): void { + for (const argument of callArguments) { + if (ts.isSpreadElement(argument)) { + context.diagnostics.push(luaTableForbiddenUsage(argument, "Arguments cannot be spread")); + return; + } } switch (methodName) { case "get": if (callArguments.length !== 1) { - throw ForbiddenLuaTableUseException("One parameter is required for get().", original); + context.diagnostics.push( + luaTableForbiddenUsage(node, `Expected 1 arguments, but got ${callArguments.length}`) + ); } break; case "set": if (callArguments.length !== 2) { - throw ForbiddenLuaTableUseException("Two parameters are required for set().", original); + context.diagnostics.push( + luaTableForbiddenUsage(node, `Expected 2 arguments, but got ${callArguments.length}`) + ); } break; } } -function transformLuaTableExpressionAsExpressionStatement( +export function transformLuaTableExpressionStatement( context: TransformationContext, - expression: ts.CallExpression -): lua.Statement { + node: ts.ExpressionStatement +): lua.Statement | undefined { + const expression = ts.isExpressionStatement(node) ? node.expression : node; + + if (!ts.isCallExpression(expression) || !ts.isPropertyAccessExpression(expression.expression)) return; + + const ownerType = context.checker.getTypeAtLocation(expression.expression.expression); + const annotations = getTypeAnnotations(ownerType); + if (!annotations.has(AnnotationKind.LuaTable)) return; + const [luaTable, methodName] = parseLuaTableExpression(context, expression.expression); - validateLuaTableCall(methodName, expression.arguments, expression); + validateLuaTableCall(context, expression, methodName, expression.arguments); const signature = context.checker.getResolvedSignature(expression); const params = transformArguments(context, expression.arguments, signature); @@ -49,83 +61,83 @@ function transformLuaTableExpressionAsExpressionStatement( case "get": return lua.createVariableDeclarationStatement( lua.createAnonymousIdentifier(expression), - lua.createTableIndexExpression(luaTable, params[0], expression), + lua.createTableIndexExpression(luaTable, params[0] ?? lua.createNilLiteral(), expression), expression ); case "set": return lua.createAssignmentStatement( - lua.createTableIndexExpression(luaTable, params[0], expression), - params.splice(1), + lua.createTableIndexExpression(luaTable, params[0] ?? lua.createNilLiteral(), expression), + [params[1] ?? lua.createNilLiteral()], expression ); default: - throw UnsupportedProperty("LuaTable", methodName, expression); + context.diagnostics.push(unsupportedProperty(expression.expression.name, "LuaTable", methodName)); } } -export function transformLuaTableExpressionStatement( +export function transformLuaTableCallExpression( context: TransformationContext, - node: ts.ExpressionStatement -): lua.Statement | undefined { - const expression = ts.isExpressionStatement(node) ? node.expression : node; + node: ts.CallExpression +): lua.Expression | undefined { + if (!ts.isPropertyAccessExpression(node.expression)) return; - if (ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression)) { - const ownerType = context.checker.getTypeAtLocation(expression.expression.expression); - const annotations = getTypeAnnotations(ownerType); - if (annotations.has(AnnotationKind.LuaTable)) { - return transformLuaTableExpressionAsExpressionStatement(context, expression); - } + const ownerType = context.checker.getTypeAtLocation(node.expression.expression); + const annotations = getTypeAnnotations(ownerType); + if (!annotations.has(AnnotationKind.LuaTable)) return; + + const [luaTable, methodName] = parseLuaTableExpression(context, node.expression); + validateLuaTableCall(context, node, methodName, node.arguments); + const signature = context.checker.getResolvedSignature(node); + const params = transformArguments(context, node.arguments, signature); + + switch (methodName) { + case "get": + return lua.createTableIndexExpression(luaTable, params[0] ?? lua.createNilLiteral(), node); + default: + context.diagnostics.push(unsupportedProperty(node.expression.name, "LuaTable", methodName)); } } -export function transformLuaTableCallExpression( +export function transformLuaTablePropertyAccessExpression( context: TransformationContext, - node: ts.CallExpression + node: ts.PropertyAccessExpression ): lua.Expression | undefined { - if (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) { - const ownerType = context.checker.getTypeAtLocation(node.expression.expression); - const annotations = getTypeAnnotations(ownerType); - - if (annotations.has(AnnotationKind.LuaTable)) { - const [luaTable, methodName] = parseLuaTableExpression(context, node.expression); - validateLuaTableCall(methodName, node.arguments, node); - const signature = context.checker.getResolvedSignature(node); - const params = transformArguments(context, node.arguments, signature); - - switch (methodName) { - case "get": - return lua.createTableIndexExpression(luaTable, params[0], node); - default: - throw UnsupportedProperty("LuaTable", methodName, node); - } - } + const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(node.expression)); + if (!annotations.has(AnnotationKind.LuaTable)) return; + + const [luaTable, propertyName] = parseLuaTableExpression(context, node); + if (propertyName === "length") { + return lua.createUnaryExpression(luaTable, lua.SyntaxKind.LengthOperator, node); } + + context.diagnostics.push(unsupportedProperty(node.name, "LuaTable", propertyName)); } -export function transformLuaTablePropertyAccessExpression( +export function transformLuaTablePropertyAccessInAssignment( context: TransformationContext, node: ts.PropertyAccessExpression -): lua.Expression | undefined { - const type = context.checker.getTypeAtLocation(node.expression); - const annotations = getTypeAnnotations(type); - if (annotations.has(AnnotationKind.LuaTable)) { - const [luaTable, propertyName] = parseLuaTableExpression(context, node); - switch (node.name.text) { - case "length": - return lua.createUnaryExpression(luaTable, lua.SyntaxKind.LengthOperator, node); - default: - throw UnsupportedProperty("LuaTable", propertyName, node); - } +): lua.AssignmentLeftHandSideExpression | undefined { + if (!ts.isPropertyAccessExpression(node)) return; + + const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(node.expression)); + if (!annotations.has(AnnotationKind.LuaTable)) return; + + const [luaTable, propertyName] = parseLuaTableExpression(context, node); + if (propertyName === "length") { + context.diagnostics.push(luaTableForbiddenUsage(node, `A LuaTable object's length cannot be re-assigned`)); + return lua.createTableIndexExpression(luaTable, lua.createStringLiteral(propertyName), node); } + + context.diagnostics.push(unsupportedProperty(node.name, "LuaTable", propertyName)); } -export function transformLuaTableElementAccessExpression( +export function validateLuaTableElementAccessExpression( context: TransformationContext, node: ts.ElementAccessExpression ): void { const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(node.expression)); if (annotations.has(AnnotationKind.LuaTable)) { - throw UnsupportedKind("LuaTable access expression", node.kind, node); + context.diagnostics.push(luaTableCannotBeAccessedDynamically(node)); } } @@ -133,13 +145,14 @@ export function transformLuaTableNewExpression( context: TransformationContext, node: ts.NewExpression ): lua.Expression | undefined { - const type = context.checker.getTypeAtLocation(node); - const annotations = getTypeAnnotations(type); - if (annotations.has(AnnotationKind.LuaTable)) { - if (node.arguments && node.arguments.length > 0) { - throw ForbiddenLuaTableUseException("No parameters are allowed when constructing a LuaTable object.", node); - } else { - return lua.createTableExpression(); - } + const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(node)); + if (!annotations.has(AnnotationKind.LuaTable)) return; + + if (node.arguments && node.arguments.length > 0) { + context.diagnostics.push( + luaTableForbiddenUsage(node, "No parameters are allowed when constructing a LuaTable object") + ); } + + return lua.createTableExpression(); } diff --git a/src/transformation/visitors/modules/export.ts b/src/transformation/visitors/modules/export.ts index c6b83fcde..5e12c6c5e 100644 --- a/src/transformation/visitors/modules/export.ts +++ b/src/transformation/visitors/modules/export.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; +import { assert } from "../../../utils"; import { FunctionVisitor, TransformationContext } from "../../context"; -import { InvalidExportDeclaration } from "../../utils/errors"; import { createDefaultExportIdentifier, createDefaultExportStringLiteral, @@ -37,9 +37,7 @@ export const transformExportAssignment: FunctionVisitor = ( }; function transformExportAllFrom(context: TransformationContext, node: ts.ExportDeclaration): lua.Statement | undefined { - if (node.moduleSpecifier === undefined) { - throw InvalidExportDeclaration(node); - } + assert(node.moduleSpecifier); if (!context.resolver.moduleExportsSomeValue(node.moduleSpecifier)) { return undefined; diff --git a/src/transformation/visitors/modules/import.ts b/src/transformation/visitors/modules/import.ts index 088fac7d2..089f0949f 100644 --- a/src/transformation/visitors/modules/import.ts +++ b/src/transformation/visitors/modules/import.ts @@ -4,20 +4,22 @@ import * as lua from "../../../LuaAST"; import { formatPathToLuaPath } from "../../../utils"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getSymbolAnnotations, getTypeAnnotations } from "../../utils/annotations"; -import { UnresolvableRequirePath } from "../../utils/errors"; import { createDefaultExportStringLiteral } from "../../utils/export"; import { createHoistableVariableDeclarationStatement } from "../../utils/lua-ast"; import { createSafeName } from "../../utils/safe-names"; import { peekScope } from "../../utils/scope"; import { transformIdentifier } from "../identifier"; import { transformPropertyName } from "../literal"; +import { unresolvableRequirePath } from "../../utils/diagnostics"; const getAbsoluteImportPath = (relativePath: string, directoryPath: string, options: ts.CompilerOptions): string => relativePath[0] !== "." && options.baseUrl ? path.resolve(options.baseUrl, relativePath) : path.resolve(directoryPath, relativePath); -function getImportPath(fileName: string, relativePath: string, node: ts.Node, options: ts.CompilerOptions): string { +function getImportPath(context: TransformationContext, relativePath: string, node: ts.Node): string { + const fileName = context.sourceFile.fileName; + const options = context.options; const rootDir = options.rootDir ? path.resolve(options.rootDir) : path.resolve("."); const absoluteImportPath = path.format( @@ -27,11 +29,8 @@ function getImportPath(fileName: string, relativePath: string, node: ts.Node, op if (absoluteImportPath.includes(absoluteRootDirPath)) { return formatPathToLuaPath(absoluteImportPath.replace(absoluteRootDirPath, "").slice(1)); } else { - throw UnresolvableRequirePath( - node, - `Cannot create require path. Module does not exist within --rootDir`, - relativePath - ); + context.diagnostics.push(unresolvableRequirePath(node, relativePath)); + return relativePath; } } @@ -51,12 +50,7 @@ export function createModuleRequire( const params: lua.Expression[] = []; if (ts.isStringLiteral(moduleSpecifier)) { const modulePath = shouldResolveModulePath(context, moduleSpecifier) - ? getImportPath( - context.sourceFile.fileName, - moduleSpecifier.text.replace(/"/g, ""), - moduleSpecifier, - context.options - ) + ? getImportPath(context, moduleSpecifier.text.replace(/"/g, ""), moduleSpecifier) : moduleSpecifier.text; params.push(lua.createStringLiteral(modulePath)); diff --git a/src/transformation/visitors/sourceFile.ts b/src/transformation/visitors/sourceFile.ts index 064b5200f..539c9f9d7 100644 --- a/src/transformation/visitors/sourceFile.ts +++ b/src/transformation/visitors/sourceFile.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; +import { assert } from "../../utils"; import { FunctionVisitor } from "../context"; -import { InvalidJsonFileContent } from "../utils/errors"; import { createExportsIdentifier } from "../utils/lua-ast"; import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; import { hasExportEquals } from "../utils/typescript"; @@ -10,11 +10,16 @@ export const transformSourceFileNode: FunctionVisitor = (node, co let statements: lua.Statement[] = []; if (node.flags & ts.NodeFlags.JsonFile) { const [statement] = node.statements; - if (!statement || !ts.isExpressionStatement(statement)) { - throw InvalidJsonFileContent(node); - } + if (statement) { + assert(ts.isExpressionStatement(statement)); + statements.push(lua.createReturnStatement([context.transformExpression(statement.expression)])); + } else { + const errorCall = lua.createCallExpression(lua.createIdentifier("error"), [ + lua.createStringLiteral("Unexpected end of JSON input"), + ]); - statements.push(lua.createReturnStatement([context.transformExpression(statement.expression)])); + statements.push(lua.createExpressionStatement(errorCall)); + } } else { pushScope(context, ScopeType.File); statements = performHoisting(context, context.transformStatements(node.statements)); diff --git a/src/transformation/visitors/switch.ts b/src/transformation/visitors/switch.ts index 941d8182d..880f449bd 100644 --- a/src/transformation/visitors/switch.ts +++ b/src/transformation/visitors/switch.ts @@ -2,12 +2,12 @@ import * as ts from "typescript"; import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; -import { UnsupportedForTarget } from "../utils/errors"; +import { unsupportedForTarget } from "../utils/diagnostics"; import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; export const transformSwitchStatement: FunctionVisitor = (statement, context) => { if (context.luaTarget === LuaTarget.Lua51) { - throw UnsupportedForTarget("Switch statements", LuaTarget.Lua51, statement); + context.diagnostics.push(unsupportedForTarget(statement, "Switch statements", LuaTarget.Lua51)); } const scope = pushScope(context, ScopeType.Switch); diff --git a/src/transformation/visitors/typeof.ts b/src/transformation/visitors/typeof.ts index 585746ca4..60eef310c 100644 --- a/src/transformation/visitors/typeof.ts +++ b/src/transformation/visitors/typeof.ts @@ -15,37 +15,37 @@ export function transformTypeOfBinaryExpression( node: ts.BinaryExpression ): lua.Expression | undefined { const operator = node.operatorToken.kind; - function transformTypeOfLiteralComparison( - typeOfExpression: ts.TypeOfExpression, - comparedExpression: lua.StringLiteral - ): lua.Expression { - if (comparedExpression.value === "object") { - comparedExpression.value = "table"; - } else if (comparedExpression.value === "undefined") { - comparedExpression.value = "nil"; - } + if ( + operator !== ts.SyntaxKind.EqualsEqualsToken && + operator !== ts.SyntaxKind.EqualsEqualsEqualsToken && + operator !== ts.SyntaxKind.ExclamationEqualsToken && + operator !== ts.SyntaxKind.ExclamationEqualsEqualsToken + ) { + return; + } - const innerExpression = context.transformExpression(typeOfExpression.expression); - const typeCall = lua.createCallExpression(lua.createIdentifier("type"), [innerExpression], typeOfExpression); - return transformBinaryOperation(context, typeCall, comparedExpression, operator, node); + let literalExpression: ts.Expression; + let typeOfExpression: ts.TypeOfExpression; + if (ts.isTypeOfExpression(node.left)) { + typeOfExpression = node.left; + literalExpression = node.right; + } else if (ts.isTypeOfExpression(node.right)) { + typeOfExpression = node.right; + literalExpression = node.left; + } else { + return; } - if ( - operator === ts.SyntaxKind.EqualsEqualsToken || - operator === ts.SyntaxKind.EqualsEqualsEqualsToken || - operator === ts.SyntaxKind.ExclamationEqualsToken || - operator === ts.SyntaxKind.ExclamationEqualsEqualsToken - ) { - if (ts.isTypeOfExpression(node.left)) { - const right = context.transformExpression(node.right); - if (lua.isStringLiteral(right)) { - return transformTypeOfLiteralComparison(node.left, right); - } - } else if (ts.isTypeOfExpression(node.right)) { - const left = context.transformExpression(node.left); - if (lua.isStringLiteral(left)) { - return transformTypeOfLiteralComparison(node.right, left); - } - } + const comparedExpression = context.transformExpression(literalExpression); + if (!lua.isStringLiteral(comparedExpression)) return; + + if (comparedExpression.value === "object") { + comparedExpression.value = "table"; + } else if (comparedExpression.value === "undefined") { + comparedExpression.value = "nil"; } + + const innerExpression = context.transformExpression(typeOfExpression.expression); + const typeCall = lua.createCallExpression(lua.createIdentifier("type"), [innerExpression], typeOfExpression); + return transformBinaryOperation(context, typeCall, comparedExpression, operator, node); } diff --git a/src/transformation/visitors/unary-expression.ts b/src/transformation/visitors/unary-expression.ts index cf0d44312..76b0e4941 100644 --- a/src/transformation/visitors/unary-expression.ts +++ b/src/transformation/visitors/unary-expression.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; +import { assertNever } from "../../utils"; import { FunctionVisitor, TransformationContext } from "../context"; -import { UnsupportedKind } from "../utils/errors"; import { transformUnaryBitOperation } from "./binary-expression/bit"; import { transformCompoundAssignmentExpression, @@ -66,7 +66,7 @@ export const transformPostfixUnaryExpression: FunctionVisitor; @@ -229,13 +235,15 @@ export function transformVariableDeclaration( } } -export function checkVariableDeclarationList(node: ts.VariableDeclarationList): void { +export function checkVariableDeclarationList(context: TransformationContext, node: ts.VariableDeclarationList): void { if ((node.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) === 0) { - throw UnsupportedVarDeclaration(node); + const token = node.getFirstToken(); + assert(token); + context.diagnostics.push(unsupportedVarDeclaration(token)); } } export const transformVariableStatement: FunctionVisitor = (node, context) => { - checkVariableDeclarationList(node.declarationList); + checkVariableDeclarationList(context, node.declarationList); return node.declarationList.declarations.flatMap(declaration => transformVariableDeclaration(context, declaration)); }; diff --git a/src/transpilation/bundle.ts b/src/transpilation/bundle.ts index 7c587055c..c60a5b7cc 100644 --- a/src/transpilation/bundle.ts +++ b/src/transpilation/bundle.ts @@ -5,7 +5,7 @@ import { CompilerOptions } from "../CompilerOptions"; import { getLuaLibBundle } from "../LuaLib"; import { escapeString } from "../LuaPrinter"; import { formatPathToLuaPath, normalizeSlashes, trimExtension } from "../utils"; -import { couldNotFindBundleEntryPoint } from "./diagnostics"; +import * as diagnosticFactories from "./diagnostics"; import { EmitHost, TranspiledFile } from "./transpile"; const createModulePath = (baseDir: string, pathToResolve: string) => @@ -33,7 +33,7 @@ export function bundleTranspiledFiles( // Resolve source files relative to common source directory. const sourceRootDir = program.getCommonSourceDirectory(); if (!transpiledFiles.some(f => path.resolve(sourceRootDir, f.fileName) === resolvedEntryModule)) { - return [[couldNotFindBundleEntryPoint(entryModule)], { fileName: bundleFile }]; + return [[diagnosticFactories.couldNotFindBundleEntryPoint(entryModule)], { fileName: bundleFile }]; } // For each file: [""] = function() end, diff --git a/src/transpilation/diagnostics.ts b/src/transpilation/diagnostics.ts index 3383c3cfd..9467bb606 100644 --- a/src/transpilation/diagnostics.ts +++ b/src/transpilation/diagnostics.ts @@ -1,51 +1,38 @@ import * as ts from "typescript"; +import { createSerialDiagnosticFactory } from "../utils"; -export const toLoadTransformerItShouldBeTranspiled = (transform: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: `To load "${transform}" transformer it should be transpiled or "ts-node" should be installed`, -}); - -export const couldNotResolveTransformerFrom = (transform: string, base: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: `Could not resolve "${transform}" transformer from "${base}".`, -}); - -export const transformerShouldHaveAExport = (transform: string, importName: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: `"${transform}" transformer should have a "${importName}" export`, -}); - -export const transformerShouldBeATsTransformerFactory = (transform: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: `"${transform}" transformer should be a ts.TransformerFactory or an object with ts.TransformerFactory values`, -}); - -export const couldNotFindBundleEntryPoint = (entryPoint: string): ts.Diagnostic => ({ - file: undefined, - start: undefined, - length: undefined, - category: ts.DiagnosticCategory.Error, - code: 0, - source: "typescript-to-lua", - messageText: `Could not find bundle entry point '${entryPoint}'. It should be a file in the project.`, -}); +const createDiagnosticFactory = (getMessage: (...args: TArgs) => string) => + createSerialDiagnosticFactory((...args: TArgs) => ({ messageText: getMessage(...args) })); + +export const toLoadTransformerItShouldBeTranspiled = createDiagnosticFactory( + (transform: string) => + `To load "${transform}" transformer it should be transpiled or "ts-node" should be installed.` +); + +export const couldNotResolveTransformerFrom = createDiagnosticFactory( + (transform: string, base: string) => `Could not resolve "${transform}" transformer from "${base}".` +); + +export const transformerShouldHaveAExport = createDiagnosticFactory( + (transform: string, importName: string) => `"${transform}" transformer should have a "${importName}" export.` +); + +export const transformerShouldBeATsTransformerFactory = createDiagnosticFactory( + (transform: string) => + `"${transform}" transformer should be a ts.TransformerFactory or an object with ts.TransformerFactory values.` +); + +export const couldNotFindBundleEntryPoint = createDiagnosticFactory( + (entryPoint: string) => `Could not find bundle entry point '${entryPoint}'. It should be a file in the project.` +); + +export const luaBundleEntryIsRequired = createDiagnosticFactory( + () => "'luaBundleEntry' is required when 'luaBundle' is enabled." +); + +export const usingLuaBundleWithInlineMightGenerateDuplicateCode = createSerialDiagnosticFactory(() => ({ + category: ts.DiagnosticCategory.Warning, + messageText: + `Using 'luaBundle' with 'luaLibImport: "inline"' might generate duplicate code. ` + + `It is recommended to use 'luaLibImport: "require"'.`, +})); diff --git a/src/utils.ts b/src/utils.ts index 6baad413a..822c5df3a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,34 @@ +import * as ts from "typescript"; +import * as nativeAssert from "assert"; import * as path from "path"; +export const createDiagnosticFactoryWithCode = < + T extends (...args: any) => Partial & Pick +>( + code: number, + create: T +) => { + return Object.assign( + (...args: Parameters): ts.Diagnostic => ({ + file: undefined, + start: undefined, + length: undefined, + category: ts.DiagnosticCategory.Error, + code, + source: "typescript-to-lua", + ...create(...(args as any)), + }), + { code } + ); +}; + +let serialDiagnosticCodeCounter = 100000; +export const createSerialDiagnosticFactory = < + T extends (...args: any) => Partial & Pick +>( + create: T +) => createDiagnosticFactoryWithCode(serialDiagnosticCodeCounter++, create); + export const normalizeSlashes = (filePath: string) => filePath.replace(/\\/g, "/"); export const trimExtension = (filePath: string) => filePath.slice(0, -path.extname(filePath).length); @@ -52,6 +81,10 @@ export function castEach( } } +export function assert(value: any, message?: string | Error): asserts value { + nativeAssert(value, message); +} + export function assertNever(_value: never): never { throw new Error("Value is expected to be never"); } diff --git a/test/setup.ts b/test/setup.ts index 8305ec264..ebaa4e2fd 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,54 +1,43 @@ import * as ts from "typescript"; -import * as util from "./util"; +import * as tstl from "../src"; declare global { namespace jest { interface Matchers { - toThrowExactError(error: Error): R; - toHaveDiagnostics(): R; + toHaveDiagnostics(expected?: number[]): R; } } } expect.extend({ - toThrowExactError(callback: () => void, error: Error): jest.CustomMatcherResult { - if (this.isNot) { - return { pass: true, message: () => "Inverted toThrowExactError is not implemented" }; - } - - let executionError: Error | undefined; - try { - callback(); - } catch (err) { - executionError = err; - } - - // TODO: - if (util.expectToBeDefined(executionError)) { - expect(executionError.message).toContain(error.message); - } - - return { pass: true, message: () => "" }; - }, - toHaveDiagnostics(diagnostics: ts.Diagnostic[]): jest.CustomMatcherResult { + toHaveDiagnostics(diagnostics: ts.Diagnostic[], expected?: number[]): jest.CustomMatcherResult { expect(diagnostics).toBeInstanceOf(Array); // @ts-ignore const matcherHint = this.utils.matcherHint("toHaveDiagnostics", undefined, "", this); - const diagnosticMessages = ts.formatDiagnosticsWithColorAndContext(diagnostics, { - getCurrentDirectory: () => "", - getCanonicalFileName: fileName => fileName, - getNewLine: () => "\n", - }); + const diagnosticMessages = ts.formatDiagnosticsWithColorAndContext( + diagnostics.map(tstl.prepareDiagnosticForFormatting), + { getCurrentDirectory: () => "", getCanonicalFileName: fileName => fileName, getNewLine: () => "\n" } + ); + + if (this.isNot && expected !== undefined) { + throw new Error(`expect(actual).not.toHaveDiagnostics(expected) is not supported`); + } return { - pass: diagnostics.length > 0, + pass: expected + ? diagnostics.length === expected.length && + diagnostics.every((diag, index) => diag.code === expected[index]) + : diagnostics.length > 0, + message: () => { - return ( - matcherHint + - "\n\n" + - (this.isNot ? diagnosticMessages : `Received: ${this.utils.printReceived(diagnostics)}\n`) - ); + const message = this.isNot + ? diagnosticMessages + : expected + ? `Expected:\n${expected.join("\n")}\nReceived:\n${diagnostics.map(diag => diag.code).join("\n")}\n` + : `Received: ${this.utils.printReceived([])}\n`; + + return matcherHint + "\n\n" + message; }, }; }, diff --git a/test/unit/__snapshots__/assignments.spec.ts.snap b/test/unit/__snapshots__/assignments.spec.ts.snap new file mode 100644 index 000000000..6f9f553ff --- /dev/null +++ b/test/unit/__snapshots__/assignments.spec.ts.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`var declaration in for loop is disallowed: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + do + local foo = 0 + while true do + end + end +end +return ____exports" +`; + +exports[`var declaration in for loop is disallowed: diagnostics 1`] = `"main.ts(2,14): error TSTL: \`var\` declarations are not supported. Use \`let\` or \`const\` instead."`; + +exports[`var declaration in for...in loop is disallowed: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + for foo in pairs({}) do + end +end +return ____exports" +`; + +exports[`var declaration in for...in loop is disallowed: diagnostics 1`] = `"main.ts(2,14): error TSTL: \`var\` declarations are not supported. Use \`let\` or \`const\` instead."`; + +exports[`var declaration in for...of loop is disallowed: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + for ____, foo in ipairs({}) do + end +end +return ____exports" +`; + +exports[`var declaration in for...of loop is disallowed: diagnostics 1`] = `"main.ts(2,14): error TSTL: \`var\` declarations are not supported. Use \`let\` or \`const\` instead."`; + +exports[`var declaration is disallowed: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local foo = true +end +return ____exports" +`; + +exports[`var declaration is disallowed: diagnostics 1`] = `"main.ts(2,9): error TSTL: \`var\` declarations are not supported. Use \`let\` or \`const\` instead."`; diff --git a/test/unit/__snapshots__/bundle.spec.ts.snap b/test/unit/__snapshots__/bundle.spec.ts.snap new file mode 100644 index 000000000..84c10f3d5 --- /dev/null +++ b/test/unit/__snapshots__/bundle.spec.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LuaLibImportKind.Inline generates a warning: diagnostics 1`] = `"warning TSTL: Using 'luaBundle' with 'luaLibImport: \\"inline\\"' might generate duplicate code. It is recommended to use 'luaLibImport: \\"require\\"'."`; + +exports[`luaEntry doesn't exist: diagnostics 1`] = `"error TSTL: Could not find bundle entry point 'entry.ts'. It should be a file in the project."`; + +exports[`no entry point: diagnostics 1`] = `"error TSTL: 'luaBundleEntry' is required when 'luaBundle' is enabled."`; diff --git a/test/unit/__snapshots__/conditionals.spec.ts.snap b/test/unit/__snapshots__/conditionals.spec.ts.snap index e1c59f48f..e7d003fa5 100644 --- a/test/unit/__snapshots__/conditionals.spec.ts.snap +++ b/test/unit/__snapshots__/conditionals.spec.ts.snap @@ -39,3 +39,15 @@ function ____exports.__main(self) end return ____exports" `; + +exports[`switch not allowed in 5.1: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____switch3 = \\"abc\\" + goto ____switch3_end + ::____switch3_end:: +end +return ____exports" +`; + +exports[`switch not allowed in 5.1: diagnostics 1`] = `"main.ts(2,9): error TSTL: Switch statements is/are not supported for target Lua 5.1."`; diff --git a/test/unit/__snapshots__/expressions.spec.ts.snap b/test/unit/__snapshots__/expressions.spec.ts.snap index 7095c91a8..fd53ab8ac 100644 --- a/test/unit/__snapshots__/expressions.spec.ts.snap +++ b/test/unit/__snapshots__/expressions.spec.ts.snap @@ -36,6 +36,128 @@ ____exports.__result = 10 - (4 + 5) return ____exports" `; +exports[`Bitop [5.1] ("~a"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bnot(a) +return ____exports" +`; + +exports[`Bitop [5.1] ("~a"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a&=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.band(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a&=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a&b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.band(a, b) +return ____exports" +`; + +exports[`Bitop [5.1] ("a&b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a<<=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.lshift(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a<<=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a<>=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.arshift(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a>>>=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.rshift(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a>>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a>>>b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.rshift(a, b) +return ____exports" +`; + +exports[`Bitop [5.1] ("a>>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a>>b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.arshift(a, b) +return ____exports" +`; + +exports[`Bitop [5.1] ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a^=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.bxor(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a^=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a^b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bxor(a, b) +return ____exports" +`; + +exports[`Bitop [5.1] ("a^b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a|=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = bit.bor(a, b) + return a +end)() +return ____exports" +`; + +exports[`Bitop [5.1] ("a|=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + +exports[`Bitop [5.1] ("a|b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bor(a, b) +return ____exports" +`; + +exports[`Bitop [5.1] ("a|b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.1."`; + exports[`Bitop [5.2] ("~a") 1`] = ` "local ____exports = {} ____exports.__result = bit32.bnot(a) @@ -402,3 +524,22 @@ function ____exports.__main(self) end return ____exports" `; + +exports[`Unsupported bitop 5.3 ("a>>=b"): code 1`] = ` +"local ____exports = {} +____exports.__result = (function() + a = a >> b + return a +end)() +return ____exports" +`; + +exports[`Unsupported bitop 5.3 ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; + +exports[`Unsupported bitop 5.3 ("a>>b"): code 1`] = ` +"local ____exports = {} +____exports.__result = a >> b +return ____exports" +`; + +exports[`Unsupported bitop 5.3 ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; diff --git a/test/unit/__snapshots__/identifiers.spec.ts.snap b/test/unit/__snapshots__/identifiers.spec.ts.snap new file mode 100644 index 000000000..6ab8a4433 --- /dev/null +++ b/test/unit/__snapshots__/identifiers.spec.ts.snap @@ -0,0 +1,241 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ambient identifier cannot be a lua keyword ("class local {}"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("class local {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("const foo: any, bar: any, local: any;"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("const foo: any, bar: any, local: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("const local: any;"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("const local: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("enum local {}"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("enum local {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("function local() {}"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("function local() {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("let local: any;"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("let local: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("module local { export const bar: any; }"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("module local { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("namespace local { export const bar: any; }"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("namespace local { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier cannot be a lua keyword ("var local: any;"): code 1`] = `"local ____ = ____local"`; + +exports[`ambient identifier cannot be a lua keyword ("var local: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("class $$ {}"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("class $$ {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("const $$: any;"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("const $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("const foo: any, bar: any, $$: any;"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("const foo: any, bar: any, $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("enum $$ {}"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("enum $$ {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("function $$();"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("function $$();"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("let $$: any;"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("let $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("module $$ { export const bar: any; }"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("module $$ { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("namespace $$ { export const bar: any; }"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("namespace $$ { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier ("var $$: any;"): code 1`] = `"local ____ = _____24_24_24"`; + +exports[`ambient identifier must be a valid lua identifier ("var $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {[\\"$$$\\"] = _____24_24_24}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("$$"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {[\\"_̀ः٠‿\\"] = ______300_903_660_203F}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name '_̀ः٠‿'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {[\\"and\\"] = ____and}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("and"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'and'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {[\\"elseif\\"] = ____elseif}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("elseif"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'elseif'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {[\\"end\\"] = ____end}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("end"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'end'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {[\\"goto\\"] = ____goto}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("goto"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'goto'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {[\\"local\\"] = ____local}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("local"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {[\\"nil\\"] = ____nil}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("nil"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'nil'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {[\\"not\\"] = ____not}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("not"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'not'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {[\\"or\\"] = ____or}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("or"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'or'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {[\\"repeat\\"] = ____repeat}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("repeat"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'repeat'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {[\\"then\\"] = ____then}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("then"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'then'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {[\\"until\\"] = ____until}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("until"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'until'. Ambient identifiers must be valid lua identifiers."`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {[\\"ɥɣɎɌͼƛಠ\\"] = _____265_263_24E_24C_37C_19B_CA0}"`; + +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("$$"): code 1`] = `"foo = _____24_24_24"`; + +exports[`undeclared identifier must be a valid lua identifier ("$$"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("_̀ः٠‿"): code 1`] = `"foo = ______300_903_660_203F"`; + +exports[`undeclared identifier must be a valid lua identifier ("_̀ः٠‿"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name '_̀ः٠‿'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("and"): code 1`] = `"foo = ____and"`; + +exports[`undeclared identifier must be a valid lua identifier ("and"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'and'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("elseif"): code 1`] = `"foo = ____elseif"`; + +exports[`undeclared identifier must be a valid lua identifier ("elseif"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'elseif'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("end"): code 1`] = `"foo = ____end"`; + +exports[`undeclared identifier must be a valid lua identifier ("end"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'end'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("goto"): code 1`] = `"foo = ____goto"`; + +exports[`undeclared identifier must be a valid lua identifier ("goto"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'goto'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("local"): code 1`] = `"foo = ____local"`; + +exports[`undeclared identifier must be a valid lua identifier ("local"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("nil"): code 1`] = `"foo = ____nil"`; + +exports[`undeclared identifier must be a valid lua identifier ("nil"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'nil'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("not"): code 1`] = `"foo = ____not"`; + +exports[`undeclared identifier must be a valid lua identifier ("not"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'not'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("or"): code 1`] = `"foo = ____or"`; + +exports[`undeclared identifier must be a valid lua identifier ("or"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'or'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("repeat"): code 1`] = `"foo = ____repeat"`; + +exports[`undeclared identifier must be a valid lua identifier ("repeat"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'repeat'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("then"): code 1`] = `"foo = ____then"`; + +exports[`undeclared identifier must be a valid lua identifier ("then"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'then'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("until"): code 1`] = `"foo = ____until"`; + +exports[`undeclared identifier must be a valid lua identifier ("until"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'until'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = _____265_263_24E_24C_37C_19B_CA0"`; + +exports[`undeclared identifier must be a valid lua identifier ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {[\\"$$$\\"] = _____24_24_24}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("$$"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {[\\"_̀ः٠‿\\"] = ______300_903_660_203F}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name '_̀ः٠‿'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {[\\"and\\"] = ____and}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("and"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'and'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {[\\"elseif\\"] = ____elseif}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("elseif"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'elseif'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {[\\"end\\"] = ____end}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("end"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'end'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {[\\"goto\\"] = ____goto}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("goto"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'goto'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {[\\"local\\"] = ____local}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("local"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {[\\"nil\\"] = ____nil}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("nil"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'nil'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {[\\"not\\"] = ____not}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("not"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'not'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {[\\"or\\"] = ____or}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("or"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'or'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {[\\"repeat\\"] = ____repeat}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("repeat"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'repeat'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {[\\"then\\"] = ____then}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("then"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'then'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {[\\"until\\"] = ____until}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("until"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'until'. Ambient identifiers must be valid lua identifiers."`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {[\\"ɥɣɎɌͼƛಠ\\"] = _____265_263_24E_24C_37C_19B_CA0}"`; + +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; diff --git a/test/unit/__snapshots__/loops.spec.ts.snap b/test/unit/__snapshots__/loops.spec.ts.snap new file mode 100644 index 000000000..f1daffe65 --- /dev/null +++ b/test/unit/__snapshots__/loops.spec.ts.snap @@ -0,0 +1,72 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`forin[Array]: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local array = {} + for key in pairs(array) do + end +end +return ____exports" +`; + +exports[`forin[Array]: diagnostics 1`] = `"main.ts(3,9): error TSTL: Iterating over arrays with 'for ... in' is not allowed."`; + +exports[`loop continue (do { continue; } while (false)) [5.1]: code 1`] = ` +"repeat + do + do + goto __continue2 + end + ::__continue2:: + end +until not false" +`; + +exports[`loop continue (do { continue; } while (false)) [5.1]: diagnostics 1`] = `"main.ts(1,6): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; + +exports[`loop continue (for (;;) { continue; }) [5.1]: code 1`] = ` +"do + while true do + do + goto __continue2 + end + ::__continue2:: + end +end" +`; + +exports[`loop continue (for (;;) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,12): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; + +exports[`loop continue (for (const a in {}) { continue; }) [5.1]: code 1`] = ` +"for a in pairs({}) do + do + goto __continue2 + end + ::__continue2:: +end" +`; + +exports[`loop continue (for (const a in {}) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; + +exports[`loop continue (for (const a of []) { continue; }) [5.1]: code 1`] = ` +"for ____, a in ipairs({}) do + do + goto __continue2 + end + ::__continue2:: +end" +`; + +exports[`loop continue (for (const a of []) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; + +exports[`loop continue (while (false) { continue; }) [5.1]: code 1`] = ` +"while false do + do + goto __continue2 + end + ::__continue2:: +end" +`; + +exports[`loop continue (while (false) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,17): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; diff --git a/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap b/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap new file mode 100644 index 000000000..c283485bf --- /dev/null +++ b/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`IncorrectUsage: code 1`] = ` +"require(\\"lualib_bundle\\"); +local ____exports = {} +function ____exports.__main(self) + local Point2D = __TS__Class() + Point2D.name = \\"Point2D\\" + function Point2D.prototype.____constructor(self) + end + __TS__New(Point2D) +end +return ____exports" +`; + +exports[`IncorrectUsage: diagnostics 1`] = `"main.ts(5,9): error TSTL: '@customConstructor' expects 1 arguments, but got 0."`; diff --git a/test/unit/annotations/__snapshots__/extension.spec.ts.snap b/test/unit/annotations/__snapshots__/extension.spec.ts.snap new file mode 100644 index 000000000..f69a1315a --- /dev/null +++ b/test/unit/annotations/__snapshots__/extension.spec.ts.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Class construct extension ("extension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +b = __TS__New(B)" +`; + +exports[`Class construct extension ("extension"): diagnostics 1`] = `"main.ts(5,19): error TSTL: Cannot construct classes with '@extension' or '@metaExtension' annotation."`; + +exports[`Class construct extension ("metaExtension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +local __meta__A = debug.getregistry().A +b = __TS__New(B)" +`; + +exports[`Class construct extension ("metaExtension"): diagnostics 1`] = `"main.ts(5,19): error TSTL: Cannot construct classes with '@extension' or '@metaExtension' annotation."`; + +exports[`Class extends extension ("extension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +C = __TS__Class() +C.name = \\"C\\" +__TS__ClassExtends(C, B)" +`; + +exports[`Class extends extension ("extension"): diagnostics 1`] = `"main.ts(5,9): error TSTL: Cannot extend classes with '@extension' or '@metaExtension' annotation."`; + +exports[`Class extends extension ("metaExtension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +local __meta__A = debug.getregistry().A +C = __TS__Class() +C.name = \\"C\\" +__TS__ClassExtends(C, B)" +`; + +exports[`Class extends extension ("metaExtension"): diagnostics 1`] = `"main.ts(5,9): error TSTL: Cannot extend classes with '@extension' or '@metaExtension' annotation."`; + +exports[`instanceof extension ("extension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +result = __TS__InstanceOf(foo, B)" +`; + +exports[`instanceof extension ("extension"): diagnostics 1`] = `"main.ts(6,24): error TSTL: Cannot use instanceof on classes with '@extension' or '@metaExtension' annotation."`; + +exports[`instanceof extension ("metaExtension"): code 1`] = ` +"require(\\"lualib_bundle\\"); +local __meta__A = debug.getregistry().A +result = __TS__InstanceOf(foo, B)" +`; + +exports[`instanceof extension ("metaExtension"): diagnostics 1`] = `"main.ts(6,24): error TSTL: Cannot use instanceof on classes with '@extension' or '@metaExtension' annotation."`; diff --git a/test/unit/annotations/__snapshots__/forRange.spec.ts.snap b/test/unit/annotations/__snapshots__/forRange.spec.ts.snap new file mode 100644 index 000000000..325c32be7 --- /dev/null +++ b/test/unit/annotations/__snapshots__/forRange.spec.ts.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`invalid usage argument count ([]): code 1`] = ` +"for i = 0, 0 do +end" +`; + +exports[`invalid usage argument count ([]): diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: Expected 2-3 arguments, but got 0."`; + +exports[`invalid usage argument count ([1, 2, 3, 4]): code 1`] = ` +"for i = 1, 2, 3 do +end" +`; + +exports[`invalid usage argument count ([1, 2, 3, 4]): diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: Expected 2-3 arguments, but got 4."`; + +exports[`invalid usage argument count ([1]): code 1`] = ` +"for i = 1, 0 do +end" +`; + +exports[`invalid usage argument count ([1]): diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: Expected 2-3 arguments, but got 1."`; + +exports[`invalid usage argument types: code 1`] = ` +"for i = \\"foo\\", 2 do +end" +`; + +exports[`invalid usage argument types: diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: arguments must be numbers."`; + +exports[`invalid usage non-ambient declaration: code 1`] = ` +"function luaRange(self) +end" +`; + +exports[`invalid usage non-ambient declaration: diagnostics 1`] = `"main.ts(3,22): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage non-declared loop variable: code 1`] = ` +"for ____ = 1, 10, 2 do +end" +`; + +exports[`invalid usage non-declared loop variable: diagnostics 1`] = `"main.ts(7,18): error TSTL: Invalid @forRange call: loop must declare it's own control variable."`; + +exports[`invalid usage reference ("const call = undefined as any; call(luaRange);"): code 1`] = ` +"call = nil +call(_G, luaRange)" +`; + +exports[`invalid usage reference ("const call = undefined as any; call(luaRange);"): diagnostics 1`] = `"main.ts(6,49): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage reference ("const range = luaRange(1, 10);"): code 1`] = `"range = luaRange(_G, 1, 10)"`; + +exports[`invalid usage reference ("const range = luaRange(1, 10);"): diagnostics 1`] = `"main.ts(6,27): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage reference ("for (const i of [...luaRange(1, 10)]) {}"): code 1`] = ` +"for ____, i in ipairs( + { + table.unpack( + luaRange(_G, 1, 10) + ) + } +) do +end" +`; + +exports[`invalid usage reference ("for (const i of [...luaRange(1, 10)]) {}"): diagnostics 1`] = `"main.ts(6,33): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage reference ("let array = [0, luaRange, 1];"): code 1`] = `"array = {0, luaRange, 1}"`; + +exports[`invalid usage reference ("let array = [0, luaRange, 1];"): diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage reference ("luaRange.call(null, 0, 0, 0);"): code 1`] = ` +"require(\\"lualib_bundle\\"); +__TS__FunctionCall(luaRange, nil, 0, 0, 0)" +`; + +exports[`invalid usage reference ("luaRange.call(null, 0, 0, 0);"): diagnostics 1`] = `"main.ts(6,13): error TSTL: Invalid @forRange call: can be used only as an iterable in a for...of loop."`; + +exports[`invalid usage return type: code 1`] = ` +"for i = 1, 10 do +end" +`; + +exports[`invalid usage return type: diagnostics 1`] = `"main.ts(6,29): error TSTL: Invalid @forRange call: function must return Iterable."`; + +exports[`invalid usage variable destructuring: code 1`] = ` +"for ____ = 1, 10, 2 do +end" +`; + +exports[`invalid usage variable destructuring: diagnostics 1`] = `"main.ts(6,18): error TSTL: Invalid @forRange call: destructuring cannot be used."`; diff --git a/test/unit/annotations/__snapshots__/luaIterator.spec.ts.snap b/test/unit/annotations/__snapshots__/luaIterator.spec.ts.snap new file mode 100644 index 000000000..24761ca3a --- /dev/null +++ b/test/unit/annotations/__snapshots__/luaIterator.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`forof lua iterator tuple-return single existing variable: code 1`] = ` +"for ____ in luaIter(_G) do +end" +`; + +exports[`forof lua iterator tuple-return single existing variable: diagnostics 1`] = `"main.ts(9,14): error TSTL: Unsupported use of lua iterator with '@tupleReturn' annotation in for...of statement. You must use a destructuring statement to catch results from a lua iterator with the '@tupleReturn' annotation."`; + +exports[`forof lua iterator tuple-return single variable: code 1`] = ` +"for ____ in luaIter(_G) do +end" +`; + +exports[`forof lua iterator tuple-return single variable: diagnostics 1`] = `"main.ts(8,18): error TSTL: Unsupported use of lua iterator with '@tupleReturn' annotation in for...of statement. You must use a destructuring statement to catch results from a lua iterator with the '@tupleReturn' annotation."`; diff --git a/test/unit/annotations/__snapshots__/luaTable.spec.ts.snap b/test/unit/annotations/__snapshots__/luaTable.spec.ts.snap new file mode 100644 index 000000000..fae2b1f20 --- /dev/null +++ b/test/unit/annotations/__snapshots__/luaTable.spec.ts.snap @@ -0,0 +1,197 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Cannot extend LuaTable class ("class Ext extends Table {}"): code 1`] = ` +"require(\\"lualib_bundle\\"); +Ext = __TS__Class() +Ext.name = \\"Ext\\" +__TS__ClassExtends(Ext, Table)" +`; + +exports[`Cannot extend LuaTable class ("class Ext extends Table {}"): diagnostics 1`] = `"main.ts(11,19): error TSTL: Cannot extend classes with the '@luaTable' annotation."`; + +exports[`Cannot extend LuaTable class ("const c = class Ext extends Table {}"): code 1`] = ` +"require(\\"lualib_bundle\\"); +c = (function() + local Ext = __TS__Class() + Ext.name = \\"Ext\\" + __TS__ClassExtends(Ext, Table) + return Ext +end)()" +`; + +exports[`Cannot extend LuaTable class ("const c = class Ext extends Table {}"): diagnostics 1`] = `"main.ts(11,29): error TSTL: Cannot extend classes with the '@luaTable' annotation."`; + +exports[`Cannot isolate LuaTable method ("get"): code 1`] = `"property = tbl.get"`; + +exports[`Cannot isolate LuaTable method ("get"): code 2`] = `"property = tbl.get"`; + +exports[`Cannot isolate LuaTable method ("get"): diagnostics 1`] = `"main.ts(11,21): error TSTL: LuaTable.get is unsupported."`; + +exports[`Cannot isolate LuaTable method ("get"): diagnostics 2`] = `"main.ts(13,21): error TSTL: LuaTable.get is unsupported."`; + +exports[`Cannot isolate LuaTable method ("set"): code 1`] = `"property = tbl.set"`; + +exports[`Cannot isolate LuaTable method ("set"): code 2`] = `"property = tbl.set"`; + +exports[`Cannot isolate LuaTable method ("set"): diagnostics 1`] = `"main.ts(11,21): error TSTL: LuaTable.set is unsupported."`; + +exports[`Cannot isolate LuaTable method ("set"): diagnostics 2`] = `"main.ts(13,21): error TSTL: LuaTable.set is unsupported."`; + +exports[`Cannot set LuaTable length: code 1`] = `"tbl.length = 2"`; + +exports[`Cannot set LuaTable length: code 2`] = `"tbl.length = 2"`; + +exports[`Cannot set LuaTable length: diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: A LuaTable object's length cannot be re-assigned."`; + +exports[`Cannot set LuaTable length: diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: A LuaTable object's length cannot be re-assigned."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"get\\"](\\"field\\")"): code 1`] = `"tbl.get(tbl, \\"field\\")"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"get\\"](\\"field\\")"): code 2`] = `"tbl.get(tbl, \\"field\\")"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"get\\"](\\"field\\")"): diagnostics 1`] = `"main.ts(11,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"get\\"](\\"field\\")"): diagnostics 2`] = `"main.ts(13,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"length\\"]"): code 1`] = `"local ____ = tbl.length"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"length\\"]"): code 2`] = `"local ____ = tbl.length"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"length\\"]"): diagnostics 1`] = `"main.ts(11,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"length\\"]"): diagnostics 2`] = `"main.ts(13,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"set\\"](\\"field\\")"): code 1`] = `"tbl.set(tbl, \\"field\\")"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"set\\"](\\"field\\")"): code 2`] = `"tbl.set(tbl, \\"field\\")"`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"set\\"](\\"field\\")"): diagnostics 1`] = `"main.ts(11,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use ElementAccessExpression on a LuaTable ("tbl[\\"set\\"](\\"field\\")"): diagnostics 2`] = `"main.ts(13,1): error TSTL: @luaTable cannot be accessed dynamically."`; + +exports[`Cannot use instanceof on a LuaTable class ("tbl instanceof Table"): code 1`] = ` +"require(\\"lualib_bundle\\"); +__TS__InstanceOf(tbl, Table)" +`; + +exports[`Cannot use instanceof on a LuaTable class ("tbl instanceof Table"): diagnostics 1`] = `"main.ts(11,1): error TSTL: The instanceof operator cannot be used with a '@luaTable' class."`; + +exports[`Forbidden LuaTable use ("tbl.get()"): code 1`] = `"local ____ = tbl[nil]"`; + +exports[`Forbidden LuaTable use ("tbl.get()"): code 2`] = `"local ____ = tbl[nil]"`; + +exports[`Forbidden LuaTable use ("tbl.get()"): diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: Expected 1 arguments, but got 0."`; + +exports[`Forbidden LuaTable use ("tbl.get()"): diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: Expected 1 arguments, but got 0."`; + +exports[`Forbidden LuaTable use ("tbl.get(\\"field\\", \\"field2\\")"): code 1`] = `"local ____ = tbl.field"`; + +exports[`Forbidden LuaTable use ("tbl.get(\\"field\\", \\"field2\\")"): code 2`] = `"local ____ = tbl.field"`; + +exports[`Forbidden LuaTable use ("tbl.get(\\"field\\", \\"field2\\")"): diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: Expected 1 arguments, but got 2."`; + +exports[`Forbidden LuaTable use ("tbl.get(\\"field\\", \\"field2\\")"): diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: Expected 1 arguments, but got 2."`; + +exports[`Forbidden LuaTable use ("tbl.set()"): code 1`] = `"tbl[nil] = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set()"): code 2`] = `"tbl[nil] = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set()"): diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 0."`; + +exports[`Forbidden LuaTable use ("tbl.set()"): diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 0."`; + +exports[`Forbidden LuaTable use ("tbl.set(...([\\"field\\", 0] as const))"): code 1`] = `"tbl[table.unpack({\\"field\\", 0})] = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set(...([\\"field\\", 0] as const))"): code 2`] = `"tbl[table.unpack({\\"field\\", 0})] = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set(...([\\"field\\", 0] as const))"): diagnostics 1`] = `"main.ts(11,9): error TSTL: Invalid @luaTable usage: Arguments cannot be spread."`; + +exports[`Forbidden LuaTable use ("tbl.set(...([\\"field\\", 0] as const))"): diagnostics 2`] = `"main.ts(13,9): error TSTL: Invalid @luaTable usage: Arguments cannot be spread."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\")"): code 1`] = `"tbl.field = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\")"): code 2`] = `"tbl.field = nil"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\")"): diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 1."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\")"): diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 1."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", ...([0] as const))"): code 1`] = `"tbl.field = table.unpack({0})"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", ...([0] as const))"): code 2`] = `"tbl.field = table.unpack({0})"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", ...([0] as const))"): diagnostics 1`] = `"main.ts(11,18): error TSTL: Invalid @luaTable usage: Arguments cannot be spread."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", ...([0] as const))"): diagnostics 2`] = `"main.ts(13,18): error TSTL: Invalid @luaTable usage: Arguments cannot be spread."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", 0, 1)"): code 1`] = `"tbl.field = 0"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", 0, 1)"): code 2`] = `"tbl.field = 0"`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", 0, 1)"): diagnostics 1`] = `"main.ts(11,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 3."`; + +exports[`Forbidden LuaTable use ("tbl.set(\\"field\\", 0, 1)"): diagnostics 2`] = `"main.ts(13,1): error TSTL: Invalid @luaTable usage: Expected 2 arguments, but got 3."`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ class Table {}"): code 1`] = ` +"require(\\"lualib_bundle\\"); +Table = __TS__Class() +Table.name = \\"Table\\" +function Table.prototype.____constructor(self) +end" +`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ class Table {}"): diagnostics 1`] = `"main.ts(1,18): error TSTL: Classes with the '@luaTable' annotation must be ambient."`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ const c = class Table {}"): code 1`] = ` +"require(\\"lualib_bundle\\"); +c = (function() + local Table = __TS__Class() + Table.name = \\"Table\\" + function Table.prototype.____constructor(self) + end + return Table +end)()" +`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ const c = class Table {}"): diagnostics 1`] = `"main.ts(1,28): error TSTL: Classes with the '@luaTable' annotation must be ambient."`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ export class Table {}"): code 1`] = ` +"require(\\"lualib_bundle\\"); +local ____exports = {} +____exports.Table = __TS__Class() +local Table = ____exports.Table +Table.name = \\"Table\\" +function Table.prototype.____constructor(self) +end +return ____exports" +`; + +exports[`LuaTable classes must be ambient ("/** @luaTable */ export class Table {}"): diagnostics 1`] = `"main.ts(1,18): error TSTL: Classes with the '@luaTable' annotation must be ambient."`; + +exports[`LuaTable set() cannot be used in a LuaTable call expression: code 1`] = `"exp = tbl:set(\\"value\\", 5)"`; + +exports[`LuaTable set() cannot be used in a LuaTable call expression: code 2`] = `"exp = tbl:set(\\"value\\", 5)"`; + +exports[`LuaTable set() cannot be used in a LuaTable call expression: diagnostics 1`] = `"main.ts(11,17): error TSTL: LuaTable.set is unsupported."`; + +exports[`LuaTable set() cannot be used in a LuaTable call expression: diagnostics 2`] = `"main.ts(13,17): error TSTL: LuaTable.set is unsupported."`; + +exports[`LuaTables cannot be constructed with arguments: code 1`] = `"____table = {}"`; + +exports[`LuaTables cannot be constructed with arguments: diagnostics 1`] = `"main.ts(11,15): error TSTL: Invalid @luaTable usage: No parameters are allowed when constructing a LuaTable object."`; + +exports[`LuaTables cannot have other members: code 1`] = `"tbl:other()"`; + +exports[`LuaTables cannot have other members: code 2`] = `"tbl:other()"`; + +exports[`LuaTables cannot have other members: code 3`] = `"x = tbl:other()"`; + +exports[`LuaTables cannot have other members: code 4`] = `"x = tbl:other()"`; + +exports[`LuaTables cannot have other members: diagnostics 1`] = `"main.ts(11,5): error TSTL: LuaTable.other is unsupported."`; + +exports[`LuaTables cannot have other members: diagnostics 2`] = `"main.ts(13,5): error TSTL: LuaTable.other is unsupported."`; + +exports[`LuaTables cannot have other members: diagnostics 3`] = `"main.ts(11,13): error TSTL: LuaTable.other is unsupported."`; + +exports[`LuaTables cannot have other members: diagnostics 4`] = `"main.ts(13,13): error TSTL: LuaTable.other is unsupported."`; diff --git a/test/unit/annotations/__snapshots__/metaExtension.spec.ts.snap b/test/unit/annotations/__snapshots__/metaExtension.spec.ts.snap new file mode 100644 index 000000000..ba6b5e0a1 --- /dev/null +++ b/test/unit/annotations/__snapshots__/metaExtension.spec.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DontAllowInstantiation: code 1`] = ` +"require(\\"lualib_bundle\\"); +local __meta___LOADED = debug.getregistry()._LOADED +e = __TS__New(Ext)" +`; + +exports[`DontAllowInstantiation: diagnostics 1`] = `"main.ts(5,19): error TSTL: Cannot construct classes with '@extension' or '@metaExtension' annotation."`; + +exports[`IncorrectUsage: code 1`] = ` +"function LoadedExt.test(self) + return 5 +end" +`; + +exports[`IncorrectUsage: diagnostics 1`] = `"main.ts(3,9): error TSTL: '@metaExtension' annotation requires the extension of the metatable class."`; diff --git a/test/unit/annotations/customConstructor.spec.ts b/test/unit/annotations/customConstructor.spec.ts index 856a566f0..cd77bcca6 100644 --- a/test/unit/annotations/customConstructor.spec.ts +++ b/test/unit/annotations/customConstructor.spec.ts @@ -1,4 +1,4 @@ -import { InvalidAnnotationArgumentNumber } from "../../../src/transformation/utils/errors"; +import { annotationInvalidArgumentCount } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("CustomCreate", () => { @@ -25,16 +25,10 @@ test("CustomCreate", () => { }); test("IncorrectUsage", () => { - expect(() => { - util.transpileString(` - /** @customConstructor */ - class Point2D { - constructor( - public x: number, - public y: number - ) {} - } - return new Point2D(1, 2).x; - `); - }).toThrowExactError(InvalidAnnotationArgumentNumber("@customConstructor", 0, 1, util.nodeStub)); + util.testFunction` + /** @customConstructor */ + class Point2D {} + + new Point2D(); + `.expectDiagnosticsToMatchSnapshot([annotationInvalidArgumentCount.code]); }); diff --git a/test/unit/annotations/extension.spec.ts b/test/unit/annotations/extension.spec.ts index 18e41719c..c8da1b81b 100644 --- a/test/unit/annotations/extension.spec.ts +++ b/test/unit/annotations/extension.spec.ts @@ -1,28 +1,26 @@ import { - InvalidExtendsExtension, - InvalidInstanceOfExtension, - InvalidNewExpressionOnExtension, -} from "../../../src/transformation/utils/errors"; + extensionCannotConstruct, + extensionCannotExtend, + extensionInvalidInstanceOf, +} from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test.each(["extension", "metaExtension"])("Class extends extension (%p)", extensionType => { - const code = ` + util.testModule` declare class A {} /** @${extensionType} **/ class B extends A {} class C extends B {} - `; - expect(() => util.transpileString(code)).toThrowExactError(InvalidExtendsExtension(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([extensionCannotExtend.code]); }); test.each(["extension", "metaExtension"])("Class construct extension (%p)", extensionType => { - const code = ` + util.testModule` declare class A {} /** @${extensionType} **/ class B extends A {} const b = new B(); - `; - expect(() => util.transpileString(code)).toThrowExactError(InvalidNewExpressionOnExtension(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([extensionCannotConstruct.code]); }); test.each(["extension", "metaExtension"])("instanceof extension (%p)", extensionType => { @@ -32,5 +30,5 @@ test.each(["extension", "metaExtension"])("instanceof extension (%p)", extension class B extends A {} declare const foo: any; const result = foo instanceof B; - `.expectToHaveDiagnosticOfError(InvalidInstanceOfExtension(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([extensionInvalidInstanceOf.code]); }); diff --git a/test/unit/annotations/forRange.spec.ts b/test/unit/annotations/forRange.spec.ts index d49fa5c1c..661c45253 100644 --- a/test/unit/annotations/forRange.spec.ts +++ b/test/unit/annotations/forRange.spec.ts @@ -1,108 +1,83 @@ -import * as ts from "typescript"; -import { InvalidForRangeCall } from "../../../src/transformation/utils/errors"; +import { invalidForRangeCall } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; +const createForRangeDeclaration = (args = "i: number, j: number, k?: number", returns = "number[]") => ` + /** @forRange */ + declare function luaRange(${args}): ${returns}; +`; + test.each([ - { args: [1, 10], expectResult: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }, - { args: [1, 10, 2], expectResult: [1, 3, 5, 7, 9] }, - { args: [10, 1, -1], expectResult: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] }, - { args: [10, 1, -2], expectResult: [10, 8, 6, 4, 2] }, -])("@forRange loop", ({ args, expectResult }) => { - const tsHeader = "/** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[];"; - const code = ` - const results: number[] = []; + { args: [1, 10], results: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }, + { args: [1, 10, 2], results: [1, 3, 5, 7, 9] }, + { args: [10, 1, -1], results: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] }, + { args: [10, 1, -2], results: [10, 8, 6, 4, 2] }, +])("usage in for...of loop", ({ args, results }) => { + util.testModule` + ${createForRangeDeclaration()} + export const results: number[] = []; + for (const i of luaRange(${args})) { results.push(i); } - return JSONStringify(results);`; - - const result = util.transpileAndExecute(code, undefined, undefined, tsHeader); - expect(JSON.parse(result)).toEqual(expectResult); -}); - -test("invalid non-ambient @forRange function", () => { - const code = ` - /** @forRange **/ function luaRange(i: number, j: number, k?: number): number[] { return []; } - for (const i of luaRange(1, 10, 2)) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall( - ts.createEmptyStatement(), - "@forRange function can only be used as an iterable in a for...of loop." - ).message - ); -}); - -test.each([[1], [1, 2, 3, 4]])("invalid @forRange argument count", (...args) => { - const code = ` - /** @forRange **/ declare function luaRange(...args: number[]): number[] { return []; } - for (const i of luaRange(${util.formatCode(...args)})) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall(ts.createEmptyStatement(), "@forRange function must take 2 or 3 arguments.").message - ); -}); - -test("invalid @forRange control variable", () => { - const code = ` - /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[]; - let i: number; - for (i of luaRange(1, 10, 2)) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall(ts.createEmptyStatement(), "@forRange loop must declare its own control variable.").message - ); + ` + .setReturnExport("results") + .expectToEqual(results); }); -test("invalid @forRange argument type", () => { - const code = ` - /** @forRange **/ declare function luaRange(i: string, j: number): number[] { return []; } - for (const i of luaRange("foo", 2)) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall(ts.createEmptyStatement(), "@forRange arguments must be number types.").message - ); -}); - -test("invalid @forRange destructuring", () => { - const code = ` - /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[][]; - for (const [i] of luaRange(1, 10, 2)) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall(ts.createEmptyStatement(), "@forRange loop cannot use destructuring.").message - ); -}); - -test("invalid @forRange return type", () => { - const code = ` - /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): string[]; - for (const i of luaRange(1, 10)) {}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall( - ts.createEmptyStatement(), - "@forRange function must return Iterable or Array." - ).message - ); -}); - -test.each([ - "const range = luaRange(1, 10);", - "console.log(luaRange);", - "luaRange.call(null, 0, 0, 0);", - "let array = [0, luaRange, 1];", - "const call: any; call(luaRange);", - "for (const i of [...luaRange(1, 10)]) {}", -])("invalid @forRange reference (%p)", statement => { - const code = ` - /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[]; - ${statement}`; - - expect(() => util.transpileString(code)).toThrow( - InvalidForRangeCall( - ts.createEmptyStatement(), - "@forRange function can only be used as an iterable in a for...of loop." - ).message - ); +describe("invalid usage", () => { + test("non-ambient declaration", () => { + util.testModule` + /** @forRange */ + function luaRange() {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test.each<[number[]]>([[[]], [[1]], [[1, 2, 3, 4]]])("argument count (%p)", args => { + util.testModule` + ${createForRangeDeclaration("...args: number[]")} + for (const i of luaRange(${args})) {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test("non-declared loop variable", () => { + util.testModule` + ${createForRangeDeclaration()} + let i: number; + for (i of luaRange(1, 10, 2)) {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test("argument types", () => { + util.testModule` + ${createForRangeDeclaration("i: string, j: number")} + for (const i of luaRange("foo", 2)) {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test("variable destructuring", () => { + util.testModule` + ${createForRangeDeclaration(undefined, "number[][]")} + for (const [i] of luaRange(1, 10, 2)) {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test("return type", () => { + util.testModule` + ${createForRangeDeclaration(undefined, "string[]")} + for (const i of luaRange(1, 10)) {} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); + + test.each([ + "const range = luaRange(1, 10);", + "luaRange.call(null, 0, 0, 0);", + "let array = [0, luaRange, 1];", + "const call = undefined as any; call(luaRange);", + "for (const i of [...luaRange(1, 10)]) {}", + ])("reference (%p)", statement => { + util.testModule` + ${createForRangeDeclaration()} + ${statement} + `.expectDiagnosticsToMatchSnapshot([invalidForRangeCall.code]); + }); }); diff --git a/test/unit/annotations/luaIterator.spec.ts b/test/unit/annotations/luaIterator.spec.ts index 122c6e7fb..46e324bc5 100644 --- a/test/unit/annotations/luaIterator.spec.ts +++ b/test/unit/annotations/luaIterator.spec.ts @@ -1,7 +1,5 @@ -import * as ts from "typescript"; -import * as tstl from "../../../src"; -import { UnsupportedNonDestructuringLuaIterator } from "../../../src/transformation/utils/errors"; import * as util from "../../util"; +import { luaIteratorForbiddenUsage } from "../../../src/transformation/utils/diagnostics"; test("forof lua iterator", () => { const code = ` @@ -16,12 +14,7 @@ test("forof lua iterator", () => { for (let e of luaIter()) { result += e; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("abc"); }); @@ -38,12 +31,7 @@ test("forof array lua iterator", () => { for (let e of luaIter()) { result += e; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("abc"); }); @@ -61,12 +49,7 @@ test("forof lua iterator with existing variable", () => { for (e of luaIter()) { result += e; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("abc"); }); @@ -83,12 +66,7 @@ test("forof lua iterator destructuring", () => { for (let [a, b] of luaIter()) { result += a + b; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("0a1b2c"); }); @@ -107,12 +85,7 @@ test("forof lua iterator destructuring with existing variables", () => { for ([a, b] of luaIter()) { result += a + b; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("0a1b2c"); }); @@ -134,12 +107,7 @@ test("forof lua iterator tuple-return", () => { for (let [a, b] of luaIter()) { result += a + b; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("0a1b2c"); }); @@ -163,17 +131,12 @@ test("forof lua iterator tuple-return with existing variables", () => { for ([a, b] of luaIter()) { result += a + b; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("0a1b2c"); }); test("forof lua iterator tuple-return single variable", () => { - const code = ` + util.testModule` /** * @luaIterator * @tupleReturn @@ -181,19 +144,11 @@ test("forof lua iterator tuple-return single variable", () => { interface Iter extends Iterable<[string, string]> {} declare function luaIter(): Iter; for (let x of luaIter()) {} - `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( - UnsupportedNonDestructuringLuaIterator(util.nodeStub) - ); + `.expectDiagnosticsToMatchSnapshot([luaIteratorForbiddenUsage.code]); }); test("forof lua iterator tuple-return single existing variable", () => { - const code = ` + util.testModule` /** * @luaIterator * @tupleReturn @@ -202,15 +157,7 @@ test("forof lua iterator tuple-return single existing variable", () => { declare function luaIter(): Iter; let x: [string, string]; for (x of luaIter()) {} - `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( - UnsupportedNonDestructuringLuaIterator(util.nodeStub) - ); + `.expectDiagnosticsToMatchSnapshot([luaIteratorForbiddenUsage.code]); }); test("forof forwarded lua iterator", () => { @@ -231,12 +178,7 @@ test("forof forwarded lua iterator", () => { for (let a of forward()) { result += a; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("abc"); }); @@ -262,11 +204,6 @@ test("forof forwarded lua iterator with tupleReturn", () => { for (let [a, b] of forward()) { result += a + b; } return result; `; - const compilerOptions = { - luaLibImport: tstl.LuaLibImportKind.Require, - luaTarget: tstl.LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); + const result = util.transpileAndExecute(code); expect(result).toBe("0a1b2c"); }); diff --git a/test/unit/annotations/luaTable.spec.ts b/test/unit/annotations/luaTable.spec.ts index 95813e5ce..ec7d1af35 100644 --- a/test/unit/annotations/luaTable.spec.ts +++ b/test/unit/annotations/luaTable.spec.ts @@ -1,21 +1,20 @@ -import * as ts from "typescript"; import { - ForbiddenLuaTableNonDeclaration, - ForbiddenLuaTableUseException, - InvalidExtendsLuaTable, - InvalidInstanceOfLuaTable, - UnsupportedKind, - UnsupportedProperty, -} from "../../../src/transformation/utils/errors"; + luaTableCannotBeAccessedDynamically, + luaTableCannotBeExtended, + luaTableForbiddenUsage, + luaTableMustBeAmbient, + unsupportedProperty, + luaTableInvalidInstanceOf, +} from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; const tableLibClass = ` /** @luaTable */ declare class Table { length: number; - constructor(notAllowed?: boolean); - set(key?: K, value?: V): void; - get(key?: K): V; + constructor(notAllowed?: any); + set(key?: K, value?: V, notAllowed?: any): void; + get(key?: K, notAllowed?: any): V; other(): void; } declare let tbl: Table; @@ -25,39 +24,37 @@ const tableLibInterface = ` /** @luaTable */ declare interface Table { length: number; - constructor(notAllowed?: boolean); - set(key?: K, value?: V): void; - get(key?: K): V; + set(key?: K, value?: V, notAllowed?: any): void; + get(key?: K, notAllowed?: any): V; other(): void; } + +/** @luaTable */ +declare const Table: new (notAllowed?: any) => Table; declare let tbl: Table; `; test.each([tableLibClass])("LuaTables cannot be constructed with arguments", tableLib => { - expect(() => util.transpileString(tableLib + `const table = new Table(true);`)).toThrowExactError( - ForbiddenLuaTableUseException("No parameters are allowed when constructing a LuaTable object.", util.nodeStub) - ); + util.testModule(tableLib + `const table = new Table(true);`).expectDiagnosticsToMatchSnapshot([ + luaTableForbiddenUsage.code, + ]); }); test.each([tableLibClass, tableLibInterface])( "LuaTable set() cannot be used in a LuaTable call expression", tableLib => { - expect(() => util.transpileString(tableLib + `const exp = tbl.set("value", 5)`)).toThrowExactError( - UnsupportedProperty("LuaTable", "set", util.nodeStub) - ); + util.testModule(tableLib + `const exp = tbl.set("value", 5)`).expectDiagnosticsToMatchSnapshot([ + unsupportedProperty.code, + ]); } ); test.each([tableLibClass, tableLibInterface])("LuaTables cannot have other members", tableLib => { - expect(() => util.transpileString(tableLib + `tbl.other()`)).toThrowExactError( - UnsupportedProperty("LuaTable", "other", util.nodeStub) - ); + util.testModule(tableLib + `tbl.other()`).expectDiagnosticsToMatchSnapshot([unsupportedProperty.code]); }); test.each([tableLibClass, tableLibInterface])("LuaTables cannot have other members", tableLib => { - expect(() => util.transpileString(tableLib + `let x = tbl.other()`)).toThrowExactError( - UnsupportedProperty("LuaTable", "other", util.nodeStub) - ); + util.testModule(tableLib + `let x = tbl.other()`).expectDiagnosticsToMatchSnapshot([unsupportedProperty.code]); }); test.each([tableLibClass])("LuaTable new", tableLib => { @@ -72,23 +69,20 @@ test.each([tableLibClass])("LuaTable length", tableLib => { }); test.each([tableLibClass, tableLibInterface])("Cannot set LuaTable length", tableLib => { - expect(() => util.transpileString(tableLib + `tbl.length = 2;`)).toThrowExactError( - ForbiddenLuaTableUseException("A LuaTable object's length cannot be re-assigned.", util.nodeStub) - ); + util.testModule(tableLib + `tbl.length = 2;`).expectDiagnosticsToMatchSnapshot([luaTableForbiddenUsage.code]); }); test.each([tableLibClass, tableLibInterface])("Forbidden LuaTable use", tableLib => { test.each([ - [`tbl.get()`, "One parameter is required for get()."], - [`tbl.get("field", "field2")`, "One parameter is required for get()."], - [`tbl.set()`, "Two parameters are required for set()."], - [`tbl.set("field")`, "Two parameters are required for set()."], - [`tbl.set("field", 0, 1)`, "Two parameters are required for set()."], - [`tbl.set("field", ...[0, 1])`, "Arguments cannot be spread."], - ])("Forbidden LuaTable use (%p)", (invalidCode, errorDescription) => { - expect(() => util.transpileString(tableLib + invalidCode)).toThrowExactError( - ForbiddenLuaTableUseException(errorDescription, util.nodeStub) - ); + "tbl.get()", + 'tbl.get("field", "field2")', + "tbl.set()", + 'tbl.set("field")', + 'tbl.set("field", 0, 1)', + 'tbl.set(...(["field", 0] as const))', + 'tbl.set("field", ...([0] as const))', + ])("Forbidden LuaTable use (%p)", invalidCode => { + util.testModule(tableLib + invalidCode).expectDiagnosticsToMatchSnapshot([luaTableForbiddenUsage.code]); }); }); @@ -96,9 +90,7 @@ test.each([tableLibClass])("Cannot extend LuaTable class", tableLib => { test.each([`class Ext extends Table {}`, `const c = class Ext extends Table {}`])( "Cannot extend LuaTable class (%p)", code => { - expect(() => util.transpileString(tableLib + code)).toThrowExactError( - InvalidExtendsLuaTable(util.nodeStub) - ); + util.testModule(tableLib + code).expectDiagnosticsToMatchSnapshot([luaTableCannotBeExtended.code]); } ); }); @@ -108,12 +100,12 @@ test.each([ `/** @luaTable */ export class Table {}`, `/** @luaTable */ const c = class Table {}`, ])("LuaTable classes must be ambient (%p)", code => { - expect(() => util.transpileString(code)).toThrowExactError(ForbiddenLuaTableNonDeclaration(util.nodeStub)); + util.testModule(code).expectDiagnosticsToMatchSnapshot([luaTableMustBeAmbient.code]); }); test.each([tableLibClass])("Cannot extend LuaTable class", tableLib => { test.each([`tbl instanceof Table`])("Cannot use instanceof on a LuaTable class (%p)", code => { - expect(() => util.transpileString(tableLib + code)).toThrowExactError(InvalidInstanceOfLuaTable(util.nodeStub)); + util.testModule(tableLib + code).expectDiagnosticsToMatchSnapshot([luaTableInvalidInstanceOf.code]); }); }); @@ -121,18 +113,18 @@ test.each([tableLibClass, tableLibInterface])("Cannot use ElementAccessExpressio test.each([`tbl["get"]("field")`, `tbl["set"]("field")`, `tbl["length"]`])( "Cannot use ElementAccessExpression on a LuaTable (%p)", code => { - expect(() => util.transpileString(tableLib + code)).toThrowExactError( - UnsupportedKind("LuaTable access expression", ts.SyntaxKind.ElementAccessExpression, util.nodeStub) - ); + util.testModule(tableLib + code).expectDiagnosticsToMatchSnapshot([ + luaTableCannotBeAccessedDynamically.code, + ]); } ); }); test.each([tableLibClass, tableLibInterface])("Cannot isolate LuaTable methods", tableLib => { test.each([`set`, `get`])("Cannot isolate LuaTable method (%p)", propertyName => { - expect(() => util.transpileString(`${tableLib} let property = tbl.${propertyName}`)).toThrowExactError( - UnsupportedProperty("LuaTable", propertyName, util.nodeStub) - ); + util.testModule(`${tableLib} let property = tbl.${propertyName}`).expectDiagnosticsToMatchSnapshot([ + unsupportedProperty.code, + ]); }); }); diff --git a/test/unit/annotations/metaExtension.spec.ts b/test/unit/annotations/metaExtension.spec.ts index 76b40c791..da0f1992a 100644 --- a/test/unit/annotations/metaExtension.spec.ts +++ b/test/unit/annotations/metaExtension.spec.ts @@ -1,4 +1,4 @@ -import { InvalidNewExpressionOnExtension, MissingMetaExtension } from "../../../src/transformation/utils/errors"; +import { extensionCannotConstruct, metaExtensionMissingExtends } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("MetaExtension", () => { @@ -26,26 +26,21 @@ test("MetaExtension", () => { }); test("IncorrectUsage", () => { - expect(() => { - util.transpileString(` - /** @metaExtension */ - class LoadedExt { - public static test() { - return 5; - } + util.testModule` + /** @metaExtension */ + class LoadedExt { + public static test() { + return 5; } - `); - }).toThrowExactError(MissingMetaExtension(util.nodeStub)); + } + `.expectDiagnosticsToMatchSnapshot([metaExtensionMissingExtends.code]); }); test("DontAllowInstantiation", () => { - expect(() => { - util.transpileString(` - declare class _LOADED {} - /** @metaExtension */ - class Ext extends _LOADED { - } - const e = new Ext(); - `); - }).toThrowExactError(InvalidNewExpressionOnExtension(util.nodeStub)); + util.testModule` + declare class _LOADED {} + /** @metaExtension */ + class Ext extends _LOADED {} + const e = new Ext(); + `.expectDiagnosticsToMatchSnapshot([extensionCannotConstruct.code]); }); diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index ce7abd622..1a8665464 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -1,3 +1,4 @@ +import { unsupportedVarDeclaration } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test.each(["const", "let"])("%s declaration not top-level is not global", declarationKind => { @@ -21,25 +22,25 @@ test.each(["const", "let"])("%s declaration top-level is global", declarationKin test("var declaration is disallowed", () => { util.testFunction` var foo = true; - `.expectToHaveDiagnostics(); + `.expectDiagnosticsToMatchSnapshot([unsupportedVarDeclaration.code]); }); test("var declaration in for loop is disallowed", () => { util.testFunction` for (var foo = 0;;) {} - `.expectToHaveDiagnostics(); + `.expectDiagnosticsToMatchSnapshot([unsupportedVarDeclaration.code]); }); test("var declaration in for...in loop is disallowed", () => { util.testFunction` for (var foo in {}) {} - `.expectToHaveDiagnostics(); + `.expectDiagnosticsToMatchSnapshot([unsupportedVarDeclaration.code]); }); test("var declaration in for...of loop is disallowed", () => { util.testFunction` for (var foo of []) {} - `.expectToHaveDiagnostics(); + `.expectDiagnosticsToMatchSnapshot([unsupportedVarDeclaration.code]); }); test.each(["let myvar;", "const myvar = null;", "const myvar = undefined;"])("Null assignments (%p)", declaration => { diff --git a/test/unit/builtins/__snapshots__/loading.spec.ts.snap b/test/unit/builtins/__snapshots__/loading.spec.ts.snap new file mode 100644 index 000000000..de7fb50b4 --- /dev/null +++ b/test/unit/builtins/__snapshots__/loading.spec.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Unknown builtin property access: code 1`] = ` +"local ____exports = {} +____exports.__result = Math.unknownProperty +return ____exports" +`; + +exports[`Unknown builtin property access: diagnostics 1`] = `"main.ts(1,30): error TSTL: Math.unknownProperty is unsupported."`; diff --git a/test/unit/builtins/loading.spec.ts b/test/unit/builtins/loading.spec.ts index d1e5c204a..9284363be 100644 --- a/test/unit/builtins/loading.spec.ts +++ b/test/unit/builtins/loading.spec.ts @@ -1,5 +1,5 @@ import * as tstl from "../../../src"; -import { UnsupportedProperty } from "../../../src/transformation/utils/errors"; +import { unsupportedProperty } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; describe("luaLibImport", () => { @@ -42,6 +42,6 @@ describe("Unknown builtin property", () => { test("access", () => { util.testExpression`Math.unknownProperty` .disableSemanticCheck() - .expectToHaveDiagnosticOfError(UnsupportedProperty("Math", "unknownProperty", util.nodeStub)); + .expectDiagnosticsToMatchSnapshot([unsupportedProperty.code]); }); }); diff --git a/test/unit/builtins/set.spec.ts b/test/unit/builtins/set.spec.ts index cbd8cb3f4..2c58e5df8 100644 --- a/test/unit/builtins/set.spec.ts +++ b/test/unit/builtins/set.spec.ts @@ -109,7 +109,7 @@ test("set keys", () => { util.testFunction` let myset = new Set([5, 6, 7]); let count = 0; - for (var key of myset.keys()) { count += key; } + for (const key of myset.keys()) { count += key; } return count; `.expectToMatchJsResult(); }); @@ -118,7 +118,7 @@ test("set values", () => { util.testFunction` let myset = new Set([5, 6, 7]); let count = 0; - for (var value of myset.values()) { count += value; } + for (const value of myset.values()) { count += value; } return count; `.expectToMatchJsResult(); }); diff --git a/test/unit/bundle.spec.ts b/test/unit/bundle.spec.ts index 582b79177..3d9520da4 100644 --- a/test/unit/bundle.spec.ts +++ b/test/unit/bundle.spec.ts @@ -1,20 +1,9 @@ import * as path from "path"; import * as ts from "typescript"; -import { DiagnosticCategory } from "typescript"; import { LuaLibImportKind } from "../../src"; -import { couldNotFindBundleEntryPoint } from "../../src/transpilation/diagnostics"; +import * as diagnosticFactories from "../../src/transpilation/diagnostics"; import * as util from "../util"; -test("no entry point", () => { - util.testBundle`` - .setOptions({ luaBundleEntry: undefined }) - .expectToHaveDiagnostic( - d => - d.messageText === `'luaBundleEntry' is required when 'luaBundle' is enabled.` && - d.category === DiagnosticCategory.Error - ); -}); - test("import module -> main", () => { util.testBundle` export { value } from "./module"; @@ -24,14 +13,14 @@ test("import module -> main", () => { }); test("bundle file name", () => { - const { diagnostics, transpiledFiles } = util.testModule` - export { value } from "./module"; -` + const { transpiledFiles } = util.testModule` + export { value } from "./module"; + ` .addExtraFile("module.ts", "export const value = true") .setOptions({ luaBundle: "mybundle.lua", luaBundleEntry: "main.ts" }) + .expectToHaveNoDiagnostics() .getLuaResult(); - expect(diagnostics.length).toBe(0); expect(transpiledFiles.length).toBe(1); expect(transpiledFiles[0].fileName).toBe( path.join(ts.sys.getCurrentDirectory(), "mybundle.lua").replace(/\\/g, "/") @@ -87,35 +76,26 @@ test("entry point in directory", () => { .expectToEqual({ value: true }); }); -test.each([LuaLibImportKind.Inline, LuaLibImportKind.Require])("LuaLib %p", lualibOption => { - const testBundle = util.testBundle` +test("LuaLibImportKind.Require", () => { + util.testBundle` export const result = [1, 2]; result.push(3); - `.setOptions({ luaLibImport: lualibOption }); - - if (lualibOption === LuaLibImportKind.Inline) { - testBundle.expectToHaveDiagnostic(d => d.category === DiagnosticCategory.Warning); - } else { - expect(testBundle.getLuaResult().diagnostics).toEqual([]); - } - expect(testBundle.getLuaExecutionResult()).toEqual({ result: [1, 2, 3] }); + ` + .setOptions({ luaLibImport: LuaLibImportKind.Require }) + .expectToEqual({ result: [1, 2, 3] }); }); -test("LuaBundle and LuaLibImport.Inline generate warning", () => { - const testBundle = util.testBundle` +test("LuaLibImportKind.Inline generates a warning", () => { + util.testBundle` export const result = [1, 2]; result.push(3); ` .setOptions({ luaLibImport: LuaLibImportKind.Inline }) - .expectToHaveDiagnostic( - d => - d.category === DiagnosticCategory.Warning && - d.messageText === - `Using 'luaBundle' with 'luaLibImport: "inline"' might generate duplicate code. ` + - `It is recommended to use 'luaLibImport: "require"'` - ); - - expect(testBundle.getLuaExecutionResult()).toEqual({ result: [1, 2, 3] }); // Result should still be the same + .expectDiagnosticsToMatchSnapshot( + [diagnosticFactories.usingLuaBundleWithInlineMightGenerateDuplicateCode.code], + true + ) + .expectToEqual({ result: [1, 2, 3] }); }); test("cyclic imports", () => { @@ -136,6 +116,14 @@ test("cyclic imports", () => { .expectToEqual(new util.ExecutionError("stack overflow")); }); +test("no entry point", () => { + util.testBundle`` + .setOptions({ luaBundleEntry: undefined }) + .expectDiagnosticsToMatchSnapshot([diagnosticFactories.luaBundleEntryIsRequired.code], true); +}); + test("luaEntry doesn't exist", () => { - util.testBundle``.setEntryPoint("entry.ts").expectToHaveExactDiagnostic(couldNotFindBundleEntryPoint("entry.ts")); + util.testBundle`` + .setEntryPoint("entry.ts") + .expectDiagnosticsToMatchSnapshot([diagnosticFactories.couldNotFindBundleEntryPoint.code], true); }); diff --git a/test/unit/classes/__snapshots__/classes.spec.ts.snap b/test/unit/classes/__snapshots__/classes.spec.ts.snap new file mode 100644 index 000000000..0acca51b6 --- /dev/null +++ b/test/unit/classes/__snapshots__/classes.spec.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`missing declaration name: code 1`] = ` +"require(\\"lualib_bundle\\"); +____ = __TS__Class() +____.name = \\"____\\" +function ____.prototype.____constructor(self) +end" +`; + +exports[`missing declaration name: diagnostics 1`] = `"main.ts(2,9): error TS1211: A class declaration without the 'default' modifier must have a name."`; + +exports[`super without class: code 1`] = ` +"local ____exports = {} +____exports.__result = ____.____constructor(self) +return ____exports" +`; + +exports[`super without class: diagnostics 1`] = `"main.ts(1,25): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors."`; diff --git a/test/unit/classes/__snapshots__/decorators.spec.ts.snap b/test/unit/classes/__snapshots__/decorators.spec.ts.snap new file mode 100644 index 000000000..cbc983bd5 --- /dev/null +++ b/test/unit/classes/__snapshots__/decorators.spec.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Throws error if decorator function has void context: code 1`] = ` +"require(\\"lualib_bundle\\"); +local ____exports = {} +function ____exports.__main(self) + local function decorator(constructor) + end + local TestClass = __TS__Class() + TestClass.name = \\"TestClass\\" + function TestClass.prototype.____constructor(self) + end + TestClass = __TS__Decorate({decorator}, TestClass) +end +return ____exports" +`; + +exports[`Throws error if decorator function has void context: diagnostics 1`] = `"main.ts(4,9): error TSTL: Decorator function cannot have 'this: void'."`; diff --git a/test/unit/classes/classes.spec.ts b/test/unit/classes/classes.spec.ts index 12751fd40..0e6761fbc 100644 --- a/test/unit/classes/classes.spec.ts +++ b/test/unit/classes/classes.spec.ts @@ -236,6 +236,26 @@ test("Subclass constructor across merged namespace", () => { expect(util.transpileAndExecute("return (new NS.Sub()).prop", undefined, undefined, tsHeader)).toBe("foo"); }); +test("super without class", () => { + util.testExpression`super()`.expectDiagnosticsToMatchSnapshot([2337]); +}); + +test("super in unnamed class", () => { + util.testFunction` + class Foo { + public x = true; + } + + const Bar = (class extends (Foo) { + constructor() { + super(); + } + }); + + return new Bar().x; + `.expectToMatchJsResult(); +}); + test("classSuper", () => { const result = util.transpileAndExecute( `class a { @@ -829,3 +849,9 @@ test("Class field override in subclass with constructors", () => { return (new Foo()).field + (new Bar()).field;`; expect(util.transpileAndExecute(code)).toBe("foobar"); }); + +test("missing declaration name", () => { + util.testModule` + class {} + `.expectDiagnosticsToMatchSnapshot([1211]); +}); diff --git a/test/unit/classes/decorators.spec.ts b/test/unit/classes/decorators.spec.ts index 7d4223ecd..ad77a3a11 100644 --- a/test/unit/classes/decorators.spec.ts +++ b/test/unit/classes/decorators.spec.ts @@ -1,4 +1,4 @@ -import { InvalidDecoratorContext } from "../../../src/transformation/utils/errors"; +import { decoratorInvalidContext } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("Class decorator with no parameters", () => { @@ -105,11 +105,11 @@ test("Class decorators are applied in order and executed in reverse order", () = test("Throws error if decorator function has void context", () => { util.testFunction` - function SetBool(this: void, constructor: new (...args: any[]) => {}) {} + function decorator(this: void, constructor: new (...args: any[]) => {}) {} - @SetBool + @decorator class TestClass {} - `.expectToHaveDiagnosticOfError(InvalidDecoratorContext(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([decoratorInvalidContext.code]); }); test("Exported class decorator", () => { diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index a11fd0595..890c6dc71 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,5 +1,5 @@ import * as tstl from "../../src"; -import { UnsupportedForTarget } from "../../src/transformation/utils/errors"; +import { unsupportedForTarget } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test.each([0, 1])("if (%p)", inp => { @@ -345,7 +345,7 @@ test("switch not allowed in 5.1", () => { switch ("abc") {} ` .setOptions({ luaTarget: tstl.LuaTarget.Lua51 }) - .expectToHaveDiagnosticOfError(UnsupportedForTarget("Switch statements", tstl.LuaTarget.Lua51, util.nodeStub)); + .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); }); test.each([ diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 8f3121c86..90211b78c 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,6 +1,5 @@ -import * as ts from "typescript"; import * as tstl from "../../src"; -import { UnsupportedForTarget, UnsupportedKind } from "../../src/transformation/utils/errors"; +import { unsupportedForTarget, unsupportedRightShiftOperator } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; // TODO: @@ -67,7 +66,7 @@ test.each(allBinaryOperators)("Bitop [5.1] (%p)", input => { util.testExpression(input) .setOptions({ luaTarget: tstl.LuaTarget.Lua51, luaLibImport: tstl.LuaLibImportKind.None }) .disableSemanticCheck() - .expectToHaveDiagnosticOfError(UnsupportedForTarget("Bitwise operations", tstl.LuaTarget.Lua51, util.nodeStub)); + .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); }); test.each(allBinaryOperators)("Bitop [JIT] (%p)", input => { @@ -95,13 +94,7 @@ test.each(unsupportedIn53)("Unsupported bitop 5.3 (%p)", input => { util.testExpression(input) .setOptions({ luaTarget: tstl.LuaTarget.Lua53, luaLibImport: tstl.LuaLibImportKind.None }) .disableSemanticCheck() - .expectToHaveDiagnosticOfError( - UnsupportedKind( - "right shift operator (use >>> instead)", - ts.SyntaxKind.GreaterThanGreaterThanToken, - util.nodeStub - ) - ); + .expectDiagnosticsToMatchSnapshot([unsupportedRightShiftOperator.code]); }); test.each(["1+1", "-1+1", "1*30+4", "1*(3+4)", "1*(3+4*2)", "10-(4+5)"])( diff --git a/test/unit/functions/__snapshots__/functions.spec.ts.snap b/test/unit/functions/__snapshots__/functions.spec.ts.snap new file mode 100644 index 000000000..e1e5b49d2 --- /dev/null +++ b/test/unit/functions/__snapshots__/functions.spec.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`missing declaration name: code 1`] = ` +"function ____(self) +end" +`; + +exports[`missing declaration name: diagnostics 1`] = `"main.ts(2,18): error TS1003: Identifier expected."`; diff --git a/test/unit/functions/functions.spec.ts b/test/unit/functions/functions.spec.ts index aab7b151a..d664ab061 100644 --- a/test/unit/functions/functions.spec.ts +++ b/test/unit/functions/functions.spec.ts @@ -496,3 +496,9 @@ test("named function expression reference", () => { return y(); `.expectToMatchJsResult(); }); + +test("missing declaration name", () => { + util.testModule` + function () {} + `.expectDiagnosticsToMatchSnapshot([1003]); +}); diff --git a/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap b/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap new file mode 100644 index 000000000..9f112f305 --- /dev/null +++ b/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap @@ -0,0 +1,1723 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 1`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 2`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(11,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 2`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 2`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function argument with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 2`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 2`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 3`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function argument with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 4`] = ` +"main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,23): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 1`] = `"main.ts(10,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 2`] = `"main.ts(10,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(9,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(11,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 2`] = `"main.ts(6,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 2`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 2`] = `"main.ts(7,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}): diagnostics 1`] = `"main.ts(7,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 1`] = `"main.ts(9,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 2`] = `"main.ts(9,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 1`] = `"main.ts(9,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 2`] = `"main.ts(9,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}): diagnostics 1`] = `"main.ts(6,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 2`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function assignment ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function assignment with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 2`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 2`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 3`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 4`] = ` +"main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,14): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 1`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 2`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(11,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 2`] = `"main.ts(6,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 2`] = `"main.ts(7,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}): diagnostics 1`] = `"main.ts(7,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 2`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 1`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 2`] = `"main.ts(9,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}): diagnostics 1`] = `"main.ts(6,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function generic argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function generic argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function overload assignment ("(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(7,52): error TSTL: Unsupported assignment of function with different overloaded types for 'this'. Overloads should all have the same type for 'this'."`; + +exports[`Invalid function overload assignment ("(this: void, s1: string, s2: string) => string"): diagnostics 1`] = `"main.ts(7,65): error TSTL: Unsupported assignment of function with different overloaded types for 'this'. Overloads should all have the same type for 'this'."`; + +exports[`Invalid function overload assignment ("{(this: any, s1: string, s2: string): string}"): diagnostics 1`] = `"main.ts(7,64): error TSTL: Unsupported assignment of function with different overloaded types for 'this'. Overloads should all have the same type for 'this'."`; + +exports[`Invalid function overload assignment ("{(this: void, s: string): string}"): diagnostics 1`] = `"main.ts(7,52): error TSTL: Unsupported assignment of function with different overloaded types for 'this'. Overloads should all have the same type for 'this'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 1`] = `"main.ts(10,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 2`] = `"main.ts(10,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(9,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(11,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 2`] = `"main.ts(6,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 2`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 2`] = `"main.ts(7,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}): diagnostics 1`] = `"main.ts(7,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 1`] = `"main.ts(9,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 2`] = `"main.ts(9,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 1`] = `"main.ts(9,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 2`] = `"main.ts(9,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}): diagnostics 1`] = `"main.ts(6,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 2`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function return ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function return with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function return with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 2`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function return with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'. +main.ts(4,24): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." +`; + +exports[`Invalid function return with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 2`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'. +main.ts(4,24): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." +`; + +exports[`Invalid function return with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function return with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function return with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 3`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function return with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 4`] = ` +"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid function tuple assignment: diagnostics 1`] = ` +"main.ts(5,13): error TS2322: Type '[number, Meth]' is not assignable to type '[number, Func]'. + Type 'Meth' is not assignable to type 'Func'. + The 'this' types of each signature are incompatible. + Type 'void' is not assignable to type '{}'. +main.ts(5,38): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." +`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}): diagnostics 1`] = `"main.ts(6,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(4,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(4,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(4,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(4,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 1`] = `"main.ts(6,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}): diagnostics 2`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 1`] = `"main.ts(6,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}): diagnostics 2`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(6,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 2`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 1`] = `"main.ts(9,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}): diagnostics 2`] = `"main.ts(9,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(8,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}): diagnostics 1`] = `"main.ts(10,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}): diagnostics 1`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}): diagnostics 1`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}): diagnostics 1`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}): diagnostics 1`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 1`] = `"main.ts(4,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(4,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 1`] = `"main.ts(5,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}): diagnostics 2`] = `"main.ts(5,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 1`] = `"main.ts(6,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}): diagnostics 2`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 1`] = `"main.ts(6,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}): diagnostics 2`] = `"main.ts(6,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}): diagnostics 1`] = `"main.ts(6,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 1`] = `"main.ts(8,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}): diagnostics 2`] = `"main.ts(8,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 1`] = `"main.ts(8,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}): diagnostics 2`] = `"main.ts(8,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}): diagnostics 1`] = `"main.ts(5,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 1`] = `"main.ts(4,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}): diagnostics 2`] = `"main.ts(4,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid function variable declaration ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid function variable declaration ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid interface method assignment: diagnostics 1`] = `"main.ts(5,22): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid lua lib function argument: diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'callbackfn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid method tuple assignment: diagnostics 1`] = `"main.ts(5,38): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; diff --git a/test/unit/functions/validation/functionPermutations.ts b/test/unit/functions/validation/functionPermutations.ts index 2602e2ba7..c6c51be91 100644 --- a/test/unit/functions/validation/functionPermutations.ts +++ b/test/unit/functions/validation/functionPermutations.ts @@ -349,9 +349,9 @@ export const selfTestFunctionType = "(this: any, s: string) => string"; export const noSelfTestFunctionType = "(this: void, s: string) => string"; type TestFunctionCast = [ - /*testFunction: */ TestFunction, - /*castedFunction: */ string, - /*isSelfConversion?: */ boolean? + /* testFunction: */ TestFunction, + /* castedFunction: */ string, + /* isSelfConversion?: */ boolean? ]; export const validTestFunctionCasts: TestFunctionCast[] = [ [selfTestFunctions[0], `<${anonTestFunctionType}>(${selfTestFunctions[0].value})`], @@ -377,9 +377,9 @@ export const invalidTestFunctionCasts: TestFunctionCast[] = [ ]; export type TestFunctionAssignment = [ - /*testFunction: */ TestFunction, - /*functionType: */ string, - /*isSelfConversion?: */ boolean? + /* testFunction: */ TestFunction, + /* functionType: */ string, + /* isSelfConversion?: */ boolean? ]; export const validTestFunctionAssignments: TestFunctionAssignment[] = [ ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), diff --git a/test/unit/functions/validation/invalidFunctionAssignments.spec.ts b/test/unit/functions/validation/invalidFunctionAssignments.spec.ts index 4f2e385be..7d678496b 100644 --- a/test/unit/functions/validation/invalidFunctionAssignments.spec.ts +++ b/test/unit/functions/validation/invalidFunctionAssignments.spec.ts @@ -1,191 +1,153 @@ import { - UnsupportedNoSelfFunctionConversion, - UnsupportedOverloadAssignment, - UnsupportedSelfFunctionConversion, -} from "../../../../src/transformation/utils/errors"; + unsupportedOverloadAssignment, + unsupportedNoSelfFunctionConversion, + unsupportedSelfFunctionConversion, +} from "../../../../src/transformation/utils/diagnostics"; import * as util from "../../../util"; import { invalidTestFunctionAssignments, invalidTestFunctionCasts } from "./functionPermutations"; test.each(invalidTestFunctionAssignments)( "Invalid function variable declaration (%p)", (testFunction, functionType, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} const fn: ${functionType} = ${testFunction.value}; - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub) - : UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); } ); test.each(invalidTestFunctionAssignments)( "Invalid function assignment (%p)", (testFunction, functionType, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} let fn: ${functionType}; fn = ${testFunction.value}; - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub) - : UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); } ); -test.each(invalidTestFunctionCasts)( - "Invalid function assignment with cast (%p)", - (testFunction, castedFunction, isSelfConversion) => { - const code = ` - ${testFunction.definition || ""} - let fn: typeof ${testFunction.value}; - fn = ${castedFunction}; - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub) - : UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - } -); +test.each(invalidTestFunctionCasts)("Invalid function assignment with cast (%p)", (testFunction, castedFunction) => { + util.testModule` + ${testFunction.definition || ""} + let fn: typeof ${testFunction.value}; + fn = ${castedFunction}; + `.expectDiagnosticsToMatchSnapshot( + [unsupportedNoSelfFunctionConversion.code, unsupportedSelfFunctionConversion.code], + true + ); +}); test.each(invalidTestFunctionAssignments)( "Invalid function argument (%p)", (testFunction, functionType, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} declare function takesFunction(fn: ${functionType}); takesFunction(${testFunction.value}); - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub, "fn") - : UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); } ); test("Invalid lua lib function argument", () => { - const code = ` + util.testModule` declare function foo(this: void, value: string): void; declare const a: string[]; a.forEach(foo); - `; - const err = UnsupportedSelfFunctionConversion(util.nodeStub, "callbackfn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot([unsupportedSelfFunctionConversion.code], true); }); -test.each(invalidTestFunctionCasts)( - "Invalid function argument with cast (%p)", - (testFunction, castedFunction, isSelfConversion) => { - const code = ` - ${testFunction.definition || ""} - declare function takesFunction(fn: typeof ${testFunction.value}); - takesFunction(${castedFunction}); - `; - // TODO: Changed in #705 because of order change in `transformArguments`. - // After #412 both errors should be reported. - const err = isSelfConversion - ? UnsupportedNoSelfFunctionConversion(util.nodeStub) - : UnsupportedSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - } -); +test.each(invalidTestFunctionCasts)("Invalid function argument with cast (%p)", (testFunction, castedFunction) => { + util.testModule` + ${testFunction.definition || ""} + declare function takesFunction(fn: typeof ${testFunction.value}); + takesFunction(${castedFunction}); + `.expectDiagnosticsToMatchSnapshot( + [unsupportedNoSelfFunctionConversion.code, unsupportedSelfFunctionConversion.code], + true + ); +}); test.each(invalidTestFunctionAssignments)( "Invalid function generic argument (%p)", (testFunction, functionType, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} declare function takesFunction(fn: T); takesFunction(${testFunction.value}); - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub, "fn") - : UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); } ); test.each(invalidTestFunctionAssignments)( "Invalid function return (%p)", (testFunction, functionType, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} function returnsFunction(): ${functionType} { return ${testFunction.value}; } - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub) - : UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); } ); test.each(invalidTestFunctionCasts)( "Invalid function return with cast (%p)", (testFunction, castedFunction, isSelfConversion) => { - const code = ` + util.testModule` ${testFunction.definition || ""} function returnsFunction(): typeof ${testFunction.value} { return ${castedFunction}; } - `; - const err = isSelfConversion - ? UnsupportedSelfFunctionConversion(util.nodeStub) - : UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + `.expectDiagnosticsToMatchSnapshot( + isSelfConversion + ? [unsupportedSelfFunctionConversion.code, unsupportedNoSelfFunctionConversion.code] + : [unsupportedNoSelfFunctionConversion.code, unsupportedSelfFunctionConversion.code], + true + ); } ); -test("Interface method assignment", () => { - const code = ` - class Foo { - method(s: string): string { return s + "+method"; } - lambdaProp: (s: string) => string = s => s + "+lambdaProp"; - } - interface IFoo { - method: (s: string) => string; - lambdaProp(s: string): string; - } - const foo: IFoo = new Foo(); - return foo.method("foo") + "|" + foo.lambdaProp("bar"); - `; - const result = util.transpileAndExecute(code); - expect(result).toBe("foo+method|bar+lambdaProp"); -}); - test("Invalid function tuple assignment", () => { - const code = ` + util.testModule` interface Func { (this: void, s: string): string; } interface Meth { (this: {}, s: string): string; } declare function getTuple(): [number, Meth]; let [i, f]: [number, Func] = getTuple(); - `; - expect(() => util.transpileString(code)).toThrowExactError(UnsupportedNoSelfFunctionConversion(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([2322, unsupportedNoSelfFunctionConversion.code], true); }); test("Invalid method tuple assignment", () => { - const code = ` + util.testModule` interface Func { (this: void, s: string): string; } interface Meth { (this: {}, s: string): string; } declare function getTuple(): [number, Func]; let [i, f]: [number, Meth] = getTuple(); - `; - expect(() => util.transpileString(code)).toThrowExactError(UnsupportedSelfFunctionConversion(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([unsupportedSelfFunctionConversion.code], true); }); test("Invalid interface method assignment", () => { - const code = ` + util.testModule` interface A { fn(s: string): string; } interface B { fn(this: void, s: string): string; } declare const a: A; const b: B = a; - `; - expect(() => util.transpileString(code)).toThrowExactError( - UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn") - ); + `.expectDiagnosticsToMatchSnapshot([unsupportedNoSelfFunctionConversion.code], true); }); test.each([ @@ -194,13 +156,12 @@ test.each([ "{(this: void, s: string): string}", "{(this: any, s1: string, s2: string): string}", ])("Invalid function overload assignment (%p)", assignType => { - const code = ` + util.testModule` interface O { (this: any, s1: string, s2: string): string; (this: void, s: string): string; } declare const o: O; let f: ${assignType} = o; - `; - expect(() => util.transpileString(code)).toThrowExactError(UnsupportedOverloadAssignment(util.nodeStub)); + `.expectDiagnosticsToMatchSnapshot([unsupportedOverloadAssignment.code], true); }); diff --git a/test/unit/functions/validation/validFunctionAssignments.spec.ts b/test/unit/functions/validation/validFunctionAssignments.spec.ts index be1130ba6..4b4721d63 100644 --- a/test/unit/functions/validation/validFunctionAssignments.spec.ts +++ b/test/unit/functions/validation/validFunctionAssignments.spec.ts @@ -144,16 +144,21 @@ test("Valid function tuple assignment", () => { expect(result).toBe("foo"); }); -test("Valid method tuple assignment", () => { - const code = `interface Foo { method(s: string): string; } - interface Meth { (this: Foo, s: string): string; } - let meth: Meth = s => s; - function getTuple(): [number, Meth] { return [1, meth]; } - let [i, f]: [number, Meth] = getTuple(); - let foo: Foo = {method: f}; - return foo.method("foo");`; +test("Interface method assignment", () => { + const code = ` + class Foo { + method(s: string): string { return s + "+method"; } + lambdaProp: (s: string) => string = s => s + "+lambdaProp"; + } + interface IFoo { + method: (s: string) => string; + lambdaProp(s: string): string; + } + const foo: IFoo = new Foo(); + return foo.method("foo") + "|" + foo.lambdaProp("bar"); + `; const result = util.transpileAndExecute(code); - expect(result).toBe("foo"); + expect(result).toBe("foo+method|bar+lambdaProp"); }); test("Valid interface method assignment", () => { @@ -166,6 +171,18 @@ test("Valid interface method assignment", () => { expect(result).toBe("foo"); }); +test("Valid method tuple assignment", () => { + const code = `interface Foo { method(s: string): string; } + interface Meth { (this: Foo, s: string): string; } + let meth: Meth = s => s; + function getTuple(): [number, Meth] { return [1, meth]; } + let [i, f]: [number, Meth] = getTuple(); + let foo: Foo = {method: f}; + return foo.method("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + test.each([ { assignType: "(this: any, s: string) => string", args: ["foo"], expectResult: "foobar" }, { assignType: "{(this: any, s: string): string}", args: ["foo"], expectResult: "foobar" }, diff --git a/test/unit/identifiers.spec.ts b/test/unit/identifiers.spec.ts index 875c196fc..84583ccd7 100644 --- a/test/unit/identifiers.spec.ts +++ b/test/unit/identifiers.spec.ts @@ -1,5 +1,4 @@ -import * as ts from "typescript"; -import { InvalidAmbientIdentifierName } from "../../src/transformation/utils/errors"; +import { invalidAmbientIdentifierName } from "../../src/transformation/utils/diagnostics"; import { luaKeywords } from "../../src/transformation/utils/safe-names"; import * as util from "../util"; @@ -83,7 +82,7 @@ test.each([ local; ` .disableSemanticCheck() - .expectToHaveDiagnosticOfError(InvalidAmbientIdentifierName(ts.createIdentifier("local"))); + .expectDiagnosticsToMatchSnapshot([invalidAmbientIdentifierName.code]); }); test.each([ @@ -100,7 +99,7 @@ test.each([ util.testModule` declare ${statement} $$$; - `.expectToHaveDiagnosticOfError(InvalidAmbientIdentifierName(ts.createIdentifier("$$$"))); + `.expectDiagnosticsToMatchSnapshot([invalidAmbientIdentifierName.code]); }); test.each(validTsInvalidLuaNames)( @@ -109,7 +108,7 @@ test.each(validTsInvalidLuaNames)( util.testModule` declare var ${name}: any; const foo = { ${name} }; - `.expectToHaveDiagnosticOfError(InvalidAmbientIdentifierName(ts.createIdentifier(name))); + `.expectDiagnosticsToMatchSnapshot([invalidAmbientIdentifierName.code]); } ); @@ -118,7 +117,7 @@ test.each(validTsInvalidLuaNames)("undeclared identifier must be a valid lua ide const foo = ${name}; ` .disableSemanticCheck() - .expectToHaveDiagnosticOfError(InvalidAmbientIdentifierName(ts.createIdentifier(name))); + .expectDiagnosticsToMatchSnapshot([invalidAmbientIdentifierName.code]); }); test.each(validTsInvalidLuaNames)( @@ -128,7 +127,7 @@ test.each(validTsInvalidLuaNames)( const foo = { ${name} }; ` .disableSemanticCheck() - .expectToHaveDiagnosticOfError(InvalidAmbientIdentifierName(ts.createIdentifier(name))); + .expectDiagnosticsToMatchSnapshot([invalidAmbientIdentifierName.code]); } ); diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index b7b7c27e5..b61e64fd1 100644 --- a/test/unit/json.spec.ts +++ b/test/unit/json.spec.ts @@ -1,23 +1,13 @@ -import * as ts from "typescript"; -import { InvalidJsonFileContent } from "../../src/transformation/utils/errors"; import * as util from "../util"; -const jsonOptions = { - resolveJsonModule: true, - noHeader: true, - moduleResolution: ts.ModuleResolutionKind.NodeJs, -}; - test.each([0, "", [], [1, "2", []], { a: "b" }, { a: { b: "c" } }])("JSON (%p)", json => { util.testModule(JSON.stringify(json)) - .setOptions(jsonOptions) .setMainFileName("main.json") .expectToEqual(json); }); -test("Empty JSON", () => { +test("Empty JSON file error", () => { util.testModule("") - .setOptions(jsonOptions) .setMainFileName("main.json") - .expectToHaveDiagnosticOfError(InvalidJsonFileContent(util.nodeStub)); + .expectToEqual(new util.ExecutionError("Unexpected end of JSON input")); }); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index e73f85359..a2bef4c01 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -1,6 +1,5 @@ -import * as ts from "typescript"; import * as tstl from "../../src"; -import { ForbiddenForIn, UnsupportedForTarget } from "../../src/transformation/utils/errors"; +import { forbiddenForIn, unsupportedForTarget } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test("while", () => { @@ -213,15 +212,11 @@ test.each([ expect(JSON.parse(result)).toEqual(expected); }); -test.each([{ inp: [1, 2, 3] }])("forin[Array] (%p)", ({ inp }) => { - expect(() => - util.transpileString( - `let arrTest = ${JSON.stringify(inp)}; - for (let key in arrTest) { - arrTest[key]++; - }` - ) - ).toThrowExactError(ForbiddenForIn(util.nodeStub)); +test("forin[Array]", () => { + util.testFunction` + const array = []; + for (const key in array) {} + `.expectDiagnosticsToMatchSnapshot([forbiddenForIn.code]); }); test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 }, expected: { a: 0, b: 0, c: 2, d: 0, e: 4 } }])( @@ -524,25 +519,23 @@ describe("for...of empty destructuring", () => { describe("assignment", () => declareTests("")); }); -test.each([ - "while (a < b) { i++; continue; }", - "do { i++; continue; } while (a < b)", - "for (let i = 0; i < 3; i++) { continue; }", - "for (let a in b) { continue; }", - "for (let a of b) { continue; }", -])("loop continue in different lua versions (%p)", loop => { - const lua51 = { luaTarget: tstl.LuaTarget.Lua51 }; - const lua52 = { luaTarget: tstl.LuaTarget.Lua52 }; - const lua53 = { luaTarget: tstl.LuaTarget.Lua53 }; - const luajit = { luaTarget: tstl.LuaTarget.LuaJIT }; - - expect(() => util.transpileString(loop, lua51)).toThrowExactError( - UnsupportedForTarget("Continue statement", tstl.LuaTarget.Lua51, ts.createContinue()) - ); - expect(util.transpileString(loop, lua52).indexOf("::__continue2::") !== -1).toBe(true); - expect(util.transpileString(loop, lua53).indexOf("::__continue2::") !== -1).toBe(true); - expect(util.transpileString(loop, luajit).indexOf("::__continue2::") !== -1).toBe(true); -}); +for (const testCase of [ + "while (false) { continue; }", + "do { continue; } while (false)", + "for (;;) { continue; }", + "for (const a in {}) { continue; }", + "for (const a of []) { continue; }", +]) { + const expectContinueGotoLabel: util.TapCallback = builder => + expect(builder.getMainLuaCodeChunk()).toMatch("::__continue2::"); + + util.testEachVersion(`loop continue (${testCase})`, () => util.testModule(testCase), { + [tstl.LuaTarget.Lua51]: builder => builder.expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]), + [tstl.LuaTarget.Lua52]: expectContinueGotoLabel, + [tstl.LuaTarget.Lua53]: expectContinueGotoLabel, + [tstl.LuaTarget.LuaJIT]: expectContinueGotoLabel, + }); +} test("do...while", () => { util.testFunction` diff --git a/test/unit/modules/__snapshots__/resolution.spec.ts.snap b/test/unit/modules/__snapshots__/resolution.spec.ts.snap new file mode 100644 index 000000000..d4228141d --- /dev/null +++ b/test/unit/modules/__snapshots__/resolution.spec.ts.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`doesn't resolve paths out of root dir: code 1`] = ` +"local ____exports = {} +local module = require(\\"../module\\") +local ____ = module +return ____exports" +`; + +exports[`doesn't resolve paths out of root dir: diagnostics 1`] = `"src/main.ts(2,33): error TSTL: Cannot create require path. Module '../module' does not exist within --rootDir."`; diff --git a/test/unit/modules/resolution.spec.ts b/test/unit/modules/resolution.spec.ts index 6c1dbe105..1b0a6a8f9 100644 --- a/test/unit/modules/resolution.spec.ts +++ b/test/unit/modules/resolution.spec.ts @@ -1,4 +1,5 @@ import * as ts from "typescript"; +import { unresolvableRequirePath } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; const requireRegex = /require\("(.*?)"\)/; @@ -82,7 +83,7 @@ test("doesn't resolve paths out of root dir", () => { .setMainFileName("src/main.ts") .setOptions({ rootDir: "./src" }) .disableSemanticCheck() - .expectToHaveDiagnostics(); + .expectDiagnosticsToMatchSnapshot([unresolvableRequirePath.code]); }); test.each([ diff --git a/test/util.ts b/test/util.ts index a4e84f4b1..6a8909e18 100644 --- a/test/util.ts +++ b/test/util.ts @@ -9,7 +9,7 @@ import * as tstl from "../src"; export * from "./legacy-utils"; -export const nodeStub = ts.createNode(ts.SyntaxKind.Unknown); +export const nodeStub = ts.createNode(ts.SyntaxKind.Unknown, 0, 0); export function parseTypeScript( typescript: string, @@ -50,17 +50,19 @@ export const formatCode = (...values: unknown[]) => values.map(e => stringify(e) export function testEachVersion( name: string | undefined, common: () => T, - special: Record T) | false> + special?: Record void) | boolean> ): void { for (const version of Object.values(tstl.LuaTarget) as tstl.LuaTarget[]) { - const specialBuilder = special[version]; + const specialBuilder = special?.[version]; if (specialBuilder === false) return; const testName = name === undefined ? version : `${name} [${version}]`; test(testName, () => { const builder = common(); builder.setOptions({ luaTarget: version }); - specialBuilder(builder); + if (typeof specialBuilder === "function") { + specialBuilder(builder); + } }); } } @@ -194,7 +196,6 @@ export class ExecutionError extends Error { export type ExecutableTranspiledFile = tstl.TranspiledFile & { lua: string; sourceMap: string }; export type TapCallback = (builder: TestBuilder) => void; -export type DiagnosticMatcher = (diagnostic: ts.Diagnostic) => boolean; export abstract class TestBuilder { constructor(protected _tsCode: string) {} @@ -242,6 +243,8 @@ export abstract class TestBuilder { skipLibCheck: true, target: ts.ScriptTarget.ES2017, lib: ["lib.esnext.d.ts"], + moduleResolution: ts.ModuleResolutionKind.NodeJs, + resolveJsonModule: true, experimentalDecorators: true, }; public setOptions(options: tstl.CompilerOptions = {}): this { @@ -357,30 +360,20 @@ export abstract class TestBuilder { return this; } - public expectToHaveDiagnostic(matcher: DiagnosticMatcher): this { - expect(this.getLuaDiagnostics().find(matcher)).toBeDefined(); - return this; - } + private diagnosticsChecked = false; - public expectToHaveExactDiagnostic(diagnostic: ts.Diagnostic): this { - expect(this.getLuaDiagnostics()).toContainEqual(diagnostic); - return this; - } - - public expectToHaveDiagnostics(): this { - expect(this.getLuaDiagnostics()).toHaveDiagnostics(); - return this; - } + public expectToHaveDiagnostics(expected?: number[]): this { + if (this.diagnosticsChecked) return this; + this.diagnosticsChecked = true; - public expectToHaveDiagnosticOfError(error: Error): this { - this.expectToHaveDiagnostics(); - expect(this.getLuaDiagnostics()).toHaveLength(1); - const firstDiagnostic = this.getLuaDiagnostics()[0]; - expect(firstDiagnostic).toMatchObject({ messageText: error.message }); + expect(this.getLuaDiagnostics()).toHaveDiagnostics(expected); return this; } public expectToHaveNoDiagnostics(): this { + if (this.diagnosticsChecked) return this; + this.diagnosticsChecked = true; + expect(this.getLuaDiagnostics()).not.toHaveDiagnostics(); return this; } @@ -418,9 +411,19 @@ export abstract class TestBuilder { return this; } - public expectResultToMatchSnapshot(): this { - this.expectToHaveNoDiagnostics(); - expect(this.getLuaExecutionResult()).toMatchSnapshot(); + public expectDiagnosticsToMatchSnapshot(expected?: number[], diagnosticsOnly = false): this { + this.expectToHaveDiagnostics(expected); + + const diagnosticMessages = ts.formatDiagnostics( + this.getLuaDiagnostics().map(tstl.prepareDiagnosticForFormatting), + { getCurrentDirectory: () => "", getCanonicalFileName: fileName => fileName, getNewLine: () => "\n" } + ); + + expect(diagnosticMessages.trim()).toMatchSnapshot("diagnostics"); + if (!diagnosticsOnly) { + expect(this.getMainLuaCodeChunk()).toMatchSnapshot("code"); + } + return this; }