fixup! feat(ivy): Add AOT handling for bare classes with Input and Output decorators

This commit is contained in:
Ben Lesh 2018-08-09 09:16:58 -07:00
parent 244ee5846d
commit 70b1b8385f
6 changed files with 40 additions and 22 deletions

View File

@ -9,8 +9,7 @@ import {ConstantPool} from '@angular/compiler';
import * as fs from 'fs'; import * as fs from 'fs';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../ngtsc/annotations'; import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../ngtsc/annotations';
import {BaseDefDecoratorHandler} from '../../ngtsc/annotations/src/base_def';
import {Decorator} from '../../ngtsc/host'; import {Decorator} from '../../ngtsc/host';
import {CompileResult, DecoratorHandler} from '../../ngtsc/transform'; import {CompileResult, DecoratorHandler} from '../../ngtsc/transform';
@ -34,7 +33,7 @@ export interface AnalyzedFile {
export interface MatchingHandler<A, M> { export interface MatchingHandler<A, M> {
handler: DecoratorHandler<A, M>; handler: DecoratorHandler<A, M>;
decorator: Decorator; match: M;
} }
/** /**
@ -80,9 +79,10 @@ export class Analyzer {
|undefined { |undefined {
const matchingHandlers = const matchingHandlers =
this.handlers this.handlers
.map( .map(handler => ({
handler => handler,
({handler, decorator: handler.detect(clazz.declaration, clazz.decorators)})) decorator: handler.detect(clazz.declaration, clazz.decorators),
}))
.filter(isMatchingHandler); .filter(isMatchingHandler);
if (matchingHandlers.length > 1) { if (matchingHandlers.length > 1) {
@ -105,5 +105,5 @@ export class Analyzer {
function isMatchingHandler<A, M>(handler: Partial<MatchingHandler<A, M>>): function isMatchingHandler<A, M>(handler: Partial<MatchingHandler<A, M>>):
handler is MatchingHandler<A, M> { handler is MatchingHandler<A, M> {
return !!handler.decorator; return !!handler.match;
} }

View File

@ -7,6 +7,7 @@
*/ */
export {ResourceLoader} from './src/api'; export {ResourceLoader} from './src/api';
export {BaseDefDecoratorHandler} from './src/base_def';
export {ComponentDecoratorHandler} from './src/component'; export {ComponentDecoratorHandler} from './src/component';
export {DirectiveDecoratorHandler} from './src/directive'; export {DirectiveDecoratorHandler} from './src/directive';
export {InjectableDecoratorHandler} from './src/injectable'; export {InjectableDecoratorHandler} from './src/injectable';

View File

@ -32,7 +32,7 @@ export class BaseDefDecoratorHandler implements
|undefined { |undefined {
if (containsNgTopLevelDecorator(decorators)) { if (containsNgTopLevelDecorator(decorators)) {
// If the class is already decorated by @Component or @Directive let that // If the class is already decorated by @Component or @Directive let that
// decorator handle this. BaseDef is unnecessary. // DecoratorHandler handle this. BaseDef is unnecessary.
return undefined; return undefined;
} }
@ -67,10 +67,16 @@ export class BaseDefDecoratorHandler implements
metadata.inputs.forEach(({decorator, property}) => { metadata.inputs.forEach(({decorator, property}) => {
const propName = property.name; const propName = property.name;
const args = decorator.args; const args = decorator.args;
const value: string|[string, string] = args && args.length >= 1 ? let value: string|[string, string];
[staticallyResolve(args[0], this.reflector, this.checker) as string, propName] : if (args && args.length > 0) {
propName; const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker);
if (typeof resolvedValue !== 'string') {
throw new TypeError('Input alias does not resolve to a string value');
}
value = [resolvedValue, propName];
} else {
value = propName;
}
inputs[propName] = value; inputs[propName] = value;
}); });
} }
@ -80,9 +86,16 @@ export class BaseDefDecoratorHandler implements
metadata.outputs.forEach(({decorator, property}) => { metadata.outputs.forEach(({decorator, property}) => {
const propName = property.name; const propName = property.name;
const args = decorator.args; const args = decorator.args;
const value = args && args.length >= 1 ? let value: string;
staticallyResolve(args[0], this.reflector, this.checker) as string : if (args && args.length > 0) {
propName; const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker);
if (typeof resolvedValue !== 'string') {
throw new TypeError('Output alias does not resolve to a string value');
}
value = resolvedValue;
} else {
value = propName;
}
outputs[propName] = value; outputs[propName] = value;
}); });
} }

View File

@ -22,7 +22,7 @@ import {DtsFileTransformer} from './declaration';
interface EmitFieldOperation<A, M> { interface EmitFieldOperation<A, M> {
adapter: DecoratorHandler<A, M>; adapter: DecoratorHandler<A, M>;
analysis: AnalysisOutput<A>; analysis: AnalysisOutput<A>;
decorator: Decorator; metadata: M;
} }
/** /**
@ -104,7 +104,7 @@ export class IvyCompilation {
this.analysis.set(node, { this.analysis.set(node, {
adapter, adapter,
analysis: analysis.analysis, analysis: analysis.analysis,
decorator: metadata, metadata: metadata,
}); });
} }
@ -185,7 +185,7 @@ export class IvyCompilation {
return undefined; return undefined;
} }
return this.analysis.get(original) !.decorator; return this.analysis.get(original) !.metadata;
} }
/** /**

View File

@ -1979,7 +1979,6 @@ describe('compiler compliance', () => {
// ... // ...
`; `;
const result = compile(files, angularFiles); const result = compile(files, angularFiles);
debugger;
expectEmit(result.source, expectedOutput, 'Invalid base definition'); expectEmit(result.source, expectedOutput, 'Invalid base definition');
}); });
@ -2019,7 +2018,7 @@ describe('compiler compliance', () => {
} }
}; };
const result = compile(files, angularFiles); const result = compile(files, angularFiles);
expect(result.source.indexOf('ngBaseDef')).toBe(-1); expect(result.source).not.toContain('ngBaseDef');
}); });
it('should NOT add ngBaseDef if @Directive is present', () => { it('should NOT add ngBaseDef if @Directive is present', () => {
@ -2057,7 +2056,7 @@ describe('compiler compliance', () => {
} }
}; };
const result = compile(files, angularFiles); const result = compile(files, angularFiles);
expect(result.source.indexOf('ngBaseDef')).toBe(-1); expect(result.source).not.toContain('ngBaseDef');
}); });
}); });
}); });

View File

@ -779,6 +779,11 @@ const initializeBaseDef = (target: any): void => {
} }
}; };
/**
* Used to get the minified alias of ngBaseDef
*/
const NG_BASE_DEF = Object.keys({ngBaseDef: true})[0];
/** /**
* Does the work of creating the `ngBaseDef` property for the @Input and @Output decorators. * Does the work of creating the `ngBaseDef` property for the @Input and @Output decorators.
* @param key "inputs" or "outputs" * @param key "inputs" or "outputs"
@ -787,7 +792,7 @@ const updateBaseDefFromIOProp = (getProp: (baseDef: {inputs?: any, outputs?: any
(target: any, name: string, ...args: any[]) => { (target: any, name: string, ...args: any[]) => {
const constructor = target.constructor; const constructor = target.constructor;
if (!constructor.hasOwnProperty('ngBaseDef')) { if (!constructor.hasOwnProperty(NG_BASE_DEF)) {
initializeBaseDef(target); initializeBaseDef(target);
} }