diff --git a/package-lock.json b/package-lock.json index c81232199..e1293fd62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,13 +37,13 @@ "prettier": "^2.3.2", "ts-jest": "^28.0.8", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.3" }, "engines": { "node": ">=16.10.0" }, "peerDependencies": { - "typescript": "~4.8.2" + "typescript": "~4.9.3" } }, "node_modules/@ampproject/remapping": { @@ -7302,9 +7302,9 @@ } }, "node_modules/typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -13033,9 +13033,9 @@ "dev": true }, "typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true }, "unbox-primitive": { diff --git a/package.json b/package.json index 439686e58..fbe619c37 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "node": ">=16.10.0" }, "peerDependencies": { - "typescript": "~4.8.2" + "typescript": "~4.9.3" }, "dependencies": { "@typescript-to-lua/language-extensions": "1.0.0", @@ -70,6 +70,6 @@ "prettier": "^2.3.2", "ts-jest": "^28.0.8", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.3" } } diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 698534d9e..2bfa16c18 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -5,7 +5,7 @@ // because we don't create the AST from text import * as ts from "typescript"; -import { LuaLibFeature } from "./transformation/utils/lualib"; +import { LuaLibFeature } from "./LuaLib"; import { castArray } from "./utils"; export enum SyntaxKind { @@ -816,6 +816,7 @@ export function createTableIndexExpression( } export type AssignmentLeftHandSideExpression = Identifier | TableIndexExpression; + export function isAssignmentLeftHandSideExpression(node: Node): node is AssignmentLeftHandSideExpression { return isIdentifier(node) || isTableIndexExpression(node); } diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index ab2d373da..757cb23de 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -3,7 +3,7 @@ import { Mapping, SourceMapGenerator, SourceNode } from "source-map"; import * as ts from "typescript"; import { CompilerOptions, isBundleEnabled, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; import * as lua from "./LuaAST"; -import { loadInlineLualibFeatures, LuaLibFeature, loadImportedLualibFeatures } from "./LuaLib"; +import { loadImportedLualibFeatures, loadInlineLualibFeatures, LuaLibFeature } from "./LuaLib"; import { isValidLuaIdentifier, shouldAllowUnicode } from "./transformation/utils/safe-names"; import { EmitHost, getEmitPath } from "./transpilation"; import { intersperse, normalizeSlashes } from "./utils"; @@ -899,9 +899,9 @@ export class LuaPrinter { map.addMapping(currentMapping); } - for (const chunk of sourceNode.children) { + for (const chunk of sourceNode.children as SourceChunk[]) { if (typeof chunk === "string") { - const lines = (chunk as string).split("\n"); + const lines = chunk.split("\n"); if (lines.length > 1) { generatedLine += lines.length - 1; generatedColumn = 0; diff --git a/src/cli/parse.ts b/src/cli/parse.ts index a49510780..ca4f039ad 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -147,7 +147,7 @@ function updateParsedCommandLine(parsedCommandLine: ts.ParsedCommandLine, args: if (!args[i].startsWith("-")) continue; const isShorthand = !args[i].startsWith("--"); - const argumentName = args[i].substr(isShorthand ? 1 : 2); + const argumentName = args[i].substring(isShorthand ? 1 : 2); const option = optionDeclarations.find(option => { if (option.name.toLowerCase() === argumentName.toLowerCase()) return true; if (isShorthand && option.aliases) { diff --git a/src/lualib/ParseInt.ts b/src/lualib/ParseInt.ts index 2e1081a86..f6129f1df 100644 --- a/src/lualib/ParseInt.ts +++ b/src/lualib/ParseInt.ts @@ -10,8 +10,8 @@ export function __TS__ParseInt(this: void, numberString: string, base?: number): if (hexMatch) { base = 16; numberString = __TS__Match(hexMatch, "-")[0] - ? "-" + numberString.substr(hexMatch.length) - : numberString.substr(hexMatch.length); + ? "-" + numberString.substring(hexMatch.length) + : numberString.substring(hexMatch.length); } } @@ -22,7 +22,7 @@ export function __TS__ParseInt(this: void, numberString: string, base?: number): // Calculate string match pattern to use const allowedDigits = - base <= 10 ? parseIntBasePattern.substring(0, base) : parseIntBasePattern.substr(0, 10 + 2 * (base - 10)); + base <= 10 ? parseIntBasePattern.substring(0, base) : parseIntBasePattern.substring(0, 10 + 2 * (base - 10)); const pattern = `^%s*(-?[${allowedDigits}]*)`; // Try to parse with Lua tonumber diff --git a/src/lualib/SetDescriptor.ts b/src/lualib/SetDescriptor.ts index 11c435162..1646ca7bd 100644 --- a/src/lualib/SetDescriptor.ts +++ b/src/lualib/SetDescriptor.ts @@ -73,8 +73,7 @@ export function __TS__SetDescriptor( if (value !== undefined) rawset(target, key, undefined); if (!rawget(metatable, "_descriptors")) metatable._descriptors = {}; - const descriptor = __TS__CloneDescriptor(desc); - metatable._descriptors[key] = descriptor; + metatable._descriptors[key] = __TS__CloneDescriptor(desc); metatable.__index = descriptorIndex; metatable.__newindex = descriptorNewIndex; } diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 8fda0bc23..4ee8c04a5 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -65,7 +65,10 @@ export class TransformationContext { /** @internal */ public transformNodeRaw(node: ts.Node, isExpression?: boolean) { // TODO: Move to visitors? - if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword)) { + if ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword) + ) { return []; } diff --git a/src/transformation/context/visitors.ts b/src/transformation/context/visitors.ts index fff7441e5..429cce1b4 100644 --- a/src/transformation/context/visitors.ts +++ b/src/transformation/context/visitors.ts @@ -61,6 +61,7 @@ interface NodesBySyntaxKind { [ts.SyntaxKind.AsExpression]: ts.AsExpression; [ts.SyntaxKind.NonNullExpression]: ts.NonNullExpression; [ts.SyntaxKind.MetaProperty]: ts.MetaProperty; + [ts.SyntaxKind.SatisfiesExpression]: ts.SatisfiesExpression; [ts.SyntaxKind.TemplateSpan]: ts.TemplateSpan; [ts.SyntaxKind.SemicolonClassElement]: ts.SemicolonClassElement; [ts.SyntaxKind.Block]: ts.Block; @@ -148,6 +149,7 @@ export type VisitorResult = T extends ExpressionLikeNode export type Visitor = FunctionVisitor | ObjectVisitor; export type FunctionVisitor = (node: T, context: TransformationContext) => VisitorResult; + export interface ObjectVisitor { transform: FunctionVisitor; diff --git a/src/transformation/utils/diagnostics.ts b/src/transformation/utils/diagnostics.ts index 8216ab186..94f7781de 100644 --- a/src/transformation/utils/diagnostics.ts +++ b/src/transformation/utils/diagnostics.ts @@ -119,12 +119,6 @@ export const invalidMultiFunctionReturnType = createErrorDiagnosticFactory( "The $multi function cannot be cast to a non-LuaMultiReturn type." ); -export const invalidMultiTypeToNonArrayLiteral = createErrorDiagnosticFactory("Expected an array literal."); - -export const invalidMultiTypeToEmptyPatternOrArrayLiteral = createErrorDiagnosticFactory( - "There must be one or more elements specified here." -); - export const invalidMultiReturnAccess = createErrorDiagnosticFactory( "The LuaMultiReturn type can only be accessed via an element access expression of a numeric type." ); @@ -132,13 +126,6 @@ export const invalidMultiReturnAccess = createErrorDiagnosticFactory( export const invalidCallExtensionUse = createErrorDiagnosticFactory( "This function must be called directly and cannot be referred to." ); - -export const annotationRemoved = createErrorDiagnosticFactory( - (kind: AnnotationKind) => - `'@${kind}' has been removed and will no longer have any effect.` + - `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.` -); - export const annotationDeprecated = createWarningDiagnosticFactory( (kind: AnnotationKind) => `'@${kind}' is deprecated and will be removed in a future update. Please update your code before upgrading to the next release, otherwise your project will no longer compile. ` + diff --git a/src/transformation/utils/export.ts b/src/transformation/utils/export.ts index fafc26d86..a7e9db909 100644 --- a/src/transformation/utils/export.ts +++ b/src/transformation/utils/export.ts @@ -7,11 +7,17 @@ import { getSymbolInfo } from "./symbols"; import { findFirstNodeAbove } from "./typescript"; export function hasDefaultExportModifier(node: ts.Node): boolean { - return (node.modifiers ?? []).some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword); + return ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword) === true + ); } export function hasExportModifier(node: ts.Node): boolean { - return (node.modifiers ?? []).some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword); + return ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword) === true + ); } export const createDefaultExportStringLiteral = (original?: ts.Node): lua.StringLiteral => diff --git a/src/transformation/visitors/binary-expression/bit.ts b/src/transformation/visitors/binary-expression/bit.ts index 14ce4bdef..79e9c1f3c 100644 --- a/src/transformation/visitors/binary-expression/bit.ts +++ b/src/transformation/visitors/binary-expression/bit.ts @@ -49,6 +49,7 @@ function transformBitOperatorToLuaOperator( return lua.SyntaxKind.BitwiseLeftShiftOperator; case ts.SyntaxKind.GreaterThanGreaterThanToken: context.diagnostics.push(unsupportedRightShiftOperator(node)); + return lua.SyntaxKind.BitwiseRightShiftOperator; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return lua.SyntaxKind.BitwiseRightShiftOperator; } @@ -66,6 +67,7 @@ export function transformBinaryBitOperation( case LuaTarget.Lua50: case LuaTarget.Lua51: context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", context.luaTarget)); + return transformBinaryBitLibOperation(node, left, right, operator, "bit"); case LuaTarget.LuaJIT: return transformBinaryBitLibOperation(node, left, right, operator, "bit"); @@ -111,6 +113,7 @@ export function transformUnaryBitOperation( case LuaTarget.Lua50: case LuaTarget.Lua51: context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", context.luaTarget)); + return transformUnaryBitLibOperation(node, expression, operator, "bit"); case LuaTarget.LuaJIT: return transformUnaryBitLibOperation(node, expression, operator, "bit"); diff --git a/src/transformation/visitors/binary-expression/compound.ts b/src/transformation/visitors/binary-expression/compound.ts index 44c492505..a8180e78b 100644 --- a/src/transformation/visitors/binary-expression/compound.ts +++ b/src/transformation/visitors/binary-expression/compound.ts @@ -3,7 +3,7 @@ import * as lua from "../../../LuaAST"; import { cast, assertNever } from "../../../utils"; import { TransformationContext } from "../../context"; import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; -import { transformBinaryOperation } from "../binary-expression"; +import { transformBinaryOperation } from "./index"; import { transformAssignmentWithRightPrecedingStatements } from "./assignments"; function isLuaExpressionWithSideEffect(expression: lua.Expression) { diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index 68adcab39..5955d6e1f 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -116,7 +116,7 @@ function transformClassLikeDeclaration( // Generate a constructor if none was defined in a base class const constructorResult = transformConstructorDeclaration( context, - ts.factory.createConstructorDeclaration([], [], [], ts.factory.createBlock([], true)), + ts.factory.createConstructorDeclaration([], [], ts.factory.createBlock([], true)), localClassName, instanceFields, classDeclaration diff --git a/src/transformation/visitors/class/utils.ts b/src/transformation/visitors/class/utils.ts index 8708a54fb..d5b960662 100644 --- a/src/transformation/visitors/class/utils.ts +++ b/src/transformation/visitors/class/utils.ts @@ -1,12 +1,12 @@ import * as ts from "typescript"; import { TransformationContext } from "../../context"; -export function isStaticNode(node: ts.Node): boolean { - return (node.modifiers ?? []).some(m => m.kind === ts.SyntaxKind.StaticKeyword); +export function isStaticNode(node: ts.HasModifiers): boolean { + return node.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) === true; } export function getExtendsClause(node: ts.ClassLikeDeclarationBase): ts.HeritageClause | undefined { - return (node.heritageClauses ?? []).find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword); + return node.heritageClauses?.find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword); } export function getExtendedNode(node: ts.ClassLikeDeclarationBase): ts.ExpressionWithTypeArguments | undefined { diff --git a/src/transformation/visitors/template.ts b/src/transformation/visitors/template.ts index 5f949adb1..bfad88057 100644 --- a/src/transformation/visitors/template.ts +++ b/src/transformation/visitors/template.ts @@ -3,7 +3,7 @@ import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; import { ContextType, getDeclarationContextType } from "../utils/function-context"; import { wrapInToStringForConcat } from "../utils/lua-ast"; -import { isStringType } from "../utils/typescript/types"; +import { isStringType } from "../utils/typescript"; import { transformArguments, transformContextualCallExpression } from "./call"; import { transformOrderedExpressions } from "./expression-list"; diff --git a/src/transformation/visitors/typescript.ts b/src/transformation/visitors/typescript.ts index ddd319381..0d9f8a8c1 100644 --- a/src/transformation/visitors/typescript.ts +++ b/src/transformation/visitors/typescript.ts @@ -21,6 +21,7 @@ export const typescriptVisitors: Visitors = { [ts.SyntaxKind.NonNullExpression]: (node, context) => context.transformExpression(node.expression), [ts.SyntaxKind.ExpressionWithTypeArguments]: (node, context) => context.transformExpression(node.expression), + [ts.SyntaxKind.SatisfiesExpression]: (node, context) => context.transformExpression(node.expression), [ts.SyntaxKind.AsExpression]: transformAssertionExpression, [ts.SyntaxKind.TypeAssertionExpression]: transformAssertionExpression, [ts.SyntaxKind.NotEmittedStatement]: () => undefined, diff --git a/src/transpilation/utils.ts b/src/transpilation/utils.ts index cef3af310..ce03fd854 100644 --- a/src/transpilation/utils.ts +++ b/src/transpilation/utils.ts @@ -40,7 +40,7 @@ export function resolvePlugin( kind: string, optionName: string, basedir: string, - query: string, + query: unknown, importName = "default" ): { error?: ts.Diagnostic; result?: unknown } { if (typeof query !== "string") { diff --git a/src/typescript-internal.d.ts b/src/typescript-internal.d.ts index 8d85b9374..afcf45685 100644 --- a/src/typescript-internal.d.ts +++ b/src/typescript-internal.d.ts @@ -35,8 +35,6 @@ declare module "typescript" { parent?: Symbol; } - function getObjectFlags(type: Type): ObjectFlags; - function transformJsx(context: TransformationContext): (x: SourceFile) => SourceFile; export type OuterExpression = diff --git a/test/unit/builtins/numbers.spec.ts b/test/unit/builtins/numbers.spec.ts index ab7e332a9..f3f0bb9b9 100644 --- a/test/unit/builtins/numbers.spec.ts +++ b/test/unit/builtins/numbers.spec.ts @@ -1,8 +1,6 @@ import * as util from "../../util"; test.each([ - "NaN === NaN", - "NaN !== NaN", "NaN + NaN", "NaN - NaN", "NaN * NaN", diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 2aec6a6f2..46ca2f7bd 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -173,6 +173,13 @@ test("Typescript 4.7 instantiation expression", () => { `.expectToMatchJsResult(); }); +test("Typescript 4.9 satisfies expression", () => { + util.testFunction` + const foo = { a: 1 } satisfies { a: number }; + return foo.a; + `.expectToMatchJsResult(); +}); + test.each([ '"foobar"', "17",