fix(compiler): Improved error reporting of the static reflector.
StaticReflector provides more context on errors reported by the collector. The metadata collector now records the line and character of the node that caused it to report the error. Includes other minor fixes to error reporting and a wording change. Fixes #8978 Closes #9011
This commit is contained in:
@ -30,7 +30,7 @@ import {
|
||||
keyframes
|
||||
} from "@angular/core";
|
||||
import {ReflectorReader} from "./core_private";
|
||||
|
||||
|
||||
const SUPPORTED_SCHEMA_VERSION = 1;
|
||||
|
||||
/**
|
||||
@ -390,7 +390,11 @@ export class StaticReflector implements ReflectorReader {
|
||||
return context;
|
||||
}
|
||||
case "error":
|
||||
throw new Error(expression['message']);
|
||||
let message = produceErrorMessage(expression);
|
||||
if (expression['line']) {
|
||||
message = `${message} (position ${expression['line']}:${expression['character']} in the original .ts file)`;
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -399,7 +403,11 @@ export class StaticReflector implements ReflectorReader {
|
||||
return null;
|
||||
}
|
||||
|
||||
return simplify(value);
|
||||
try {
|
||||
return simplify(value);
|
||||
} catch(e) {
|
||||
throw new Error(`${e.message}, resolving symbol ${context.name} in ${context.filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,6 +439,33 @@ export class StaticReflector implements ReflectorReader {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function expandedMessage(error: any): string {
|
||||
switch (error.message) {
|
||||
case 'Reference to non-exported class':
|
||||
if (error.context && error.context.className) {
|
||||
return `Reference to a non-exported class ${error.context.className}`;
|
||||
}
|
||||
break;
|
||||
case 'Variable not initialized':
|
||||
return 'Only initialized variables and constants can be referenced';
|
||||
case 'Destructuring not supported':
|
||||
return 'Referencing an exported destructured variable or constant is not supported';
|
||||
case 'Could not resolve type':
|
||||
if (error.context && error.context.typeName) {
|
||||
return `Could not resolve type ${error.context.typeName}`;
|
||||
}
|
||||
break;
|
||||
case 'Function call not supported':
|
||||
return 'Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
|
||||
}
|
||||
return error.message;
|
||||
}
|
||||
|
||||
function produceErrorMessage(error: any): string {
|
||||
return `Error encountered resolving symbol values statically. ${expandedMessage(error)}`;
|
||||
}
|
||||
|
||||
function mapStringMap(input: {[key: string]: any},
|
||||
|
@ -109,6 +109,11 @@ describe('StaticReflector', () => {
|
||||
expect(parameters).toEqual([]);
|
||||
});
|
||||
|
||||
it('should provide context for errors reported by the collector', () => {
|
||||
let SomeClass = host.findDeclaration('src/error-reporting', 'SomeClass');
|
||||
expect(() => reflector.annotations(SomeClass)).toThrow(new Error('Error encountered resolving symbol values statically. A reasonable error message (position 12:33 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
||||
});
|
||||
|
||||
it('should simplify primitive into itself', () => {
|
||||
expect(simplify(noContext, 1)).toBe(1);
|
||||
expect(simplify(noContext, true)).toBe(true);
|
||||
@ -537,6 +542,58 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||
},
|
||||
'/src/extern.d.ts': {"__symbolic": "module", "version": 1, metadata: {s: "s"}},
|
||||
'/tmp/src/version-error.d.ts': {"__symbolic": "module", "version": 100, metadata: {e: "s"}},
|
||||
'/tmp/src/error-reporting.d.ts': {
|
||||
__symbolic: "module",
|
||||
version: 1,
|
||||
metadata: {
|
||||
SomeClass: {
|
||||
__symbolic: "class",
|
||||
decorators: [
|
||||
{
|
||||
__symbolic: "call",
|
||||
expression: {
|
||||
__symbolic: "reference",
|
||||
name: "Component",
|
||||
module: "angular2/src/core/metadata"
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
directives: [
|
||||
{
|
||||
__symbolic: "reference",
|
||||
module: "src/error-references",
|
||||
name: "Link1",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
'/tmp/src/error-references.d.ts': {
|
||||
__symbolic: "module",
|
||||
version: 1,
|
||||
metadata: {
|
||||
Link1: {
|
||||
__symbolic: "reference",
|
||||
module: "src/error-references",
|
||||
name: "Link2"
|
||||
},
|
||||
Link2: {
|
||||
__symbolic: "reference",
|
||||
module: "src/error-references",
|
||||
name: "ErrorSym"
|
||||
},
|
||||
ErrorSym: {
|
||||
__symbolic: "error",
|
||||
message: "A reasonable error message",
|
||||
line: 12,
|
||||
character: 33
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return data[moduleId];
|
||||
}
|
||||
|
Reference in New Issue
Block a user