From e7dbbb4685758b51b57f60b10af08e5ad9864694 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 19 Sep 2025 12:08:49 +0200 Subject: [PATCH 1/5] Integrate JS syntax checks with parser and remove separate pass --- internal/parser/parser.go | 275 ++++++++++++++++++++++---------------- 1 file changed, 158 insertions(+), 117 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 2a4328863f..b8cba8e287 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -358,7 +358,7 @@ func (p *Parser) parseSourceFileWorker() *ast.SourceFile { } collectExternalModuleReferences(result) if ast.IsInJSFile(node) { - result.SetJSDiagnostics(getJSSyntacticDiagnosticsForFile(result)) + result.SetJSDiagnostics(attachFileToDiagnostics(p.jsDiagnostics, result)) } return result } @@ -1407,6 +1407,7 @@ func (p *Parser) parseVariableStatement(pos int, hasJSDoc bool, modifiers *ast.M p.parseSemicolon() result := p.finishNode(p.factory.NewVariableStatement(modifiers, declarationList), pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) return result } @@ -1477,7 +1478,7 @@ func (p *Parser) parseVariableDeclarationWorker(allowExclamation bool) *ast.Node if allowExclamation && name.Kind == ast.KindIdentifier && p.token == ast.KindExclamationToken && !p.hasPrecedingLineBreak() { exclamationToken = p.parseTokenNode() } - typeNode := p.parseTypeAnnotation() + typeNode := p.checkNoJSTypeAnnotation(p.parseTypeAnnotation()) var initializer *ast.Expression if p.token != ast.KindInKeyword && p.token != ast.KindOfKeyword { initializer = p.parseInitializer() @@ -1583,11 +1584,14 @@ func (p *Parser) parseFunctionDeclaration(pos int, hasJSDoc bool, modifiers *ast p.setContextFlags(ast.NodeFlagsAwaitContext, true) } parameters := p.parseParameters(signatureFlags) - returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) + returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnostics.X_or_expected) p.contextFlags = saveContextFlags result := p.finishNode(p.factory.NewFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + p.checkNoJSSignature(result) return result } @@ -1631,6 +1635,19 @@ func (p *Parser) parseClassDeclarationOrExpression(pos int, hasJSDoc bool, modif } p.finishNode(result, pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + if heritageClauses != nil { + for _, clause := range heritageClauses.Nodes { + if clause.AsHeritageClause().Token == ast.KindExtendsKeyword { + for _, expr := range clause.AsHeritageClause().Types.Nodes { + p.checkNoJSTypeArguments(expr) + } + } + } + } + } return result } @@ -1675,7 +1692,11 @@ func (p *Parser) parseHeritageClause() *ast.Node { kind := p.token p.nextToken() types := p.parseDelimitedList(PCHeritageClauseElement, (*Parser).parseExpressionWithTypeArguments) - return p.finishNode(p.factory.NewHeritageClause(kind, types), pos) + result := p.finishNode(p.factory.NewHeritageClause(kind, types), pos) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && kind == ast.KindImplementsKeyword { + p.jsErrorAtRange(result.Loc, diagnostics.X_implements_clauses_can_only_be_used_in_TypeScript_files) + } + return result } func (p *Parser) parseExpressionWithTypeArguments() *ast.Node { @@ -1714,7 +1735,7 @@ func (p *Parser) parseClassElement() *ast.Node { } } if p.isIndexSignature() { - return p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers) + return p.checkNoJSSignature(p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers)) } // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name @@ -1763,13 +1784,21 @@ func (p *Parser) parseClassStaticBlockBody() *ast.Node { func (p *Parser) tryParseConstructorDeclaration(pos int, hasJSDoc bool, modifiers *ast.ModifierList) *ast.Node { state := p.mark() if p.token == ast.KindConstructorKeyword || p.token == ast.KindStringLiteral && p.scanner.TokenValue() == "constructor" && p.lookAhead((*Parser).nextTokenIsOpenParen) { + errorRange := core.NewTextRange(p.scanner.TokenStart(), p.scanner.TokenEnd()) p.nextToken() typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsNone) - returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) + returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) body := p.parseFunctionBlockOrSemicolon(ParseFlagsNone, diagnostics.X_or_expected) result := p.finishNode(p.factory.NewConstructorDeclaration(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + if result.Body() == nil { + p.jsErrorAtRange(errorRange, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) + } + } return result } p.rewind(state) @@ -1785,7 +1814,7 @@ func (p *Parser) parsePropertyOrMethodDeclaration(pos int, hasJSDoc bool, modifi name := p.parsePropertyName() // Note: this is not legal as per the grammar. But we allow it in the parser and // report an error in the grammar checker. - questionToken := p.parseOptionalToken(ast.KindQuestionToken) + questionToken := p.checkNoJSQuestionToken(p.parseOptionalToken(ast.KindQuestionToken)) if asteriskToken != nil || p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken { return p.parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, diagnostics.X_or_expected) } @@ -1796,10 +1825,13 @@ func (p *Parser) parseMethodDeclaration(pos int, hasJSDoc bool, modifiers *ast.M signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifierListHasAsync(modifiers), ParseFlagsAwait, ParseFlagsNone) typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) - typeNode := p.parseReturnType(ast.KindColonToken, false /*isType*/) + typeNode := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnosticMessage) result := p.finishNode(p.factory.NewMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, typeNode, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + p.checkNoJSSignature(result) return result } @@ -1812,11 +1844,12 @@ func (p *Parser) parsePropertyDeclaration(pos int, hasJSDoc bool, modifiers *ast if postfixToken == nil && !p.hasPrecedingLineBreak() { postfixToken = p.parseOptionalToken(ast.KindExclamationToken) } - typeNode := p.parseTypeAnnotation() + typeNode := p.checkNoJSTypeAnnotation(p.parseTypeAnnotation()) initializer := doInContext(p, ast.NodeFlagsYieldContext|ast.NodeFlagsAwaitContext|ast.NodeFlagsDisallowInContext, false, (*Parser).parseInitializer) p.parseSemicolonAfterPropertyName(name, typeNode, initializer) result := p.finishNode(p.factory.NewPropertyDeclaration(modifiers, name, postfixToken, typeNode, initializer), pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) return result } @@ -1929,6 +1962,9 @@ func (p *Parser) parseInterfaceDeclaration(pos int, hasJSDoc bool, modifiers *as members := p.parseObjectTypeMembers() result := p.finishNode(p.factory.NewInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") + } return result } @@ -1949,6 +1985,9 @@ func (p *Parser) parseTypeAliasDeclaration(pos int, hasJSDoc bool, modifiers *as p.parseSemicolon() result := p.finishNode(p.factory.NewTypeAliasDeclaration(modifiers, name, typeParameters, typeNode), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(name.Loc, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) + } return result } @@ -1986,6 +2025,9 @@ func (p *Parser) parseEnumDeclaration(pos int, hasJSDoc bool, modifiers *ast.Mod } result := p.finishNode(p.factory.NewEnumDeclaration(modifiers, name, members), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") + } p.statementHasAwaitIdentifier = saveHasAwaitIdentifier return result } @@ -2062,6 +2104,9 @@ func (p *Parser) parseModuleOrNamespaceDeclaration(pos int, hasJSDoc bool, modif } result := p.finishNode(p.factory.NewModuleDeclaration(modifiers, keyword, name, body), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(keyword)) + } p.statementHasAwaitIdentifier = saveHasAwaitIdentifier return result } @@ -2088,6 +2133,9 @@ func (p *Parser) parseImportDeclarationOrImportEqualsDeclaration(pos int, hasJSD if identifier != nil && !p.tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() { importEquals := p.parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly) p.statementHasAwaitIdentifier = saveHasAwaitIdentifier // Import= declaration is always parsed in an Await context, no need to reparse + if importEquals.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(importEquals.Loc, diagnostics.X_import_can_only_be_used_in_TypeScript_files) + } return importEquals } importClause := p.tryParseImportClause(identifier, afterImportPos, isTypeOnly, false /*skipJSDocLeadingAsterisks*/) @@ -2097,6 +2145,9 @@ func (p *Parser) parseImportDeclarationOrImportEqualsDeclaration(pos int, hasJSD p.parseSemicolon() result := p.finishNode(p.factory.NewImportDeclaration(modifiers, importClause, moduleSpecifier, attributes), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { + p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import type") + } return result } @@ -2226,7 +2277,11 @@ func (p *Parser) parseImportSpecifier() *ast.Node { identifierName = p.newIdentifier("") p.finishNode(identifierName, name.Pos()) } - return p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos) + result := p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { + p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import...type") + } + return result } func (p *Parser) parseImportOrExportSpecifier(kind ast.Kind) (isTypeOnly bool, propertyName *ast.Node, name *ast.Node) { @@ -2340,6 +2395,9 @@ func (p *Parser) parseExportAssignment(pos int, hasJSDoc bool, modifiers *ast.Mo p.statementHasAwaitIdentifier = saveHasAwaitIdentifier result := p.finishNode(p.factory.NewExportAssignment(modifiers, isExportEquals, nil /*typeNode*/, expression), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isExportEquals { + p.jsErrorAtRange(result.Loc, diagnostics.X_export_can_only_be_used_in_TypeScript_files) + } return result } @@ -2389,6 +2447,9 @@ func (p *Parser) parseExportDeclaration(pos int, hasJSDoc bool, modifiers *ast.M p.statementHasAwaitIdentifier = saveHasAwaitIdentifier result := p.finishNode(p.factory.NewExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { + p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export type") + } return result } @@ -2413,6 +2474,9 @@ func (p *Parser) parseExportSpecifier() *ast.Node { isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(ast.KindExportSpecifier) result := p.finishNode(p.factory.NewExportSpecifier(isTypeOnly, propertyName, name), pos) p.withJSDoc(result, hasJSDoc) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { + p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export...type") + } return result } @@ -3110,7 +3174,15 @@ func (p *Parser) parseParametersWorker(flags ParseFlags, allowAmbiguity bool) *a p.setContextFlags(ast.NodeFlagsYieldContext, flags&ParseFlagsYield != 0) p.setContextFlags(ast.NodeFlagsAwaitContext, flags&ParseFlagsAwait != 0) parameters := p.parseDelimitedList(PCParameters, func(p *Parser) *ast.Node { - return p.parseParameterEx(inAwaitContext, allowAmbiguity) + parameter := p.parseParameterEx(inAwaitContext, allowAmbiguity) + if parameter != nil && parameter.Flags&ast.NodeFlagsJavaScriptFile != 0 && parameter.Flags&ast.NodeFlagsJSDoc == 0 && flags&ParseFlagsType == 0 { + if core.Some(parameter.ModifierNodes(), ast.IsModifier) { + p.jsErrorAtRange(parameter.Modifiers().Loc, diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files) + } + p.checkNoJSQuestionToken(parameter.PostfixToken()) + p.checkNoJSTypeAnnotation(parameter.Type()) + } + return parameter }) p.contextFlags = saveContextFlags return parameters @@ -3244,6 +3316,12 @@ func (p *Parser) parseAccessorDeclaration(pos int, hasJSDoc bool, modifiers *ast result = p.factory.NewSetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body) } p.withJSDoc(p.finishNode(result, pos), hasJSDoc) + if flags&ParseFlagsType == 0 { + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + p.checkNoJSTypeAnnotation(returnType) + p.checkNoJSSignature(result) + } return result } @@ -4235,6 +4313,9 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, } result := p.finishNode(p.factory.NewArrowFunction(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, equalsGreaterThanToken, body), pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) + p.checkNoJSTypeAnnotation(returnType) return result } @@ -4442,11 +4523,19 @@ func (p *Parser) parseBinaryExpressionRest(precedence ast.OperatorPrecedence, le } func (p *Parser) makeSatisfiesExpression(expression *ast.Expression, typeNode *ast.TypeNode) *ast.Node { - return p.finishNode(p.factory.NewSatisfiesExpression(expression, typeNode), expression.Pos()) + result := p.finishNode(p.factory.NewSatisfiesExpression(expression, typeNode), expression.Pos()) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(typeNode.Loc, diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files) + } + return result } func (p *Parser) makeAsExpression(left *ast.Expression, right *ast.TypeNode) *ast.Node { - return p.finishNode(p.factory.NewAsExpression(left, right), left.Pos()) + result := p.finishNode(p.factory.NewAsExpression(left, right), left.Pos()) + if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(right.Loc, diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files) + } + return result } func (p *Parser) makeBinaryExpression(left *ast.Expression, operatorToken *ast.Node, right *ast.Expression, pos int) *ast.Node { @@ -5149,6 +5238,9 @@ func (p *Parser) parseMemberExpressionRest(pos int, expression *ast.Expression, if p.token == ast.KindExclamationToken && !p.hasPrecedingLineBreak() { p.nextToken() expression = p.finishNode(p.factory.NewNonNullExpression(expression, ast.NodeFlagsNone), pos) + if expression.Flags&ast.NodeFlagsJavaScriptFile != 0 { + p.jsErrorAtRange(expression.Loc, diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files) + } continue } typeArguments := p.tryParseTypeArgumentsInExpression() @@ -5252,7 +5344,7 @@ func (p *Parser) parseCallExpressionRest(pos int, expression *ast.Expression) *a inner := expression argumentList := p.parseArgumentList() isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression) - expression = p.finishNode(p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos) + expression = p.checkNoJSTypeArguments(p.finishNode(p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) p.unparseExpressionWithTypeArguments(inner, typeArguments, expression) continue } @@ -5304,7 +5396,7 @@ func (p *Parser) parseTaggedTemplateRest(pos int, tag *ast.Expression, questionD template = p.parseTemplateExpression(true /*isTaggedTemplate*/) } isOptionalChain := questionDotToken != nil || tag.Flags&ast.NodeFlagsOptionalChain != 0 - return p.finishNode(p.factory.NewTaggedTemplateExpression(tag, questionDotToken, typeArguments, template, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos) + return p.checkNoJSTypeArguments(p.finishNode(p.factory.NewTaggedTemplateExpression(tag, questionDotToken, typeArguments, template, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) } func (p *Parser) parseTemplateExpression(isTaggedTemplate bool) *ast.Expression { @@ -5489,12 +5581,14 @@ func (p *Parser) parseFunctionExpression() *ast.Expression { } typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) - returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) + returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) body := p.parseFunctionBlock(signatureFlags, nil /*diagnosticMessage*/) p.contextFlags = saveContexFlags result := p.factory.NewFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body) p.finishNode(result, pos) p.withJSDoc(result, hasJSDoc) + p.checkNoJSExtraModifiers(result) + p.checkNoJSTypeParameters(result) return result } @@ -5550,7 +5644,7 @@ func (p *Parser) parseNewExpressionOrNewDotTarget() *ast.Node { if p.token == ast.KindOpenParenToken { argumentList = p.parseArgumentList() } - result := p.finishNode(p.factory.NewNewExpression(expression, typeArguments, argumentList), pos) + result := p.checkNoJSTypeArguments(p.finishNode(p.factory.NewNewExpression(expression, typeArguments, argumentList), pos)) p.unparseExpressionWithTypeArguments(expression, typeArguments, result) return result } @@ -6437,111 +6531,58 @@ func parseResolutionMode(mode string, pos int, end int /*reportDiagnostic: Pragm // return undefined; } -func getJSSyntacticDiagnosticsForFile(sourceFile *ast.SourceFile) []*ast.Diagnostic { - var diags []*ast.Diagnostic - - errorAtRange := func(loc core.TextRange, message *diagnostics.Message, args ...any) { - diags = append(diags, ast.NewDiagnostic(sourceFile, core.NewTextRange(scanner.SkipTrivia(sourceFile.Text(), loc.Pos()), loc.End()), message, args...)) +func (p *Parser) checkNoJSExtraModifiers(node *ast.Node) *ast.Node { + if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { + if modifiers := node.Modifiers(); modifiers != nil { + for _, modifier := range modifiers.Nodes { + if modifier.Flags&ast.NodeFlagsReparsed == 0 && modifier.Kind != ast.KindDecorator && ast.ModifierToFlag(modifier.Kind)&ast.ModifierFlagsJavaScript == 0 { + p.jsErrorAtRange(modifier.Loc, diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, scanner.TokenToString(modifier.Kind)) + } + } + } } + return node +} - errorAtNode := func(node *ast.Node, message *diagnostics.Message, args ...any) { - diags = append(diags, ast.NewDiagnostic(sourceFile, scanner.GetErrorRangeForNode(sourceFile, node), message, args...)) +func (p *Parser) checkNoJSQuestionToken(node *ast.Node) *ast.Node { + if node != nil && node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { + p.jsErrorAtRange(node.Loc, diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?") } + return node +} - var visit func(*ast.Node) bool - visit = func(node *ast.Node) bool { - if node.Flags&ast.NodeFlagsReparsed != 0 || ast.IsTypeNode(node) && !ast.IsExpressionWithTypeArguments(node) { - return false - } - switch node.Kind { - case ast.KindParameter, ast.KindPropertyDeclaration, ast.KindMethodDeclaration: - if token := node.PostfixToken(); token != nil && token.Flags&ast.NodeFlagsReparsed == 0 && ast.IsQuestionToken(token) { - errorAtNode(node.PostfixToken(), diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?") - } - fallthrough - case ast.KindMethodSignature, ast.KindConstructor, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindFunctionExpression, - ast.KindFunctionDeclaration, ast.KindArrowFunction, ast.KindVariableDeclaration: - if t := node.Type(); t != nil && t.Flags&ast.NodeFlagsReparsed == 0 { - errorAtNode(node.Type(), diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files) - } else if ast.IsFunctionLike(node) && node.Body() == nil { - errorAtNode(node, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) - } - case ast.KindImportClause: - if node.IsTypeOnly() { - errorAtNode(node.Parent, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import type") - } - case ast.KindExportDeclaration: - if node.IsTypeOnly() { - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export type") - } - case ast.KindImportSpecifier: - if node.IsTypeOnly() { - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import...type") - } - case ast.KindExportSpecifier: - if node.IsTypeOnly() { - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export...type") - } - case ast.KindImportEqualsDeclaration: - errorAtNode(node, diagnostics.X_import_can_only_be_used_in_TypeScript_files) - case ast.KindExportAssignment: - if node.AsExportAssignment().IsExportEquals { - errorAtNode(node, diagnostics.X_export_can_only_be_used_in_TypeScript_files) - } - case ast.KindHeritageClause: - if node.AsHeritageClause().Token == ast.KindImplementsKeyword { - errorAtNode(node, diagnostics.X_implements_clauses_can_only_be_used_in_TypeScript_files) - } - case ast.KindInterfaceDeclaration: - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") - return false - case ast.KindModuleDeclaration: - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(node.AsModuleDeclaration().Keyword)) - return false - case ast.KindTypeAliasDeclaration: - errorAtNode(node, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) - return false - case ast.KindEnumDeclaration: - errorAtNode(node, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") - return false - case ast.KindNonNullExpression: - errorAtNode(node, diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files) - return false - case ast.KindAsExpression: - errorAtNode(node.Type(), diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files) - return false - case ast.KindSatisfiesExpression: - errorAtNode(node.Type(), diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files) - return false +func (p *Parser) checkNoJSTypeParameters(node *ast.Node) *ast.Node { + if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.TypeParameterList() != nil { + if list := node.TypeParameterList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { + p.jsErrorAtRange(list.Loc, diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files) } - // Check absence of type parameters, type arguments and non-JavaScript modifiers - switch node.Kind { - case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindMethodDeclaration, ast.KindConstructor, ast.KindGetAccessor, - ast.KindSetAccessor, ast.KindFunctionExpression, ast.KindFunctionDeclaration, ast.KindArrowFunction: - if list := node.TypeParameterList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { - errorAtRange(list.Loc, diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files) - } - fallthrough - case ast.KindVariableStatement, ast.KindPropertyDeclaration: - if modifiers := node.Modifiers(); modifiers != nil { - for _, modifier := range modifiers.Nodes { - if modifier.Flags&ast.NodeFlagsReparsed == 0 && modifier.Kind != ast.KindDecorator && ast.ModifierToFlag(modifier.Kind)&ast.ModifierFlagsJavaScript == 0 { - errorAtNode(modifier, diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, scanner.TokenToString(modifier.Kind)) - } - } - } - case ast.KindParameter: - if core.Some(node.ModifierNodes(), ast.IsModifier) { - errorAtRange(node.Modifiers().Loc, diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files) - } - case ast.KindCallExpression, ast.KindNewExpression, ast.KindExpressionWithTypeArguments, ast.KindJsxSelfClosingElement, - ast.KindJsxOpeningElement, ast.KindTaggedTemplateExpression: - if list := node.TypeArgumentList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { - errorAtRange(list.Loc, diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files) - } + } + return node +} + +func (p *Parser) checkNoJSTypeAnnotation(node *ast.Node) *ast.Node { + if node != nil && node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { + p.jsErrorAtRange(node.Loc, diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files) + } + return node +} + +func (p *Parser) checkNoJSTypeArguments(node *ast.Node) *ast.Node { + if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.TypeArgumentList() != nil { + if list := node.TypeArgumentList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { + p.jsErrorAtRange(list.Loc, diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files) } - return node.ForEachChild(visit) } - sourceFile.ForEachChild(visit) - return diags + return node +} + +func (p *Parser) checkNoJSSignature(node *ast.Node) *ast.Node { + if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.Body() == nil { + p.jsErrorAtRange(core.OrElse(node.Name(), node).Loc, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) + } + return node +} + +func (p *Parser) jsErrorAtRange(loc core.TextRange, message *diagnostics.Message, args ...any) { + p.jsDiagnostics = append(p.jsDiagnostics, ast.NewDiagnostic(nil, core.NewTextRange(scanner.SkipTrivia(p.sourceText, loc.Pos()), loc.End()), message, args...)) } From 2cb176560245fe7fb31842d46a183a42e73fbe41 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 19 Sep 2025 12:14:35 +0200 Subject: [PATCH 2/5] Accept new baselines --- .../jsDeclarationsClassesErr.errors.txt | 96 +++++----- .../jsDeclarationsTypeReferences4.errors.txt | 5 +- .../plainJSGrammarErrors.errors.txt | 5 +- .../jsDeclarationsClassesErr.errors.txt.diff | 166 ++++++++++++++++++ ...eclarationsTypeReferences4.errors.txt.diff | 23 +++ .../plainJSGrammarErrors.errors.txt.diff | 23 ++- 6 files changed, 262 insertions(+), 56 deletions(-) create mode 100644 testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsClassesErr.errors.txt.diff create mode 100644 testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsTypeReferences4.errors.txt.diff diff --git a/testdata/baselines/reference/submodule/conformance/jsDeclarationsClassesErr.errors.txt b/testdata/baselines/reference/submodule/conformance/jsDeclarationsClassesErr.errors.txt index 548135e903..835d95bb5e 100644 --- a/testdata/baselines/reference/submodule/conformance/jsDeclarationsClassesErr.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/jsDeclarationsClassesErr.errors.txt @@ -3,22 +3,22 @@ index.js(5,12): error TS8010: Type annotations can only be used in TypeScript fi index.js(8,16): error TS8004: Type parameter declarations can only be used in TypeScript files. index.js(8,29): error TS8011: Type arguments can only be used in TypeScript files. index.js(9,12): error TS8010: Type annotations can only be used in TypeScript files. -index.js(13,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(19,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(23,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(27,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(28,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(32,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(39,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(43,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(47,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(48,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(52,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(53,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(59,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(63,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(67,11): error TS8010: Type annotations can only be used in TypeScript files. -index.js(68,11): error TS8010: Type annotations can only be used in TypeScript files. +index.js(13,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(19,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(23,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(27,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(28,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(32,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(39,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(43,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(47,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(48,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(52,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(53,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(59,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(63,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(67,5): error TS8017: Signature declarations can only be used in TypeScript files. +index.js(68,5): error TS8017: Signature declarations can only be used in TypeScript files. ==== index.js (21 errors) ==== @@ -45,37 +45,37 @@ index.js(68,11): error TS8010: Type annotations can only be used in TypeScript f export class O { [idx: string]: string; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class P extends O {} export class Q extends O { [idx: string]: "ok"; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class R extends O { [idx: number]: "ok"; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class S extends O { [idx: string]: "ok"; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. [idx: number]: never; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class T { [idx: number]: string; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class U extends T {} @@ -83,54 +83,54 @@ index.js(68,11): error TS8010: Type annotations can only be used in TypeScript f export class V extends T { [idx: string]: string; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class W extends T { [idx: number]: "ok"; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class X extends T { [idx: string]: string; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. [idx: number]: "ok"; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class Y { [idx: string]: {x: number}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. [idx: number]: {x: number, y: number}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class Z extends Y {} export class AA extends Y { [idx: string]: {x: number, y: number}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class BB extends Y { [idx: number]: {x: 0, y: 0}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } export class CC extends Y { [idx: string]: {x: number, y: number}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. [idx: number]: {x: 0, y: 0}; - ~~~~~~ -!!! error TS8010: Type annotations can only be used in TypeScript files. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/jsDeclarationsTypeReferences4.errors.txt b/testdata/baselines/reference/submodule/conformance/jsDeclarationsTypeReferences4.errors.txt index 146844daa3..e04e27110e 100644 --- a/testdata/baselines/reference/submodule/conformance/jsDeclarationsTypeReferences4.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/jsDeclarationsTypeReferences4.errors.txt @@ -1,7 +1,8 @@ index.js(4,18): error TS8006: 'namespace' declarations can only be used in TypeScript files. +index.js(6,22): error TS8006: 'namespace' declarations can only be used in TypeScript files. -==== index.js (1 errors) ==== +==== index.js (2 errors) ==== /// export const Something = 2; // to show conflict that can occur // @ts-ignore @@ -10,6 +11,8 @@ index.js(4,18): error TS8006: 'namespace' declarations can only be used in TypeS !!! error TS8006: 'namespace' declarations can only be used in TypeScript files. // @ts-ignore export namespace B { + ~ +!!! error TS8006: 'namespace' declarations can only be used in TypeScript files. const Something = require("fs").Something; const thing = new Something(); // @ts-ignore diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt index b59b8e7543..aefa0c4e01 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt @@ -66,7 +66,6 @@ plainJSGrammarErrors.js(105,5): error TS18016: Private identifiers are not allow plainJSGrammarErrors.js(106,5): error TS1042: 'export' modifier cannot be used here. plainJSGrammarErrors.js(108,25): error TS1162: An object member cannot be declared optional. plainJSGrammarErrors.js(109,6): error TS1162: An object member cannot be declared optional. -plainJSGrammarErrors.js(109,6): error TS8009: The '?' modifier can only be used in TypeScript files. plainJSGrammarErrors.js(110,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. plainJSGrammarErrors.js(111,19): error TS1255: A definite assignment assertion '!' is not permitted in this context. plainJSGrammarErrors.js(114,16): error TS1312: Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern. @@ -101,7 +100,7 @@ plainJSGrammarErrors.js(204,30): message TS1450: Dynamic imports can only accept plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot be spread element. -==== plainJSGrammarErrors.js (101 errors) ==== +==== plainJSGrammarErrors.js (100 errors) ==== class C { // #private mistakes q = #unbound @@ -347,8 +346,6 @@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot m?() { return 12 }, ~ !!! error TS1162: An object member cannot be declared optional. - ~ -!!! error TS8009: The '?' modifier can only be used in TypeScript files. definitely!, ~ !!! error TS1255: A definite assignment assertion '!' is not permitted in this context. diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsClassesErr.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsClassesErr.errors.txt.diff new file mode 100644 index 0000000000..eade1a0230 --- /dev/null +++ b/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsClassesErr.errors.txt.diff @@ -0,0 +1,166 @@ +--- old.jsDeclarationsClassesErr.errors.txt ++++ new.jsDeclarationsClassesErr.errors.txt +@@= skipped -2, +2 lines =@@ + index.js(8,16): error TS8004: Type parameter declarations can only be used in TypeScript files. + index.js(8,29): error TS8011: Type arguments can only be used in TypeScript files. + index.js(9,12): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(13,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(19,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(23,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(27,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(28,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(32,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(39,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(43,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(47,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(48,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(52,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(53,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(59,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(63,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(67,11): error TS8010: Type annotations can only be used in TypeScript files. +-index.js(68,11): error TS8010: Type annotations can only be used in TypeScript files. ++index.js(13,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(19,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(23,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(27,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(28,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(32,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(39,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(43,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(47,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(48,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(52,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(53,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(59,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(63,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(67,5): error TS8017: Signature declarations can only be used in TypeScript files. ++index.js(68,5): error TS8017: Signature declarations can only be used in TypeScript files. + + + ==== index.js (21 errors) ==== +@@= skipped -42, +42 lines =@@ + + export class O { + [idx: string]: string; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class P extends O {} + + export class Q extends O { + [idx: string]: "ok"; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class R extends O { + [idx: number]: "ok"; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class S extends O { + [idx: string]: "ok"; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + [idx: number]: never; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class T { + [idx: number]: string; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class U extends T {} +@@= skipped -38, +38 lines =@@ + + export class V extends T { + [idx: string]: string; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class W extends T { + [idx: number]: "ok"; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class X extends T { + [idx: string]: string; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + [idx: number]: "ok"; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class Y { + [idx: string]: {x: number}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + [idx: number]: {x: number, y: number}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class Z extends Y {} + + export class AA extends Y { + [idx: string]: {x: number, y: number}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class BB extends Y { + [idx: number]: {x: 0, y: 0}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + + export class CC extends Y { + [idx: string]: {x: number, y: number}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + [idx: number]: {x: 0, y: 0}; +- ~~~~~~ +-!!! error TS8010: Type annotations can only be used in TypeScript files. ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS8017: Signature declarations can only be used in TypeScript files. + } + \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsTypeReferences4.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsTypeReferences4.errors.txt.diff new file mode 100644 index 0000000000..90a2e6f285 --- /dev/null +++ b/testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsTypeReferences4.errors.txt.diff @@ -0,0 +1,23 @@ +--- old.jsDeclarationsTypeReferences4.errors.txt ++++ new.jsDeclarationsTypeReferences4.errors.txt +@@= skipped -0, +0 lines =@@ + index.js(4,18): error TS8006: 'namespace' declarations can only be used in TypeScript files. +- +- +-==== index.js (1 errors) ==== ++index.js(6,22): error TS8006: 'namespace' declarations can only be used in TypeScript files. ++ ++ ++==== index.js (2 errors) ==== + /// + export const Something = 2; // to show conflict that can occur + // @ts-ignore +@@= skipped -9, +10 lines =@@ + !!! error TS8006: 'namespace' declarations can only be used in TypeScript files. + // @ts-ignore + export namespace B { ++ ~ ++!!! error TS8006: 'namespace' declarations can only be used in TypeScript files. + const Something = require("fs").Something; + const thing = new Something(); + // @ts-ignore \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff index 1274e947de..5e55cf776b 100644 --- a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff +++ b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff @@ -18,12 +18,20 @@ plainJSGrammarErrors.js(64,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(65,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(66,1): error TS1042: 'async' modifier cannot be used here. -@@= skipped -64, +63 lines =@@ +@@= skipped -29, +28 lines =@@ + plainJSGrammarErrors.js(106,5): error TS1042: 'export' modifier cannot be used here. + plainJSGrammarErrors.js(108,25): error TS1162: An object member cannot be declared optional. + plainJSGrammarErrors.js(109,6): error TS1162: An object member cannot be declared optional. +-plainJSGrammarErrors.js(109,6): error TS8009: The '?' modifier can only be used in TypeScript files. + plainJSGrammarErrors.js(110,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. + plainJSGrammarErrors.js(111,19): error TS1255: A definite assignment assertion '!' is not permitted in this context. + plainJSGrammarErrors.js(114,16): error TS1312: Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern. +@@= skipped -35, +34 lines =@@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot be spread element. -==== plainJSGrammarErrors.js (102 errors) ==== -+==== plainJSGrammarErrors.js (101 errors) ==== ++==== plainJSGrammarErrors.js (100 errors) ==== class C { // #private mistakes q = #unbound @@ -53,4 +61,13 @@ -!!! error TS8009: The 'async' modifier can only be used in TypeScript files. } async const cantAsyncConst = 2 - ~~~~~ \ No newline at end of file + ~~~~~ +@@= skipped -105, +103 lines =@@ + m?() { return 12 }, + ~ + !!! error TS1162: An object member cannot be declared optional. +- ~ +-!!! error TS8009: The '?' modifier can only be used in TypeScript files. + definitely!, + ~ + !!! error TS1255: A definite assignment assertion '!' is not permitted in this context. \ No newline at end of file From f5c22971b913d7c4db09baee037f89dcf79a5d68 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Sep 2025 10:10:33 +0200 Subject: [PATCH 3/5] Keep all JS syntax checking in a single checkJSSyntax function --- internal/parser/parser.go | 186 ++++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index b8cba8e287..00c07cfea2 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -1407,7 +1407,7 @@ func (p *Parser) parseVariableStatement(pos int, hasJSDoc bool, modifiers *ast.M p.parseSemicolon() result := p.finishNode(p.factory.NewVariableStatement(modifiers, declarationList), pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) + p.checkJSSyntax(result) return result } @@ -1478,13 +1478,14 @@ func (p *Parser) parseVariableDeclarationWorker(allowExclamation bool) *ast.Node if allowExclamation && name.Kind == ast.KindIdentifier && p.token == ast.KindExclamationToken && !p.hasPrecedingLineBreak() { exclamationToken = p.parseTokenNode() } - typeNode := p.checkNoJSTypeAnnotation(p.parseTypeAnnotation()) + typeNode := p.parseTypeAnnotation() var initializer *ast.Expression if p.token != ast.KindInKeyword && p.token != ast.KindOfKeyword { initializer = p.parseInitializer() } result := p.finishNode(p.factory.NewVariableDeclaration(name, exclamationToken, typeNode, initializer), pos) p.withJSDoc(result, hasJSDoc) + p.checkJSSyntax(result) return result } @@ -1584,14 +1585,12 @@ func (p *Parser) parseFunctionDeclaration(pos int, hasJSDoc bool, modifiers *ast p.setContextFlags(ast.NodeFlagsAwaitContext, true) } parameters := p.parseParameters(signatureFlags) - returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) + returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnostics.X_or_expected) p.contextFlags = saveContextFlags result := p.finishNode(p.factory.NewFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) - p.checkNoJSSignature(result) + p.checkJSSyntax(result) return result } @@ -1636,13 +1635,12 @@ func (p *Parser) parseClassDeclarationOrExpression(pos int, hasJSDoc bool, modif p.finishNode(result, pos) p.withJSDoc(result, hasJSDoc) if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) + p.checkJSSyntax(result) if heritageClauses != nil { for _, clause := range heritageClauses.Nodes { if clause.AsHeritageClause().Token == ast.KindExtendsKeyword { for _, expr := range clause.AsHeritageClause().Types.Nodes { - p.checkNoJSTypeArguments(expr) + p.checkJSSyntax(expr) } } } @@ -1735,7 +1733,7 @@ func (p *Parser) parseClassElement() *ast.Node { } } if p.isIndexSignature() { - return p.checkNoJSSignature(p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers)) + return p.checkJSSyntax(p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers)) } // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name @@ -1784,21 +1782,14 @@ func (p *Parser) parseClassStaticBlockBody() *ast.Node { func (p *Parser) tryParseConstructorDeclaration(pos int, hasJSDoc bool, modifiers *ast.ModifierList) *ast.Node { state := p.mark() if p.token == ast.KindConstructorKeyword || p.token == ast.KindStringLiteral && p.scanner.TokenValue() == "constructor" && p.lookAhead((*Parser).nextTokenIsOpenParen) { - errorRange := core.NewTextRange(p.scanner.TokenStart(), p.scanner.TokenEnd()) p.nextToken() typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsNone) - returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) + returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(ParseFlagsNone, diagnostics.X_or_expected) result := p.finishNode(p.factory.NewConstructorDeclaration(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) - if result.Body() == nil { - p.jsErrorAtRange(errorRange, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) - } - } + p.checkJSSyntax(result) return result } p.rewind(state) @@ -1814,7 +1805,7 @@ func (p *Parser) parsePropertyOrMethodDeclaration(pos int, hasJSDoc bool, modifi name := p.parsePropertyName() // Note: this is not legal as per the grammar. But we allow it in the parser and // report an error in the grammar checker. - questionToken := p.checkNoJSQuestionToken(p.parseOptionalToken(ast.KindQuestionToken)) + questionToken := p.parseOptionalToken(ast.KindQuestionToken) if asteriskToken != nil || p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken { return p.parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, diagnostics.X_or_expected) } @@ -1825,13 +1816,11 @@ func (p *Parser) parseMethodDeclaration(pos int, hasJSDoc bool, modifiers *ast.M signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifierListHasAsync(modifiers), ParseFlagsAwait, ParseFlagsNone) typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) - typeNode := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) + typeNode := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnosticMessage) result := p.finishNode(p.factory.NewMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, typeNode, nil /*fullSignature*/, body), pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) - p.checkNoJSSignature(result) + p.checkJSSyntax(result) return result } @@ -1844,12 +1833,12 @@ func (p *Parser) parsePropertyDeclaration(pos int, hasJSDoc bool, modifiers *ast if postfixToken == nil && !p.hasPrecedingLineBreak() { postfixToken = p.parseOptionalToken(ast.KindExclamationToken) } - typeNode := p.checkNoJSTypeAnnotation(p.parseTypeAnnotation()) + typeNode := p.parseTypeAnnotation() initializer := doInContext(p, ast.NodeFlagsYieldContext|ast.NodeFlagsAwaitContext|ast.NodeFlagsDisallowInContext, false, (*Parser).parseInitializer) p.parseSemicolonAfterPropertyName(name, typeNode, initializer) result := p.finishNode(p.factory.NewPropertyDeclaration(modifiers, name, postfixToken, typeNode, initializer), pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) + p.checkJSSyntax(result) return result } @@ -3175,12 +3164,8 @@ func (p *Parser) parseParametersWorker(flags ParseFlags, allowAmbiguity bool) *a p.setContextFlags(ast.NodeFlagsAwaitContext, flags&ParseFlagsAwait != 0) parameters := p.parseDelimitedList(PCParameters, func(p *Parser) *ast.Node { parameter := p.parseParameterEx(inAwaitContext, allowAmbiguity) - if parameter != nil && parameter.Flags&ast.NodeFlagsJavaScriptFile != 0 && parameter.Flags&ast.NodeFlagsJSDoc == 0 && flags&ParseFlagsType == 0 { - if core.Some(parameter.ModifierNodes(), ast.IsModifier) { - p.jsErrorAtRange(parameter.Modifiers().Loc, diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files) - } - p.checkNoJSQuestionToken(parameter.PostfixToken()) - p.checkNoJSTypeAnnotation(parameter.Type()) + if parameter != nil && flags&ParseFlagsType == 0 { + p.checkJSSyntax(parameter) } return parameter }) @@ -3317,10 +3302,7 @@ func (p *Parser) parseAccessorDeclaration(pos int, hasJSDoc bool, modifiers *ast } p.withJSDoc(p.finishNode(result, pos), hasJSDoc) if flags&ParseFlagsType == 0 { - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) - p.checkNoJSTypeAnnotation(returnType) - p.checkNoJSSignature(result) + p.checkJSSyntax(result) } return result } @@ -4313,9 +4295,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, } result := p.finishNode(p.factory.NewArrowFunction(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, equalsGreaterThanToken, body), pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) - p.checkNoJSTypeAnnotation(returnType) + p.checkJSSyntax(result) return result } @@ -5344,7 +5324,7 @@ func (p *Parser) parseCallExpressionRest(pos int, expression *ast.Expression) *a inner := expression argumentList := p.parseArgumentList() isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression) - expression = p.checkNoJSTypeArguments(p.finishNode(p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) + expression = p.checkJSSyntax(p.finishNode(p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) p.unparseExpressionWithTypeArguments(inner, typeArguments, expression) continue } @@ -5396,7 +5376,7 @@ func (p *Parser) parseTaggedTemplateRest(pos int, tag *ast.Expression, questionD template = p.parseTemplateExpression(true /*isTaggedTemplate*/) } isOptionalChain := questionDotToken != nil || tag.Flags&ast.NodeFlagsOptionalChain != 0 - return p.checkNoJSTypeArguments(p.finishNode(p.factory.NewTaggedTemplateExpression(tag, questionDotToken, typeArguments, template, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) + return p.checkJSSyntax(p.finishNode(p.factory.NewTaggedTemplateExpression(tag, questionDotToken, typeArguments, template, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone)), pos)) } func (p *Parser) parseTemplateExpression(isTaggedTemplate bool) *ast.Expression { @@ -5581,14 +5561,13 @@ func (p *Parser) parseFunctionExpression() *ast.Expression { } typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) - returnType := p.checkNoJSTypeAnnotation(p.parseReturnType(ast.KindColonToken, false /*isType*/)) + returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlock(signatureFlags, nil /*diagnosticMessage*/) p.contextFlags = saveContexFlags result := p.factory.NewFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body) p.finishNode(result, pos) p.withJSDoc(result, hasJSDoc) - p.checkNoJSExtraModifiers(result) - p.checkNoJSTypeParameters(result) + p.checkJSSyntax(result) return result } @@ -5644,7 +5623,7 @@ func (p *Parser) parseNewExpressionOrNewDotTarget() *ast.Node { if p.token == ast.KindOpenParenToken { argumentList = p.parseArgumentList() } - result := p.checkNoJSTypeArguments(p.finishNode(p.factory.NewNewExpression(expression, typeArguments, argumentList), pos)) + result := p.checkJSSyntax(p.finishNode(p.factory.NewNewExpression(expression, typeArguments, argumentList), pos)) p.unparseExpressionWithTypeArguments(expression, typeArguments, result) return result } @@ -6531,8 +6510,77 @@ func parseResolutionMode(mode string, pos int, end int /*reportDiagnostic: Pragm // return undefined; } -func (p *Parser) checkNoJSExtraModifiers(node *ast.Node) *ast.Node { - if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { +func (p *Parser) jsErrorAtRange(loc core.TextRange, message *diagnostics.Message, args ...any) { + p.jsDiagnostics = append(p.jsDiagnostics, ast.NewDiagnostic(nil, core.NewTextRange(scanner.SkipTrivia(p.sourceText, loc.Pos()), loc.End()), message, args...)) +} + +func (p *Parser) checkJSSyntax(node *ast.Node) *ast.Node { + if node.Flags&ast.NodeFlagsJavaScriptFile == 0 || node.Flags&(ast.NodeFlagsJSDoc|ast.NodeFlagsReparsed) != 0 { + return node + } + switch node.Kind { + case ast.KindParameter, ast.KindPropertyDeclaration, ast.KindMethodDeclaration: + if token := node.PostfixToken(); token != nil && token.Flags&ast.NodeFlagsReparsed == 0 && ast.IsQuestionToken(token) { + p.jsErrorAtRange(token.Loc, diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?") + } + fallthrough + case ast.KindMethodSignature, ast.KindConstructor, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindFunctionExpression, + ast.KindFunctionDeclaration, ast.KindArrowFunction, ast.KindVariableDeclaration, ast.KindIndexSignature: + if ast.IsFunctionLike(node) && node.Body() == nil { + p.jsErrorAtRange(node.Loc, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) + } else if t := node.Type(); t != nil && t.Flags&ast.NodeFlagsReparsed == 0 { + p.jsErrorAtRange(t.Loc, diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files) + } + case ast.KindImportDeclaration: + if clause := node.AsImportDeclaration().ImportClause; clause != nil && clause.IsTypeOnly() { + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import type") + } + case ast.KindExportDeclaration: + if node.IsTypeOnly() { + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export type") + } + case ast.KindImportSpecifier: + if node.IsTypeOnly() { + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import...type") + } + case ast.KindExportSpecifier: + if node.IsTypeOnly() { + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export...type") + } + case ast.KindImportEqualsDeclaration: + p.jsErrorAtRange(node.Loc, diagnostics.X_import_can_only_be_used_in_TypeScript_files) + case ast.KindExportAssignment: + if node.AsExportAssignment().IsExportEquals { + p.jsErrorAtRange(node.Loc, diagnostics.X_export_can_only_be_used_in_TypeScript_files) + } + case ast.KindHeritageClause: + if node.AsHeritageClause().Token == ast.KindImplementsKeyword { + p.jsErrorAtRange(node.Loc, diagnostics.X_implements_clauses_can_only_be_used_in_TypeScript_files) + } + case ast.KindInterfaceDeclaration: + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") + case ast.KindModuleDeclaration: + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(node.AsModuleDeclaration().Keyword)) + case ast.KindTypeAliasDeclaration: + p.jsErrorAtRange(node.Loc, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) + case ast.KindEnumDeclaration: + p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") + case ast.KindNonNullExpression: + p.jsErrorAtRange(node.Loc, diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files) + case ast.KindAsExpression: + p.jsErrorAtRange(node.Type().Loc, diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files) + case ast.KindSatisfiesExpression: + p.jsErrorAtRange(node.Type().Loc, diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files) + } + // Check absence of type parameters, type arguments and non-JavaScript modifiers + switch node.Kind { + case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindMethodDeclaration, ast.KindConstructor, ast.KindGetAccessor, + ast.KindSetAccessor, ast.KindFunctionExpression, ast.KindFunctionDeclaration, ast.KindArrowFunction: + if list := node.TypeParameterList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { + p.jsErrorAtRange(list.Loc, diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files) + } + fallthrough + case ast.KindVariableStatement, ast.KindPropertyDeclaration: if modifiers := node.Modifiers(); modifiers != nil { for _, modifier := range modifiers.Nodes { if modifier.Flags&ast.NodeFlagsReparsed == 0 && modifier.Kind != ast.KindDecorator && ast.ModifierToFlag(modifier.Kind)&ast.ModifierFlagsJavaScript == 0 { @@ -6540,49 +6588,15 @@ func (p *Parser) checkNoJSExtraModifiers(node *ast.Node) *ast.Node { } } } - } - return node -} - -func (p *Parser) checkNoJSQuestionToken(node *ast.Node) *ast.Node { - if node != nil && node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { - p.jsErrorAtRange(node.Loc, diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?") - } - return node -} - -func (p *Parser) checkNoJSTypeParameters(node *ast.Node) *ast.Node { - if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.TypeParameterList() != nil { - if list := node.TypeParameterList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { - p.jsErrorAtRange(list.Loc, diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files) + case ast.KindParameter: + if core.Some(node.ModifierNodes(), ast.IsModifier) { + p.jsErrorAtRange(node.Modifiers().Loc, diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files) } - } - return node -} - -func (p *Parser) checkNoJSTypeAnnotation(node *ast.Node) *ast.Node { - if node != nil && node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 { - p.jsErrorAtRange(node.Loc, diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files) - } - return node -} - -func (p *Parser) checkNoJSTypeArguments(node *ast.Node) *ast.Node { - if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.TypeArgumentList() != nil { + case ast.KindCallExpression, ast.KindNewExpression, ast.KindExpressionWithTypeArguments, ast.KindJsxSelfClosingElement, + ast.KindJsxOpeningElement, ast.KindTaggedTemplateExpression: if list := node.TypeArgumentList(); list != nil && core.Some(list.Nodes, func(n *ast.Node) bool { return n.Flags&ast.NodeFlagsReparsed == 0 }) { p.jsErrorAtRange(list.Loc, diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files) } } return node } - -func (p *Parser) checkNoJSSignature(node *ast.Node) *ast.Node { - if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && node.Flags&ast.NodeFlagsJSDoc == 0 && node.Body() == nil { - p.jsErrorAtRange(core.OrElse(node.Name(), node).Loc, diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files) - } - return node -} - -func (p *Parser) jsErrorAtRange(loc core.TextRange, message *diagnostics.Message, args ...any) { - p.jsDiagnostics = append(p.jsDiagnostics, ast.NewDiagnostic(nil, core.NewTextRange(scanner.SkipTrivia(p.sourceText, loc.Pos()), loc.End()), message, args...)) -} From a5d60c75387d0e5d08e25ed17208cc4e52c7475b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Sep 2025 10:11:21 +0200 Subject: [PATCH 4/5] Accept new baselines --- ...lationConstructorOverloadSyntax.errors.txt | 2 +- ...mpilationFunctionOverloadSyntax.errors.txt | 4 +-- ...CompilationMethodOverloadSyntax.errors.txt | 2 +- .../plainJSGrammarErrors.errors.txt | 9 ++++--- ...nConstructorOverloadSyntax.errors.txt.diff | 11 ++++++++ ...tionFunctionOverloadSyntax.errors.txt.diff | 13 +++++++++ ...lationMethodOverloadSyntax.errors.txt.diff | 11 ++++++++ .../plainJSGrammarErrors.errors.txt.diff | 27 ++++--------------- 8 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt.diff create mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt.diff create mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt.diff diff --git a/testdata/baselines/reference/submodule/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt b/testdata/baselines/reference/submodule/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt index c2eefe3d28..0ff11a2b87 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt @@ -4,7 +4,7 @@ a.js(2,3): error TS8017: Signature declarations can only be used in TypeScript f ==== a.js (1 errors) ==== class A { constructor(); - ~~~~~~~~~~~ + ~~~~~~~~~~~~~~ !!! error TS8017: Signature declarations can only be used in TypeScript files. } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt b/testdata/baselines/reference/submodule/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt index 1c10528f03..5af6399a20 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt @@ -1,8 +1,8 @@ -a.js(1,10): error TS8017: Signature declarations can only be used in TypeScript files. +a.js(1,1): error TS8017: Signature declarations can only be used in TypeScript files. ==== a.js (1 errors) ==== function foo(); - ~~~ + ~~~~~~~~~~~~~~~ !!! error TS8017: Signature declarations can only be used in TypeScript files. \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt b/testdata/baselines/reference/submodule/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt index 470da0781c..1d54c0e41e 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt @@ -4,7 +4,7 @@ a.js(2,3): error TS8017: Signature declarations can only be used in TypeScript f ==== a.js (1 errors) ==== class A { foo(); - ~~~ + ~~~~~~ !!! error TS8017: Signature declarations can only be used in TypeScript files. } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt index aefa0c4e01..40731faa29 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt @@ -13,7 +13,7 @@ plainJSGrammarErrors.js(26,11): error TS1030: 'async' modifier already seen. plainJSGrammarErrors.js(28,11): error TS1029: 'static' modifier must precede 'async' modifier. plainJSGrammarErrors.js(29,5): error TS1031: 'export' modifier cannot appear on class elements of this kind. plainJSGrammarErrors.js(30,5): error TS1031: 'export' modifier cannot appear on class elements of this kind. -plainJSGrammarErrors.js(34,9): error TS8017: Signature declarations can only be used in TypeScript files. +plainJSGrammarErrors.js(34,5): error TS8017: Signature declarations can only be used in TypeScript files. plainJSGrammarErrors.js(34,22): error TS1005: '{' expected. plainJSGrammarErrors.js(35,9): error TS1054: A 'get' accessor cannot have parameters. plainJSGrammarErrors.js(36,9): error TS1049: A 'set' accessor must have exactly one parameter. @@ -66,6 +66,7 @@ plainJSGrammarErrors.js(105,5): error TS18016: Private identifiers are not allow plainJSGrammarErrors.js(106,5): error TS1042: 'export' modifier cannot be used here. plainJSGrammarErrors.js(108,25): error TS1162: An object member cannot be declared optional. plainJSGrammarErrors.js(109,6): error TS1162: An object member cannot be declared optional. +plainJSGrammarErrors.js(109,6): error TS8009: The '?' modifier can only be used in TypeScript files. plainJSGrammarErrors.js(110,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. plainJSGrammarErrors.js(111,19): error TS1255: A definite assignment assertion '!' is not permitted in this context. plainJSGrammarErrors.js(114,16): error TS1312: Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern. @@ -100,7 +101,7 @@ plainJSGrammarErrors.js(204,30): message TS1450: Dynamic imports can only accept plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot be spread element. -==== plainJSGrammarErrors.js (100 errors) ==== +==== plainJSGrammarErrors.js (101 errors) ==== class C { // #private mistakes q = #unbound @@ -165,7 +166,7 @@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot // accessor mistakes get incorporeal(); - ~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~ !!! error TS8017: Signature declarations can only be used in TypeScript files. ~ !!! error TS1005: '{' expected. @@ -346,6 +347,8 @@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot m?() { return 12 }, ~ !!! error TS1162: An object member cannot be declared optional. + ~ +!!! error TS8009: The '?' modifier can only be used in TypeScript files. definitely!, ~ !!! error TS1255: A definite assignment assertion '!' is not permitted in this context. diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt.diff new file mode 100644 index 0000000000..794ce9898b --- /dev/null +++ b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationConstructorOverloadSyntax.errors.txt.diff @@ -0,0 +1,11 @@ +--- old.jsFileCompilationConstructorOverloadSyntax.errors.txt ++++ new.jsFileCompilationConstructorOverloadSyntax.errors.txt +@@= skipped -3, +3 lines =@@ + ==== a.js (1 errors) ==== + class A { + constructor(); +- ~~~~~~~~~~~ ++ ~~~~~~~~~~~~~~ + !!! error TS8017: Signature declarations can only be used in TypeScript files. + } + \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt.diff new file mode 100644 index 0000000000..cdef364579 --- /dev/null +++ b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationFunctionOverloadSyntax.errors.txt.diff @@ -0,0 +1,13 @@ +--- old.jsFileCompilationFunctionOverloadSyntax.errors.txt ++++ new.jsFileCompilationFunctionOverloadSyntax.errors.txt +@@= skipped -0, +0 lines =@@ +-a.js(1,10): error TS8017: Signature declarations can only be used in TypeScript files. ++a.js(1,1): error TS8017: Signature declarations can only be used in TypeScript files. + + + ==== a.js (1 errors) ==== + function foo(); +- ~~~ ++ ~~~~~~~~~~~~~~~ + !!! error TS8017: Signature declarations can only be used in TypeScript files. + \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt.diff new file mode 100644 index 0000000000..e8fe861040 --- /dev/null +++ b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileCompilationMethodOverloadSyntax.errors.txt.diff @@ -0,0 +1,11 @@ +--- old.jsFileCompilationMethodOverloadSyntax.errors.txt ++++ new.jsFileCompilationMethodOverloadSyntax.errors.txt +@@= skipped -3, +3 lines =@@ + ==== a.js (1 errors) ==== + class A { + foo(); +- ~~~ ++ ~~~~~~ + !!! error TS8017: Signature declarations can only be used in TypeScript files. + } + \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff index 5e55cf776b..249a843d77 100644 --- a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff +++ b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff @@ -6,7 +6,7 @@ plainJSGrammarErrors.js(29,5): error TS1031: 'export' modifier cannot appear on class elements of this kind. -plainJSGrammarErrors.js(29,5): error TS8009: The 'export' modifier can only be used in TypeScript files. plainJSGrammarErrors.js(30,5): error TS1031: 'export' modifier cannot appear on class elements of this kind. -+plainJSGrammarErrors.js(34,9): error TS8017: Signature declarations can only be used in TypeScript files. ++plainJSGrammarErrors.js(34,5): error TS8017: Signature declarations can only be used in TypeScript files. plainJSGrammarErrors.js(34,22): error TS1005: '{' expected. plainJSGrammarErrors.js(35,9): error TS1054: A 'get' accessor cannot have parameters. plainJSGrammarErrors.js(36,9): error TS1049: A 'set' accessor must have exactly one parameter. @@ -18,20 +18,12 @@ plainJSGrammarErrors.js(64,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(65,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(66,1): error TS1042: 'async' modifier cannot be used here. -@@= skipped -29, +28 lines =@@ - plainJSGrammarErrors.js(106,5): error TS1042: 'export' modifier cannot be used here. - plainJSGrammarErrors.js(108,25): error TS1162: An object member cannot be declared optional. - plainJSGrammarErrors.js(109,6): error TS1162: An object member cannot be declared optional. --plainJSGrammarErrors.js(109,6): error TS8009: The '?' modifier can only be used in TypeScript files. - plainJSGrammarErrors.js(110,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. - plainJSGrammarErrors.js(111,19): error TS1255: A definite assignment assertion '!' is not permitted in this context. - plainJSGrammarErrors.js(114,16): error TS1312: Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern. -@@= skipped -35, +34 lines =@@ +@@= skipped -64, +63 lines =@@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot be spread element. -==== plainJSGrammarErrors.js (102 errors) ==== -+==== plainJSGrammarErrors.js (100 errors) ==== ++==== plainJSGrammarErrors.js (101 errors) ==== class C { // #private mistakes q = #unbound @@ -48,7 +40,7 @@ // accessor mistakes get incorporeal(); -+ ~~~~~~~~~~~ ++ ~~~~~~~~~~~~~~~~~~ +!!! error TS8017: Signature declarations can only be used in TypeScript files. ~ !!! error TS1005: '{' expected. @@ -61,13 +53,4 @@ -!!! error TS8009: The 'async' modifier can only be used in TypeScript files. } async const cantAsyncConst = 2 - ~~~~~ -@@= skipped -105, +103 lines =@@ - m?() { return 12 }, - ~ - !!! error TS1162: An object member cannot be declared optional. -- ~ --!!! error TS8009: The '?' modifier can only be used in TypeScript files. - definitely!, - ~ - !!! error TS1255: A definite assignment assertion '!' is not permitted in this context. \ No newline at end of file + ~~~~~ \ No newline at end of file From 2936d5c64270958de5ae2ecf79cd7b298c35cf44 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Sep 2025 10:30:01 +0200 Subject: [PATCH 5/5] Keep all JS syntax checking in a single checkJSSyntax function --- internal/parser/parser.go | 73 ++++++++++----------------------------- 1 file changed, 18 insertions(+), 55 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 00c07cfea2..4f2ea48ffb 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -1690,11 +1690,7 @@ func (p *Parser) parseHeritageClause() *ast.Node { kind := p.token p.nextToken() types := p.parseDelimitedList(PCHeritageClauseElement, (*Parser).parseExpressionWithTypeArguments) - result := p.finishNode(p.factory.NewHeritageClause(kind, types), pos) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && kind == ast.KindImplementsKeyword { - p.jsErrorAtRange(result.Loc, diagnostics.X_implements_clauses_can_only_be_used_in_TypeScript_files) - } - return result + return p.checkJSSyntax(p.finishNode(p.factory.NewHeritageClause(kind, types), pos)) } func (p *Parser) parseExpressionWithTypeArguments() *ast.Node { @@ -1951,9 +1947,7 @@ func (p *Parser) parseInterfaceDeclaration(pos int, hasJSDoc bool, modifiers *as members := p.parseObjectTypeMembers() result := p.finishNode(p.factory.NewInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") - } + p.checkJSSyntax(result) return result } @@ -1974,9 +1968,7 @@ func (p *Parser) parseTypeAliasDeclaration(pos int, hasJSDoc bool, modifiers *as p.parseSemicolon() result := p.finishNode(p.factory.NewTypeAliasDeclaration(modifiers, name, typeParameters, typeNode), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(name.Loc, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) - } + p.checkJSSyntax(result) return result } @@ -2014,9 +2006,7 @@ func (p *Parser) parseEnumDeclaration(pos int, hasJSDoc bool, modifiers *ast.Mod } result := p.finishNode(p.factory.NewEnumDeclaration(modifiers, name, members), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") - } + p.checkJSSyntax(result) p.statementHasAwaitIdentifier = saveHasAwaitIdentifier return result } @@ -2093,9 +2083,7 @@ func (p *Parser) parseModuleOrNamespaceDeclaration(pos int, hasJSDoc bool, modif } result := p.finishNode(p.factory.NewModuleDeclaration(modifiers, keyword, name, body), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(name.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(keyword)) - } + p.checkJSSyntax(result) p.statementHasAwaitIdentifier = saveHasAwaitIdentifier return result } @@ -2120,11 +2108,8 @@ func (p *Parser) parseImportDeclarationOrImportEqualsDeclaration(pos int, hasJSD } } if identifier != nil && !p.tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() { - importEquals := p.parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly) + importEquals := p.checkJSSyntax(p.parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly)) p.statementHasAwaitIdentifier = saveHasAwaitIdentifier // Import= declaration is always parsed in an Await context, no need to reparse - if importEquals.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(importEquals.Loc, diagnostics.X_import_can_only_be_used_in_TypeScript_files) - } return importEquals } importClause := p.tryParseImportClause(identifier, afterImportPos, isTypeOnly, false /*skipJSDocLeadingAsterisks*/) @@ -2134,9 +2119,7 @@ func (p *Parser) parseImportDeclarationOrImportEqualsDeclaration(pos int, hasJSD p.parseSemicolon() result := p.finishNode(p.factory.NewImportDeclaration(modifiers, importClause, moduleSpecifier, attributes), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { - p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import type") - } + p.checkJSSyntax(result) return result } @@ -2266,10 +2249,7 @@ func (p *Parser) parseImportSpecifier() *ast.Node { identifierName = p.newIdentifier("") p.finishNode(identifierName, name.Pos()) } - result := p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { - p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "import...type") - } + result := p.checkJSSyntax(p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos)) return result } @@ -2384,9 +2364,7 @@ func (p *Parser) parseExportAssignment(pos int, hasJSDoc bool, modifiers *ast.Mo p.statementHasAwaitIdentifier = saveHasAwaitIdentifier result := p.finishNode(p.factory.NewExportAssignment(modifiers, isExportEquals, nil /*typeNode*/, expression), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isExportEquals { - p.jsErrorAtRange(result.Loc, diagnostics.X_export_can_only_be_used_in_TypeScript_files) - } + p.checkJSSyntax(result) return result } @@ -2436,9 +2414,7 @@ func (p *Parser) parseExportDeclaration(pos int, hasJSDoc bool, modifiers *ast.M p.statementHasAwaitIdentifier = saveHasAwaitIdentifier result := p.finishNode(p.factory.NewExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { - p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export type") - } + p.checkJSSyntax(result) return result } @@ -2463,9 +2439,7 @@ func (p *Parser) parseExportSpecifier() *ast.Node { isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(ast.KindExportSpecifier) result := p.finishNode(p.factory.NewExportSpecifier(isTypeOnly, propertyName, name), pos) p.withJSDoc(result, hasJSDoc) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 && isTypeOnly { - p.jsErrorAtRange(result.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "export...type") - } + p.checkJSSyntax(result) return result } @@ -4503,19 +4477,11 @@ func (p *Parser) parseBinaryExpressionRest(precedence ast.OperatorPrecedence, le } func (p *Parser) makeSatisfiesExpression(expression *ast.Expression, typeNode *ast.TypeNode) *ast.Node { - result := p.finishNode(p.factory.NewSatisfiesExpression(expression, typeNode), expression.Pos()) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(typeNode.Loc, diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files) - } - return result + return p.checkJSSyntax(p.finishNode(p.factory.NewSatisfiesExpression(expression, typeNode), expression.Pos())) } func (p *Parser) makeAsExpression(left *ast.Expression, right *ast.TypeNode) *ast.Node { - result := p.finishNode(p.factory.NewAsExpression(left, right), left.Pos()) - if result.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(right.Loc, diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files) - } - return result + return p.checkJSSyntax(p.finishNode(p.factory.NewAsExpression(left, right), left.Pos())) } func (p *Parser) makeBinaryExpression(left *ast.Expression, operatorToken *ast.Node, right *ast.Expression, pos int) *ast.Node { @@ -5217,10 +5183,7 @@ func (p *Parser) parseMemberExpressionRest(pos int, expression *ast.Expression, if questionDotToken == nil { if p.token == ast.KindExclamationToken && !p.hasPrecedingLineBreak() { p.nextToken() - expression = p.finishNode(p.factory.NewNonNullExpression(expression, ast.NodeFlagsNone), pos) - if expression.Flags&ast.NodeFlagsJavaScriptFile != 0 { - p.jsErrorAtRange(expression.Loc, diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files) - } + expression = p.checkJSSyntax(p.finishNode(p.factory.NewNonNullExpression(expression, ast.NodeFlagsNone), pos)) continue } typeArguments := p.tryParseTypeArgumentsInExpression() @@ -6558,13 +6521,13 @@ func (p *Parser) checkJSSyntax(node *ast.Node) *ast.Node { p.jsErrorAtRange(node.Loc, diagnostics.X_implements_clauses_can_only_be_used_in_TypeScript_files) } case ast.KindInterfaceDeclaration: - p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") + p.jsErrorAtRange(node.Name().Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "interface") case ast.KindModuleDeclaration: - p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(node.AsModuleDeclaration().Keyword)) + p.jsErrorAtRange(node.Name().Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, scanner.TokenToString(node.AsModuleDeclaration().Keyword)) case ast.KindTypeAliasDeclaration: - p.jsErrorAtRange(node.Loc, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) + p.jsErrorAtRange(node.Name().Loc, diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files) case ast.KindEnumDeclaration: - p.jsErrorAtRange(node.Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") + p.jsErrorAtRange(node.Name().Loc, diagnostics.X_0_declarations_can_only_be_used_in_TypeScript_files, "enum") case ast.KindNonNullExpression: p.jsErrorAtRange(node.Loc, diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files) case ast.KindAsExpression: