mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-13 04:57:55 -06:00
Merge pull request #11978 from Microsoft/errorReportingInJsFile
Report all the js file errors and skip only the nodes that are not allowed in JS file
This commit is contained in:
commit
c87bce1119
@ -908,48 +908,24 @@ namespace ts {
|
||||
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
||||
return runWithCancellationToken(() => {
|
||||
const diagnostics: Diagnostic[] = [];
|
||||
let parent: Node = sourceFile;
|
||||
walk(sourceFile);
|
||||
|
||||
return diagnostics;
|
||||
|
||||
function walk(node: Node): boolean {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
function walk(node: Node) {
|
||||
// Return directly from the case if the given node doesnt want to visit each child
|
||||
// Otherwise break to visit each child
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.ExportAssignment:
|
||||
if ((<ExportAssignment>node).isExportEquals) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
if ((<ParameterDeclaration | PropertyDeclaration>parent).questionToken === node) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
let classDeclaration = <ClassDeclaration>node;
|
||||
if (checkModifiers(classDeclaration.modifiers) ||
|
||||
checkTypeParameters(classDeclaration.typeParameters)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.HeritageClause:
|
||||
let heritageClause = <HeritageClause>node;
|
||||
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
|
||||
// Pass through
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
@ -959,124 +935,151 @@ namespace ts {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
const functionDeclaration = <FunctionLikeDeclaration>node;
|
||||
if (checkModifiers(functionDeclaration.modifiers) ||
|
||||
checkTypeParameters(functionDeclaration.typeParameters) ||
|
||||
checkTypeAnnotation(functionDeclaration.type)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.VariableStatement:
|
||||
const variableStatement = <VariableStatement>node;
|
||||
if (checkModifiers(variableStatement.modifiers)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
const variableDeclaration = <VariableDeclaration>node;
|
||||
if (checkTypeAnnotation(variableDeclaration.type)) {
|
||||
return true;
|
||||
// type annotation
|
||||
if ((<FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration>parent).type === node) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.types_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.ExportAssignment:
|
||||
if ((<ExportAssignment>node).isExportEquals) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.HeritageClause:
|
||||
let heritageClause = <HeritageClause>node;
|
||||
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
let typeAssertionExpression = <TypeAssertion>node;
|
||||
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
|
||||
const prevParent = parent;
|
||||
parent = node;
|
||||
forEachChild(node, walk, walkArray);
|
||||
parent = prevParent;
|
||||
}
|
||||
|
||||
function walkArray(nodes: NodeArray<Node>) {
|
||||
if (parent.decorators === nodes && !options.experimentalDecorators) {
|
||||
diagnostics.push(createDiagnosticForNode(parent, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning));
|
||||
}
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
// Check type parameters
|
||||
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration>parent).typeParameters) {
|
||||
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
// pass through
|
||||
case SyntaxKind.VariableStatement:
|
||||
// Check modifiers
|
||||
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration | VariableStatement>parent).modifiers) {
|
||||
return checkModifiers(<NodeArray<Modifier>>nodes, parent.kind === SyntaxKind.VariableStatement);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// Check modifiers of property declaration
|
||||
if (nodes === (<PropertyDeclaration>parent).modifiers) {
|
||||
for (const modifier of <NodeArray<Modifier>>nodes) {
|
||||
if (modifier.kind !== SyntaxKind.StaticKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.Parameter:
|
||||
// Check modifiers of parameter declaration
|
||||
if (nodes === (<ParameterDeclaration>parent).modifiers) {
|
||||
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
const expression = <CallExpression>node;
|
||||
if (expression.typeArguments && expression.typeArguments.length > 0) {
|
||||
const start = expression.typeArguments.pos;
|
||||
diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start,
|
||||
Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
// Check type arguments
|
||||
if (nodes === (<CallExpression | NewExpression | ExpressionWithTypeArguments>parent).typeArguments) {
|
||||
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.Parameter:
|
||||
const parameter = <ParameterDeclaration>node;
|
||||
if (parameter.modifiers) {
|
||||
const start = parameter.modifiers.pos;
|
||||
diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start,
|
||||
Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
}
|
||||
if (parameter.questionToken) {
|
||||
diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
|
||||
return true;
|
||||
}
|
||||
if (parameter.type) {
|
||||
diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
const propertyDeclaration = <PropertyDeclaration>node;
|
||||
if (propertyDeclaration.modifiers) {
|
||||
for (const modifier of propertyDeclaration.modifiers) {
|
||||
if (modifier.kind !== SyntaxKind.StaticKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
walk(node);
|
||||
}
|
||||
}
|
||||
|
||||
function checkModifiers(modifiers: NodeArray<Modifier>, isConstValid: boolean) {
|
||||
for (const modifier of modifiers) {
|
||||
switch (modifier.kind) {
|
||||
case SyntaxKind.ConstKeyword:
|
||||
if (isConstValid) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (checkTypeAnnotation((<PropertyDeclaration>node).type)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
let typeAssertionExpression = <TypeAssertion>node;
|
||||
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
case SyntaxKind.Decorator:
|
||||
if (!options.experimentalDecorators) {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Fallthrough to report error
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
break;
|
||||
|
||||
return forEachChild(node, walk);
|
||||
}
|
||||
|
||||
function checkTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration>): boolean {
|
||||
if (typeParameters) {
|
||||
const start = typeParameters.pos;
|
||||
diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkTypeAnnotation(type: TypeNode): boolean {
|
||||
if (type) {
|
||||
diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkModifiers(modifiers: NodeArray<Modifier>): boolean {
|
||||
if (modifiers) {
|
||||
for (const modifier of modifiers) {
|
||||
switch (modifier.kind) {
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
return true;
|
||||
|
||||
// These are all legal modifiers.
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
case SyntaxKind.DefaultKeyword:
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
}
|
||||
// These are all legal modifiers.
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.DefaultKeyword:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
|
||||
const start = nodes.pos;
|
||||
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
// Since these are syntactic diagnostics, parent might not have been set
|
||||
// this means the sourceFile cannot be infered from the node
|
||||
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
|
||||
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -514,6 +514,10 @@ namespace ts {
|
||||
|
||||
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
|
||||
const span = getErrorSpanForNode(sourceFile, node);
|
||||
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
13
tests/baselines/reference/decoratorInJsFile.errors.txt
Normal file
13
tests/baselines/reference/decoratorInJsFile.errors.txt
Normal file
@ -0,0 +1,13 @@
|
||||
tests/cases/compiler/a.js(4,12): error TS8010: 'types' can only be used in a .ts file.
|
||||
|
||||
|
||||
==== tests/cases/compiler/a.js (1 errors) ====
|
||||
|
||||
@SomeDecorator
|
||||
class SomeClass {
|
||||
foo(x: number) {
|
||||
~~~~~~
|
||||
!!! error TS8010: 'types' can only be used in a .ts file.
|
||||
|
||||
}
|
||||
}
|
||||
16
tests/baselines/reference/decoratorInJsFile1.errors.txt
Normal file
16
tests/baselines/reference/decoratorInJsFile1.errors.txt
Normal file
@ -0,0 +1,16 @@
|
||||
tests/cases/compiler/a.js(3,7): error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
|
||||
tests/cases/compiler/a.js(4,12): error TS8010: 'types' can only be used in a .ts file.
|
||||
|
||||
|
||||
==== tests/cases/compiler/a.js (2 errors) ====
|
||||
|
||||
@SomeDecorator
|
||||
class SomeClass {
|
||||
~~~~~~~~~
|
||||
!!! error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
|
||||
foo(x: number) {
|
||||
~~~~~~
|
||||
!!! error TS8010: 'types' can only be used in a .ts file.
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
error TS5055: Cannot write file 'tests/cases/compiler/a.js' because it would overwrite input file.
|
||||
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig
|
||||
tests/cases/compiler/a.js(1,1): error TS8009: 'abstract' can only be used in a .ts file.
|
||||
tests/cases/compiler/a.js(2,5): error TS8009: 'abstract' can only be used in a .ts file.
|
||||
|
||||
|
||||
!!! error TS5055: Cannot write file 'tests/cases/compiler/a.js' because it would overwrite input file.
|
||||
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig
|
||||
==== tests/cases/compiler/a.js (2 errors) ====
|
||||
abstract class c {
|
||||
~~~~~~~~
|
||||
!!! error TS8009: 'abstract' can only be used in a .ts file.
|
||||
abstract x;
|
||||
~~~~~~~~
|
||||
!!! error TS8009: 'abstract' can only be used in a .ts file.
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
=== tests/cases/compiler/a.js ===
|
||||
const c = 10;
|
||||
>c : Symbol(c, Decl(a.js, 0, 5))
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
=== tests/cases/compiler/a.js ===
|
||||
const c = 10;
|
||||
>c : 10
|
||||
>10 : 10
|
||||
|
||||
12
tests/cases/compiler/decoratorInJsFile.ts
Normal file
12
tests/cases/compiler/decoratorInJsFile.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @experimentaldecorators: true
|
||||
// @emitdecoratormetadata: true
|
||||
// @allowjs: true
|
||||
// @noEmit: true
|
||||
|
||||
// @filename: a.js
|
||||
@SomeDecorator
|
||||
class SomeClass {
|
||||
foo(x: number) {
|
||||
|
||||
}
|
||||
}
|
||||
10
tests/cases/compiler/decoratorInJsFile1.ts
Normal file
10
tests/cases/compiler/decoratorInJsFile1.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @allowjs: true
|
||||
// @noEmit: true
|
||||
|
||||
// @filename: a.js
|
||||
@SomeDecorator
|
||||
class SomeClass {
|
||||
foo(x: number) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
// @allowJs: true
|
||||
// @filename: a.js
|
||||
abstract class c {
|
||||
abstract x;
|
||||
}
|
||||
4
tests/cases/compiler/jsFileCompilationConstModifier.ts
Normal file
4
tests/cases/compiler/jsFileCompilationConstModifier.ts
Normal file
@ -0,0 +1,4 @@
|
||||
// @allowJs: true
|
||||
// @filename: a.js
|
||||
// @noEmit: true
|
||||
const c = 10;
|
||||
@ -15,6 +15,13 @@ verify.getSyntacticDiagnostics(`[
|
||||
"category": "error",
|
||||
"code": 8010
|
||||
},
|
||||
{
|
||||
"message": "\'types\' can only be used in a .ts file.",
|
||||
"start": 52,
|
||||
"length": 6,
|
||||
"category": "error",
|
||||
"code": 8010
|
||||
},
|
||||
{
|
||||
"message": "Variable declaration expected.",
|
||||
"start": 67,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user