feat(compiler-cli): improve error messages produced during structural errors (#20459)
The errors produced when error were encountered while interpreting the content of a directive was often incomprehencible. With this change these kind of error messages should be easier to understand and diagnose. PR Close #20459
This commit is contained in:

committed by
Miško Hevery

parent
1366762d12
commit
8ecda94899
@ -8,8 +8,8 @@
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {Evaluator, errorSymbol} from './evaluator';
|
||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
|
||||
import {Evaluator, errorSymbol, recordMapEntry} from './evaluator';
|
||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
|
||||
import {Symbols} from './symbols';
|
||||
|
||||
const isStatic = (node: ts.Node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
|
||||
@ -76,8 +76,7 @@ export class MetadataCollector {
|
||||
}
|
||||
|
||||
function recordEntry<T extends MetadataEntry>(entry: T, node: ts.Node): T {
|
||||
nodeMap.set(entry, node);
|
||||
return entry;
|
||||
return recordMapEntry(entry, node, nodeMap, sourceFile);
|
||||
}
|
||||
|
||||
function errorSym(
|
||||
|
@ -9,10 +9,11 @@
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {CollectorOptions} from './collector';
|
||||
import {MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
||||
import {ClassMetadata, FunctionMetadata, InterfaceMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
||||
import {Symbols} from './symbols';
|
||||
|
||||
|
||||
|
||||
// In TypeScript 2.1 the spread element kind was renamed.
|
||||
const spreadElementSyntaxKind: ts.SyntaxKind =
|
||||
(ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression;
|
||||
@ -38,6 +39,24 @@ function isCallOf(callExpression: ts.CallExpression, ident: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function recordMapEntry<T extends MetadataEntry>(
|
||||
entry: T, node: ts.Node,
|
||||
nodeMap: Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>,
|
||||
sourceFile?: ts.SourceFile) {
|
||||
if (!nodeMap.has(entry)) {
|
||||
nodeMap.set(entry, node);
|
||||
if (node && (isMetadataImportedSymbolReferenceExpression(entry) ||
|
||||
isMetadataImportDefaultReference(entry)) &&
|
||||
entry.line == null) {
|
||||
const info = sourceInfo(node, sourceFile);
|
||||
if (info.line != null) entry.line = info.line;
|
||||
if (info.character != null) entry.character = info.character;
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* ts.forEachChild stops iterating children when the callback return a truthy value.
|
||||
* This method inverts this to implement an `every` style iterator. It will return
|
||||
@ -77,21 +96,22 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function errorSymbol(
|
||||
message: string, node?: ts.Node, context?: {[name: string]: string},
|
||||
sourceFile?: ts.SourceFile): MetadataError {
|
||||
let result: MetadataError|undefined = undefined;
|
||||
export function sourceInfo(
|
||||
node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo {
|
||||
if (node) {
|
||||
sourceFile = sourceFile || getSourceFileOfNode(node);
|
||||
if (sourceFile) {
|
||||
const {line, character} =
|
||||
ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
||||
result = {__symbolic: 'error', message, line, character};
|
||||
return ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
result = {__symbolic: 'error', message};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function errorSymbol(
|
||||
message: string, node?: ts.Node, context?: {[name: string]: string},
|
||||
sourceFile?: ts.SourceFile): MetadataError {
|
||||
const result: MetadataError = {__symbolic: 'error', message, ...sourceInfo(node, sourceFile)};
|
||||
if (context) {
|
||||
result.context = context;
|
||||
}
|
||||
@ -242,8 +262,7 @@ export class Evaluator {
|
||||
}
|
||||
entry = newEntry;
|
||||
}
|
||||
t.nodeMap.set(entry, node);
|
||||
return entry;
|
||||
return recordMapEntry(entry, node, t.nodeMap);
|
||||
}
|
||||
|
||||
function isFoldableError(value: any): value is MetadataError {
|
||||
@ -256,6 +275,9 @@ export class Evaluator {
|
||||
// Encode as a global reference. StaticReflector will check the reference.
|
||||
return recordEntry({__symbolic: 'reference', name}, node);
|
||||
}
|
||||
if (reference && isMetadataSymbolicReferenceExpression(reference)) {
|
||||
return recordEntry({...reference}, node);
|
||||
}
|
||||
return reference;
|
||||
};
|
||||
|
||||
@ -628,7 +650,7 @@ export class Evaluator {
|
||||
return recordEntry({__symbolic: 'if', condition, thenExpression, elseExpression}, node);
|
||||
case ts.SyntaxKind.FunctionExpression:
|
||||
case ts.SyntaxKind.ArrowFunction:
|
||||
return recordEntry(errorSymbol('Function call not supported', node), node);
|
||||
return recordEntry(errorSymbol('Lambda not supported', node), node);
|
||||
case ts.SyntaxKind.TaggedTemplateExpression:
|
||||
return recordEntry(
|
||||
errorSymbol('Tagged template expressions are not supported in metadata', node), node);
|
||||
|
@ -178,7 +178,20 @@ export function isMetadataSymbolicIfExpression(value: any): value is MetadataSym
|
||||
return value && value.__symbolic === 'if';
|
||||
}
|
||||
|
||||
export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression {
|
||||
export interface MetadataSourceLocationInfo {
|
||||
/**
|
||||
* The line number of the error in the .ts file the metadata was created for.
|
||||
*/
|
||||
line?: number;
|
||||
|
||||
/**
|
||||
* The number of utf8 code-units from the beginning of the file of the error.
|
||||
*/
|
||||
character?: number;
|
||||
}
|
||||
|
||||
export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression,
|
||||
MetadataSourceLocationInfo {
|
||||
__symbolic: 'reference';
|
||||
name: string;
|
||||
arguments?: MetadataValue[];
|
||||
@ -188,7 +201,8 @@ export function isMetadataGlobalReferenceExpression(value: any):
|
||||
return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
|
||||
}
|
||||
|
||||
export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression {
|
||||
export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression,
|
||||
MetadataSourceLocationInfo {
|
||||
__symbolic: 'reference';
|
||||
module: string;
|
||||
}
|
||||
@ -198,7 +212,8 @@ export function isMetadataModuleReferenceExpression(value: any):
|
||||
isMetadataSymbolicReferenceExpression(value);
|
||||
}
|
||||
|
||||
export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression {
|
||||
export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression,
|
||||
MetadataSourceLocationInfo {
|
||||
__symbolic: 'reference';
|
||||
module: string;
|
||||
name: string;
|
||||
@ -209,7 +224,8 @@ export function isMetadataImportedSymbolReferenceExpression(value: any):
|
||||
return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
|
||||
}
|
||||
|
||||
export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression {
|
||||
export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression,
|
||||
MetadataSourceLocationInfo {
|
||||
__symbolic: 'reference';
|
||||
module: string;
|
||||
default:
|
||||
@ -218,7 +234,7 @@ export interface MetadataImportedDefaultReferenceExpression extends MetadataSymb
|
||||
}
|
||||
export function isMetadataImportDefaultReference(value: any):
|
||||
value is MetadataImportedDefaultReferenceExpression {
|
||||
return value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
||||
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
||||
}
|
||||
|
||||
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
|
||||
@ -248,7 +264,7 @@ export function isMetadataSymbolicSpreadExpression(value: any):
|
||||
return value && value.__symbolic === 'spread';
|
||||
}
|
||||
|
||||
export interface MetadataError {
|
||||
export interface MetadataError extends MetadataSourceLocationInfo {
|
||||
__symbolic: 'error';
|
||||
|
||||
/**
|
||||
@ -259,16 +275,6 @@ export interface MetadataError {
|
||||
*/
|
||||
message: string;
|
||||
|
||||
/**
|
||||
* The line number of the error in the .ts file the metadata was created for.
|
||||
*/
|
||||
line?: number;
|
||||
|
||||
/**
|
||||
* The number of utf8 code-units from the beginning of the file of the error.
|
||||
*/
|
||||
character?: number;
|
||||
|
||||
/**
|
||||
* The module of the error (only used in bundled metadata)
|
||||
*/
|
||||
@ -280,6 +286,7 @@ export interface MetadataError {
|
||||
*/
|
||||
context?: {[name: string]: string};
|
||||
}
|
||||
|
||||
export function isMetadataError(value: any): value is MetadataError {
|
||||
return value && value.__symbolic === 'error';
|
||||
}
|
||||
|
Reference in New Issue
Block a user