refactor(ivy): remove ngBaseDef (#33264)
Removes `ngBaseDef` from the compiler and any runtime code that was still referring to it. In the cases where we'd previously generate a base def we now generate a definition for an abstract directive. PR Close #33264
This commit is contained in:
parent
3505692f75
commit
14c4b1b205
|
@ -95,12 +95,12 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'."
|
||||||
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm5)."
|
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm5)."
|
||||||
|
|
||||||
|
|
||||||
# Did it generate a base definition for undecorated classes with inputs and view queries?
|
# Did it generate an abstract directive definition for undecorated classes with inputs and view queries?
|
||||||
grep "_MatMenuBase.ngBaseDef = ɵngcc0.ɵɵdefineBase({ inputs: {" node_modules/@angular/material/esm2015/menu.js
|
grep "_MatMenuBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: _MatMenuBase" node_modules/@angular/material/esm2015/menu.js
|
||||||
assertSucceeded "Expected 'ngcc' to generate a base definition for 'MatMenuBase' in '@angular/material' (esm2015)."
|
assertSucceeded "Expected 'ngcc' to generate an abstract directive definition for 'MatMenuBase' in '@angular/material' (esm2015)."
|
||||||
|
|
||||||
grep "_MatMenuBase.ngBaseDef = ɵngcc0.ɵɵdefineBase({ inputs: {" node_modules/@angular/material/esm5/menu.es5.js
|
grep "_MatMenuBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: _MatMenuBase" node_modules/@angular/material/esm5/menu.es5.js
|
||||||
assertSucceeded "Expected 'ngcc' to generate a base definition for 'MatMenuBase' in '@angular/material' (esm5)."
|
assertSucceeded "Expected 'ngcc' to generate an abstract directive definition for 'MatMenuBase' in '@angular/material' (esm5)."
|
||||||
|
|
||||||
|
|
||||||
# Did it handle namespace imported decorators in UMD using `__decorate` syntax?
|
# Did it handle namespace imported decorators in UMD using `__decorate` syntax?
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import {ConstantPool} from '@angular/compiler';
|
import {ConstantPool} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations';
|
||||||
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations';
|
|
||||||
import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles';
|
import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles';
|
||||||
import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
||||||
import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system';
|
import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system';
|
||||||
|
@ -85,7 +84,6 @@ export class DecorationAnalyzer {
|
||||||
importGraph = new ImportGraph(this.moduleResolver);
|
importGraph = new ImportGraph(this.moduleResolver);
|
||||||
cycleAnalyzer = new CycleAnalyzer(this.importGraph);
|
cycleAnalyzer = new CycleAnalyzer(this.importGraph);
|
||||||
handlers: DecoratorHandler<any, any>[] = [
|
handlers: DecoratorHandler<any, any>[] = [
|
||||||
new BaseDefDecoratorHandler(this.reflectionHost, this.evaluator, this.isCore),
|
|
||||||
new ComponentDecoratorHandler(
|
new ComponentDecoratorHandler(
|
||||||
this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader,
|
this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader,
|
||||||
this.scopeRegistry, this.scopeRegistry, this.isCore, this.resourceManager, this.rootDirs,
|
this.scopeRegistry, this.scopeRegistry, this.isCore, this.resourceManager, this.rootDirs,
|
||||||
|
|
|
@ -284,7 +284,7 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });
|
||||||
.toBeGreaterThan(ngInjectorDef, 'setClassMetadata should follow ɵinj');
|
.toBeGreaterThan(ngInjectorDef, 'setClassMetadata should follow ɵinj');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render classes without decorators if handler matches', () => {
|
it('should render classes without decorators if class fields are decorated', () => {
|
||||||
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
||||||
testFormatter} =
|
testFormatter} =
|
||||||
createTestRenderer('test-package', [{
|
createTestRenderer('test-package', [{
|
||||||
|
@ -309,7 +309,8 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });
|
||||||
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
||||||
expect(addDefinitionsSpy.calls.first().args[2])
|
expect(addDefinitionsSpy.calls.first().args[2])
|
||||||
.toEqual(
|
.toEqual(
|
||||||
`UndecoratedBase.ngBaseDef = ɵngcc0.ɵɵdefineBase({ viewQuery: function (rf, ctx) { if (rf & 1) {
|
`UndecoratedBase.ɵfac = function UndecoratedBase_Factory(t) { return new (t || UndecoratedBase)(); };
|
||||||
|
UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, selectors: [], viewQuery: function UndecoratedBase_Query(rf, ctx) { if (rf & 1) {
|
||||||
ɵngcc0.ɵɵstaticViewQuery(_c0, true);
|
ɵngcc0.ɵɵstaticViewQuery(_c0, true);
|
||||||
} if (rf & 2) {
|
} if (rf & 2) {
|
||||||
var _t;
|
var _t;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
|
|
||||||
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';
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ConstantPool, EMPTY_SOURCE_SPAN, R3BaseRefMetaData, WrappedNodeExpr, compileBaseDefFromMetadata, makeBindingParser} from '@angular/compiler';
|
|
||||||
|
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
|
||||||
import {ClassDeclaration, ClassMember, Decorator, ReflectionHost} from '../../reflection';
|
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
|
|
||||||
|
|
||||||
import {extractHostBindings, queriesFromFields} from './directive';
|
|
||||||
import {isAngularDecorator} from './util';
|
|
||||||
|
|
||||||
function containsNgTopLevelDecorator(decorators: Decorator[] | null, isCore: boolean): boolean {
|
|
||||||
if (!decorators) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return decorators.some(
|
|
||||||
decorator => isAngularDecorator(decorator, 'Component', isCore) ||
|
|
||||||
isAngularDecorator(decorator, 'Directive', isCore) ||
|
|
||||||
isAngularDecorator(decorator, 'NgModule', isCore));
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BaseDefDecoratorHandler implements
|
|
||||||
DecoratorHandler<R3BaseRefMetaData, R3BaseRefDecoratorDetection> {
|
|
||||||
constructor(
|
|
||||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
|
||||||
private isCore: boolean) {}
|
|
||||||
|
|
||||||
readonly precedence = HandlerPrecedence.WEAK;
|
|
||||||
|
|
||||||
detect(node: ClassDeclaration, decorators: Decorator[]|null):
|
|
||||||
DetectResult<R3BaseRefDecoratorDetection>|undefined {
|
|
||||||
if (containsNgTopLevelDecorator(decorators, this.isCore)) {
|
|
||||||
// If the class is already decorated by @Component or @Directive let that
|
|
||||||
// DecoratorHandler handle this. BaseDef is unnecessary.
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result: R3BaseRefDecoratorDetection|undefined = undefined;
|
|
||||||
|
|
||||||
this.reflector.getMembersOfClass(node).forEach(property => {
|
|
||||||
const {decorators} = property;
|
|
||||||
if (!decorators) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const decorator of decorators) {
|
|
||||||
if (isAngularDecorator(decorator, 'Input', this.isCore)) {
|
|
||||||
result = result || {};
|
|
||||||
const inputs = result.inputs = result.inputs || [];
|
|
||||||
inputs.push({decorator, property});
|
|
||||||
} else if (isAngularDecorator(decorator, 'Output', this.isCore)) {
|
|
||||||
result = result || {};
|
|
||||||
const outputs = result.outputs = result.outputs || [];
|
|
||||||
outputs.push({decorator, property});
|
|
||||||
} else if (
|
|
||||||
isAngularDecorator(decorator, 'ViewChild', this.isCore) ||
|
|
||||||
isAngularDecorator(decorator, 'ViewChildren', this.isCore)) {
|
|
||||||
result = result || {};
|
|
||||||
const viewQueries = result.viewQueries = result.viewQueries || [];
|
|
||||||
viewQueries.push({member: property, decorators});
|
|
||||||
} else if (
|
|
||||||
isAngularDecorator(decorator, 'ContentChild', this.isCore) ||
|
|
||||||
isAngularDecorator(decorator, 'ContentChildren', this.isCore)) {
|
|
||||||
result = result || {};
|
|
||||||
const queries = result.queries = result.queries || [];
|
|
||||||
queries.push({member: property, decorators});
|
|
||||||
} else if (
|
|
||||||
isAngularDecorator(decorator, 'HostBinding', this.isCore) ||
|
|
||||||
isAngularDecorator(decorator, 'HostListener', this.isCore)) {
|
|
||||||
result = result || {};
|
|
||||||
const host = result.host = result.host || [];
|
|
||||||
host.push(property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result !== undefined) {
|
|
||||||
return {
|
|
||||||
metadata: result,
|
|
||||||
trigger: null,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
analyze(node: ClassDeclaration, metadata: R3BaseRefDecoratorDetection):
|
|
||||||
AnalysisOutput<R3BaseRefMetaData> {
|
|
||||||
const analysis: R3BaseRefMetaData = {
|
|
||||||
name: node.name.text,
|
|
||||||
type: new WrappedNodeExpr(node.name),
|
|
||||||
typeSourceSpan: EMPTY_SOURCE_SPAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (metadata.inputs) {
|
|
||||||
const inputs = analysis.inputs = {} as{[key: string]: string | [string, string]};
|
|
||||||
metadata.inputs.forEach(({decorator, property}) => {
|
|
||||||
const propName = property.name;
|
|
||||||
const args = decorator.args;
|
|
||||||
let value: string|[string, string];
|
|
||||||
if (args && args.length > 0) {
|
|
||||||
const resolvedValue = this.evaluator.evaluate(args[0]);
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.outputs) {
|
|
||||||
const outputs = analysis.outputs = {} as{[key: string]: string};
|
|
||||||
metadata.outputs.forEach(({decorator, property}) => {
|
|
||||||
const propName = property.name;
|
|
||||||
const args = decorator.args;
|
|
||||||
let value: string;
|
|
||||||
if (args && args.length > 0) {
|
|
||||||
const resolvedValue = this.evaluator.evaluate(args[0]);
|
|
||||||
if (typeof resolvedValue !== 'string') {
|
|
||||||
throw new TypeError('Output alias does not resolve to a string value');
|
|
||||||
}
|
|
||||||
value = resolvedValue;
|
|
||||||
} else {
|
|
||||||
value = propName;
|
|
||||||
}
|
|
||||||
outputs[propName] = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.viewQueries) {
|
|
||||||
analysis.viewQueries =
|
|
||||||
queriesFromFields(metadata.viewQueries, this.reflector, this.evaluator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.queries) {
|
|
||||||
analysis.queries = queriesFromFields(metadata.queries, this.reflector, this.evaluator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.host) {
|
|
||||||
analysis.host = extractHostBindings(
|
|
||||||
metadata.host, this.evaluator, this.isCore ? undefined : '@angular/core');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {analysis};
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(node: ClassDeclaration, analysis: R3BaseRefMetaData, pool: ConstantPool):
|
|
||||||
CompileResult[]|CompileResult {
|
|
||||||
const {expression, type} = compileBaseDefFromMetadata(analysis, pool, makeBindingParser());
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: 'ngBaseDef',
|
|
||||||
initializer: expression, type,
|
|
||||||
statements: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface R3BaseRefDecoratorDetection {
|
|
||||||
inputs?: {property: ClassMember, decorator: Decorator}[];
|
|
||||||
outputs?: {property: ClassMember, decorator: Decorator}[];
|
|
||||||
viewQueries?: {member: ClassMember, decorators: Decorator[]}[];
|
|
||||||
queries?: {member: ClassMember, decorators: Decorator[]}[];
|
|
||||||
host?: ClassMember[];
|
|
||||||
}
|
|
|
@ -19,16 +19,24 @@ import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFl
|
||||||
|
|
||||||
import {compileNgFactoryDefField} from './factory';
|
import {compileNgFactoryDefField} from './factory';
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
import {findAngularDecorator, getConstructorDependencies, readBaseClass, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies} from './util';
|
import {findAngularDecorator, getConstructorDependencies, isAngularDecorator, readBaseClass, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies} from './util';
|
||||||
|
|
||||||
const EMPTY_OBJECT: {[key: string]: string} = {};
|
const EMPTY_OBJECT: {[key: string]: string} = {};
|
||||||
|
const FIELD_DECORATORS = [
|
||||||
|
'Input', 'Output', 'ViewChild', 'ViewChildren', 'ContentChild', 'ContentChildren', 'HostBinding',
|
||||||
|
'HostListener'
|
||||||
|
];
|
||||||
|
const LIFECYCLE_HOOKS = new Set([
|
||||||
|
'ngOnChanges', 'ngOnInit', 'ngOnDestroy', 'ngDoCheck', 'ngAfterViewInit', 'ngAfterViewChecked',
|
||||||
|
'ngAfterContentInit', 'ngAfterContentChecked'
|
||||||
|
]);
|
||||||
|
|
||||||
export interface DirectiveHandlerData {
|
export interface DirectiveHandlerData {
|
||||||
meta: R3DirectiveMetadata;
|
meta: R3DirectiveMetadata;
|
||||||
metadataStmt: Statement|null;
|
metadataStmt: Statement|null;
|
||||||
}
|
}
|
||||||
export class DirectiveDecoratorHandler implements
|
export class DirectiveDecoratorHandler implements
|
||||||
DecoratorHandler<DirectiveHandlerData, Decorator> {
|
DecoratorHandler<DirectiveHandlerData, Decorator|null> {
|
||||||
constructor(
|
constructor(
|
||||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private metaRegistry: MetadataRegistry, private defaultImportRecorder: DefaultImportRecorder,
|
private metaRegistry: MetadataRegistry, private defaultImportRecorder: DefaultImportRecorder,
|
||||||
|
@ -36,27 +44,41 @@ export class DirectiveDecoratorHandler implements
|
||||||
|
|
||||||
readonly precedence = HandlerPrecedence.PRIMARY;
|
readonly precedence = HandlerPrecedence.PRIMARY;
|
||||||
|
|
||||||
detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<Decorator>|undefined {
|
detect(node: ClassDeclaration, decorators: Decorator[]|null):
|
||||||
if (!decorators) {
|
DetectResult<Decorator|null>|undefined {
|
||||||
|
// Compiling declaration files is invalid.
|
||||||
|
if (node.getSourceFile().isDeclarationFile) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const decorator = findAngularDecorator(decorators, 'Directive', this.isCore);
|
// If the class is undecorated, check if any of the fields have Angular decorators or lifecycle
|
||||||
if (decorator !== undefined) {
|
// hooks, and if they do, label the class as an abstract directive.
|
||||||
return {
|
if (!decorators) {
|
||||||
trigger: decorator.node,
|
const angularField = this.reflector.getMembersOfClass(node).find(member => {
|
||||||
metadata: decorator,
|
if (!member.isStatic && member.kind === ClassMemberKind.Method &&
|
||||||
};
|
LIFECYCLE_HOOKS.has(member.name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (member.decorators) {
|
||||||
|
return member.decorators.some(
|
||||||
|
decorator => FIELD_DECORATORS.some(
|
||||||
|
decoratorName => isAngularDecorator(decorator, decoratorName, this.isCore)));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return angularField ? {trigger: angularField.node, metadata: null} : undefined;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
const decorator = findAngularDecorator(decorators, 'Directive', this.isCore);
|
||||||
|
return decorator ? {trigger: decorator.node, metadata: decorator} : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
analyze(node: ClassDeclaration, decorator: Decorator, flags = HandlerFlags.NONE):
|
analyze(node: ClassDeclaration, decorator: Decorator|null, flags = HandlerFlags.NONE):
|
||||||
AnalysisOutput<DirectiveHandlerData> {
|
AnalysisOutput<DirectiveHandlerData> {
|
||||||
const directiveResult = extractDirectiveMetadata(
|
const directiveResult = extractDirectiveMetadata(
|
||||||
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
||||||
flags);
|
flags);
|
||||||
const analysis = directiveResult && directiveResult.metadata;
|
const analysis = directiveResult && directiveResult.metadata;
|
||||||
|
|
||||||
if (analysis === undefined) {
|
if (analysis === undefined) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -112,15 +134,14 @@ export class DirectiveDecoratorHandler implements
|
||||||
* the module.
|
* the module.
|
||||||
*/
|
*/
|
||||||
export function extractDirectiveMetadata(
|
export function extractDirectiveMetadata(
|
||||||
clazz: ClassDeclaration, decorator: Decorator, reflector: ReflectionHost,
|
clazz: ClassDeclaration, decorator: Decorator | null, reflector: ReflectionHost,
|
||||||
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||||
flags: HandlerFlags, defaultSelector: string | null = null): {
|
flags: HandlerFlags, defaultSelector: string | null = null): {
|
||||||
decorator: Map<string, ts.Expression>,
|
decorator: Map<string, ts.Expression>,
|
||||||
metadata: R3DirectiveMetadata,
|
metadata: R3DirectiveMetadata,
|
||||||
decoratedElements: ClassMember[],
|
|
||||||
}|undefined {
|
}|undefined {
|
||||||
let directive: Map<string, ts.Expression>;
|
let directive: Map<string, ts.Expression>;
|
||||||
if (decorator.args === null || decorator.args.length === 0) {
|
if (decorator === null || decorator.args === null || decorator.args.length === 0) {
|
||||||
directive = new Map<string, ts.Expression>();
|
directive = new Map<string, ts.Expression>();
|
||||||
} else if (decorator.args.length !== 1) {
|
} else if (decorator.args.length !== 1) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -256,7 +277,7 @@ export function extractDirectiveMetadata(
|
||||||
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
|
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
|
||||||
typeSourceSpan: EMPTY_SOURCE_SPAN, usesInheritance, exportAs, providers
|
typeSourceSpan: EMPTY_SOURCE_SPAN, usesInheritance, exportAs, providers
|
||||||
};
|
};
|
||||||
return {decoratedElements, decorator: directive, metadata};
|
return {decorator: directive, metadata};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractQueryMetadata(
|
export function extractQueryMetadata(
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {nocollapseHack} from '../transformers/nocollapse_hack';
|
||||||
import {verifySupportedTypeScriptVersion} from '../typescript_support';
|
import {verifySupportedTypeScriptVersion} from '../typescript_support';
|
||||||
|
|
||||||
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from './annotations';
|
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from './annotations';
|
||||||
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
|
||||||
import {CycleAnalyzer, ImportGraph} from './cycles';
|
import {CycleAnalyzer, ImportGraph} from './cycles';
|
||||||
import {ErrorCode, ngErrorCode} from './diagnostics';
|
import {ErrorCode, ngErrorCode} from './diagnostics';
|
||||||
import {FlatIndexGenerator, ReferenceGraph, checkForPrivateExports, findFlatIndexEntryPoint} from './entry_point';
|
import {FlatIndexGenerator, ReferenceGraph, checkForPrivateExports, findFlatIndexEntryPoint} from './entry_point';
|
||||||
|
@ -587,7 +586,6 @@ export class NgtscProgram implements api.Program {
|
||||||
|
|
||||||
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
||||||
const handlers = [
|
const handlers = [
|
||||||
new BaseDefDecoratorHandler(this.reflector, evaluator, this.isCore),
|
|
||||||
new ComponentDecoratorHandler(
|
new ComponentDecoratorHandler(
|
||||||
this.reflector, evaluator, metaRegistry, this.metaReader !, scopeReader, scopeRegistry,
|
this.reflector, evaluator, metaRegistry, this.metaReader !, scopeReader, scopeRegistry,
|
||||||
this.isCore, this.resourceManager, this.rootDirs,
|
this.isCore, this.resourceManager, this.rootDirs,
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
// Pattern matching all Render3 property names.
|
// Pattern matching all Render3 property names.
|
||||||
const R3_DEF_NAME_PATTERN = [
|
const R3_DEF_NAME_PATTERN = [
|
||||||
'ngBaseDef',
|
|
||||||
'ɵcmp',
|
'ɵcmp',
|
||||||
'ɵdir',
|
'ɵdir',
|
||||||
'ɵprov',
|
'ɵprov',
|
||||||
|
|
|
@ -2973,7 +2973,7 @@ describe('compiler compliance', () => {
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should add ngBaseDef if one or more @Input is present', () => {
|
it('should add an abstract directive if one or more @Input is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3002,7 +3002,9 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
inputs: {
|
inputs: {
|
||||||
input1: "input1",
|
input1: "input1",
|
||||||
input2: ["alias2", "input2"]
|
input2: ["alias2", "input2"]
|
||||||
|
@ -3014,7 +3016,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if one or more @Output is present', () => {
|
it('should add an abstract directive if one or more @Output is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3048,7 +3050,9 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
outputs: {
|
outputs: {
|
||||||
output1: "output1",
|
output1: "output1",
|
||||||
output2: "output2"
|
output2: "output2"
|
||||||
|
@ -3060,10 +3064,11 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a mixture of @Input and @Output props are present', () => {
|
it('should add an abstract directive if a mixture of @Input and @Output props are present',
|
||||||
const files = {
|
() => {
|
||||||
app: {
|
const files = {
|
||||||
'spec.ts': `
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
import {Component, NgModule, Input, Output, EventEmitter} from '@angular/core';
|
import {Component, NgModule, Input, Output, EventEmitter} from '@angular/core';
|
||||||
export class BaseClass {
|
export class BaseClass {
|
||||||
@Output()
|
@Output()
|
||||||
|
@ -3096,11 +3101,13 @@ describe('compiler compliance', () => {
|
||||||
})
|
})
|
||||||
export class MyModule {}
|
export class MyModule {}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
inputs: {
|
inputs: {
|
||||||
input1: "input1",
|
input1: "input1",
|
||||||
input2: ["whatever", "input2"]
|
input2: ["whatever", "input2"]
|
||||||
|
@ -3112,11 +3119,11 @@ describe('compiler compliance', () => {
|
||||||
});
|
});
|
||||||
// ...
|
// ...
|
||||||
`;
|
`;
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a ViewChild query is present', () => {
|
it('should add an abstract directive if a ViewChild query is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3142,8 +3149,10 @@ describe('compiler compliance', () => {
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
const $e0_attrs$ = ["something"];
|
const $e0_attrs$ = ["something"];
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
viewQuery: function (rf, ctx) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
viewQuery: function BaseClass_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery($e0_attrs$, true);
|
$r3$.ɵɵviewQuery($e0_attrs$, true);
|
||||||
}
|
}
|
||||||
|
@ -3159,7 +3168,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a ViewChildren query is present', () => {
|
it('should add an abstract directive if a ViewChildren query is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
...directive,
|
...directive,
|
||||||
|
@ -3187,8 +3196,10 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
viewQuery: function (rf, ctx) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
viewQuery: function BaseClass_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true);
|
$r3$.ɵɵviewQuery(SomeDirective, true);
|
||||||
}
|
}
|
||||||
|
@ -3204,7 +3215,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a ContentChild query is present', () => {
|
it('should add an abstract directive if a ContentChild query is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3230,8 +3241,10 @@ describe('compiler compliance', () => {
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
const $e0_attrs$ = ["something"];
|
const $e0_attrs$ = ["something"];
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
contentQueries: function (rf, ctx, dirIndex) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
contentQueries: function BaseClass_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true);
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true);
|
||||||
}
|
}
|
||||||
|
@ -3247,7 +3260,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a ContentChildren query is present', () => {
|
it('should add an abstract directive if a ContentChildren query is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
...directive,
|
...directive,
|
||||||
|
@ -3275,8 +3288,10 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = i0.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
contentQueries: function (rf, ctx, dirIndex) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
contentQueries: function BaseClass_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false);
|
||||||
}
|
}
|
||||||
|
@ -3292,7 +3307,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a host binding is present', () => {
|
it('should add an abstract directive if a host binding is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3318,8 +3333,10 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = $r3$.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
hostBindings: function (rf, ctx, elIndex) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
hostBindings: function BaseClass_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵallocHostVars(1);
|
$r3$.ɵɵallocHostVars(1);
|
||||||
}
|
}
|
||||||
|
@ -3334,7 +3351,7 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef if a host listener is present', () => {
|
it('should add an abstract directive if a host listener is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3360,10 +3377,12 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
// ...
|
// ...
|
||||||
BaseClass.ngBaseDef = $r3$.ɵɵdefineBase({
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
hostBindings: function (rf, ctx, elIndex) {
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
hostBindings: function BaseClass_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵlistener("mousedown", function ($event) {
|
$r3$.ɵɵlistener("mousedown", function BaseClass_mousedown_HostBindingHandler($event) {
|
||||||
return ctx.handleMousedown($event);
|
return ctx.handleMousedown($event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3375,7 +3394,79 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT add ngBaseDef if @Component is present', () => {
|
it('should add an abstract directive when using any lifecycle hook', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, NgModule, Input} from '@angular/core';
|
||||||
|
export class BaseClass {
|
||||||
|
ngAfterContentChecked() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: \`<div>{{input1}} {{input2}}</div>\`
|
||||||
|
})
|
||||||
|
export class MyComponent extends BaseClass {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [MyComponent]
|
||||||
|
})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const expectedOutput = `
|
||||||
|
// ...
|
||||||
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
|
type: BaseClass,
|
||||||
|
selectors: []
|
||||||
|
});
|
||||||
|
// ...
|
||||||
|
`;
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should add an abstract directive when using ngOnChanges', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, NgModule, Input} from '@angular/core';
|
||||||
|
export class BaseClass {
|
||||||
|
ngOnChanges() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: \`<div>{{input1}} {{input2}}</div>\`
|
||||||
|
})
|
||||||
|
export class MyComponent extends BaseClass {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [MyComponent]
|
||||||
|
})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const expectedOutput = `
|
||||||
|
// ...
|
||||||
|
BaseClass.ɵdir = $r3$.ɵɵdefineDirective({
|
||||||
|
type: BaseClass,
|
||||||
|
selectors: [],
|
||||||
|
features: [$r3$.ɵɵNgOnChangesFeature()]
|
||||||
|
});
|
||||||
|
// ...
|
||||||
|
`;
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
expectEmit(result.source, expectedOutput, 'Invalid base definition');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT add an abstract directive if @Component is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3411,10 +3502,10 @@ describe('compiler compliance', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
expect(result.source).not.toContain('ngBaseDef');
|
expect(result.source).not.toContain('ɵdir');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT add ngBaseDef if @Directive is present', () => {
|
it('should NOT add an abstract directive if @Directive is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
@ -3449,7 +3540,7 @@ describe('compiler compliance', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
expect(result.source).not.toContain('ngBaseDef');
|
expect(result.source.match(/ɵdir/g) !.length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('compiler compliance: listen()', () => {
|
||||||
compileAnimations: false,
|
compileAnimations: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create declare inputs/outputs', () => {
|
it('should declare inputs/outputs', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
|
|
|
@ -416,7 +416,7 @@ runInEachFileSystem(os => {
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
|
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain('TestBase.ngBaseDef = i0.ɵɵdefineBase');
|
expect(jsContents).toContain('TestBase.ɵdir = i0.ɵɵdefineDirective');
|
||||||
expect(jsContents).toContain('TestComponent.ɵcmp = i0.ɵɵdefineComponent');
|
expect(jsContents).toContain('TestComponent.ɵcmp = i0.ɵɵdefineComponent');
|
||||||
expect(jsContents).toContain('TestDirective.ɵdir = i0.ɵɵdefineDirective');
|
expect(jsContents).toContain('TestDirective.ɵdir = i0.ɵɵdefineDirective');
|
||||||
expect(jsContents).toContain('TestPipe.ɵpipe = i0.ɵɵdefinePipe');
|
expect(jsContents).toContain('TestPipe.ɵpipe = i0.ɵɵdefinePipe');
|
||||||
|
@ -503,7 +503,7 @@ runInEachFileSystem(os => {
|
||||||
expect(jsContents).toContain('background-color: blue');
|
expect(jsContents).toContain('background-color: blue');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include generic type for ngBaseDef declarations', () => {
|
it('should include generic type for undecorated class declarations', () => {
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
import {Component, Input, NgModule} from '@angular/core';
|
import {Component, Input, NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@ -515,10 +515,14 @@ runInEachFileSystem(os => {
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
|
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain('i0.ɵɵdefineBase({ inputs: { input: "input" } });');
|
expect(jsContents)
|
||||||
|
.toContain(
|
||||||
|
'i0.ɵɵdefineDirective({ type: TestBase, selectors: [], inputs: { input: "input" } });');
|
||||||
|
|
||||||
const dtsContents = env.getContents('test.d.ts');
|
const dtsContents = env.getContents('test.d.ts');
|
||||||
expect(dtsContents).toContain('static ngBaseDef: i0.ɵɵBaseDef<TestBase>');
|
expect(dtsContents)
|
||||||
|
.toContain(
|
||||||
|
`static ɵdir: i0.ɵɵDirectiveDefWithMeta<TestBase, never, never, { 'input': "input" }, {}, never>;`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compile NgModules without errors', () => {
|
it('should compile NgModules without errors', () => {
|
||||||
|
@ -1104,7 +1108,7 @@ runInEachFileSystem(os => {
|
||||||
}));
|
}));
|
||||||
env.write('index.ts', `
|
env.write('index.ts', `
|
||||||
import {Directive} from '@angular/core';
|
import {Directive} from '@angular/core';
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class BaseClass {}
|
export class BaseClass {}
|
||||||
`);
|
`);
|
||||||
|
@ -1115,10 +1119,10 @@ runInEachFileSystem(os => {
|
||||||
env.write('index.ts', `
|
env.write('index.ts', `
|
||||||
import {NgModule, Directive} from '@angular/core';
|
import {NgModule, Directive} from '@angular/core';
|
||||||
import {BaseClass} from 'lib1_built';
|
import {BaseClass} from 'lib1_built';
|
||||||
|
|
||||||
@Directive({selector: 'my-dir'})
|
@Directive({selector: 'my-dir'})
|
||||||
export class MyDirective extends BaseClass {}
|
export class MyDirective extends BaseClass {}
|
||||||
|
|
||||||
@NgModule({declarations: [MyDirective]})
|
@NgModule({declarations: [MyDirective]})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
`);
|
`);
|
||||||
|
@ -2615,7 +2619,7 @@ runInEachFileSystem(os => {
|
||||||
|
|
||||||
env.write('test.ts', `/** I am a top-level comment. */
|
env.write('test.ts', `/** I am a top-level comment. */
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class TestModule {}
|
export class TestModule {}
|
||||||
`);
|
`);
|
||||||
|
@ -2634,7 +2638,7 @@ runInEachFileSystem(os => {
|
||||||
|
|
||||||
env.write('my-module.ts', `
|
env.write('my-module.ts', `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class MyModule {}
|
export class MyModule {}
|
||||||
`);
|
`);
|
||||||
|
@ -2647,7 +2651,7 @@ runInEachFileSystem(os => {
|
||||||
|
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class TestModule {}
|
export class TestModule {}
|
||||||
`);
|
`);
|
||||||
|
@ -2673,9 +2677,9 @@ runInEachFileSystem(os => {
|
||||||
it('should generate a summary stub for decorated classes in the input file only', () => {
|
it('should generate a summary stub for decorated classes in the input file only', () => {
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
import {Injectable, NgModule} from '@angular/core';
|
import {Injectable, NgModule} from '@angular/core';
|
||||||
|
|
||||||
export class NotAModule {}
|
export class NotAModule {}
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class TestModule {}
|
export class TestModule {}
|
||||||
`);
|
`);
|
||||||
|
@ -2689,10 +2693,10 @@ runInEachFileSystem(os => {
|
||||||
it('should generate a summary stub for classes exported via exports', () => {
|
it('should generate a summary stub for classes exported via exports', () => {
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
import {Injectable, NgModule} from '@angular/core';
|
import {Injectable, NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
class NotDirectlyExported {}
|
class NotDirectlyExported {}
|
||||||
|
|
||||||
export {NotDirectlyExported};
|
export {NotDirectlyExported};
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@ -3597,7 +3601,7 @@ runInEachFileSystem(os => {
|
||||||
it('should not re-export a directive that\'s not exported from the NgModule', () => {
|
it('should not re-export a directive that\'s not exported from the NgModule', () => {
|
||||||
env.write('dir.ts', `
|
env.write('dir.ts', `
|
||||||
import {Directive} from '@angular/core';
|
import {Directive} from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'dir',
|
selector: 'dir',
|
||||||
})
|
})
|
||||||
|
@ -3606,7 +3610,7 @@ runInEachFileSystem(os => {
|
||||||
env.write('module.ts', `
|
env.write('module.ts', `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {Dir} from './dir';
|
import {Dir} from './dir';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [Dir],
|
declarations: [Dir],
|
||||||
exports: [],
|
exports: [],
|
||||||
|
@ -3655,11 +3659,11 @@ runInEachFileSystem(os => {
|
||||||
it('should not re-export a directive from an exported, external NgModule', () => {
|
it('should not re-export a directive from an exported, external NgModule', () => {
|
||||||
env.write(`node_modules/external/index.d.ts`, `
|
env.write(`node_modules/external/index.d.ts`, `
|
||||||
import {ɵɵDirectiveDefWithMeta, ɵɵNgModuleDefWithMeta} from '@angular/core';
|
import {ɵɵDirectiveDefWithMeta, ɵɵNgModuleDefWithMeta} from '@angular/core';
|
||||||
|
|
||||||
export declare class ExternalDir {
|
export declare class ExternalDir {
|
||||||
static ɵdir: ɵɵDirectiveDefWithMeta<ExternalDir, '[test]', never, never, never, never>;
|
static ɵdir: ɵɵDirectiveDefWithMeta<ExternalDir, '[test]', never, never, never, never>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class ExternalModule {
|
export declare class ExternalModule {
|
||||||
static ɵmod: ɵɵNgModuleDefWithMeta<ExternalModule, [typeof ExternalDir], never, [typeof ExternalDir]>;
|
static ɵmod: ɵɵNgModuleDefWithMeta<ExternalModule, [typeof ExternalDir], never, [typeof ExternalDir]>;
|
||||||
}
|
}
|
||||||
|
@ -3719,7 +3723,7 @@ runInEachFileSystem(os => {
|
||||||
() => {
|
() => {
|
||||||
env.write('dir.ts', `
|
env.write('dir.ts', `
|
||||||
import {Directive} from '@angular/core';
|
import {Directive} from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'dir',
|
selector: 'dir',
|
||||||
})
|
})
|
||||||
|
@ -3727,7 +3731,7 @@ runInEachFileSystem(os => {
|
||||||
`);
|
`);
|
||||||
env.write('dir2.ts', `
|
env.write('dir2.ts', `
|
||||||
import {Directive} from '@angular/core';
|
import {Directive} from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'dir',
|
selector: 'dir',
|
||||||
})
|
})
|
||||||
|
@ -3737,7 +3741,7 @@ runInEachFileSystem(os => {
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {Dir} from './dir';
|
import {Dir} from './dir';
|
||||||
import {Dir as Dir2} from './dir2';
|
import {Dir as Dir2} from './dir2';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [Dir, Dir2],
|
declarations: [Dir, Dir2],
|
||||||
exports: [Dir, Dir2],
|
exports: [Dir, Dir2],
|
||||||
|
@ -3755,7 +3759,7 @@ runInEachFileSystem(os => {
|
||||||
it('should choose a re-exported symbol if one is present', () => {
|
it('should choose a re-exported symbol if one is present', () => {
|
||||||
env.write(`node_modules/external/dir.d.ts`, `
|
env.write(`node_modules/external/dir.d.ts`, `
|
||||||
import {ɵɵDirectiveDefWithMeta} from '@angular/core';
|
import {ɵɵDirectiveDefWithMeta} from '@angular/core';
|
||||||
|
|
||||||
export declare class ExternalDir {
|
export declare class ExternalDir {
|
||||||
static ɵdir: ɵɵDirectiveDefWithMeta<ExternalDir, '[test]', never, never, never, never>;
|
static ɵdir: ɵɵDirectiveDefWithMeta<ExternalDir, '[test]', never, never, never, never>;
|
||||||
}
|
}
|
||||||
|
@ -3763,23 +3767,23 @@ runInEachFileSystem(os => {
|
||||||
env.write('node_modules/external/module.d.ts', `
|
env.write('node_modules/external/module.d.ts', `
|
||||||
import {ɵɵNgModuleDefWithMeta} from '@angular/core';
|
import {ɵɵNgModuleDefWithMeta} from '@angular/core';
|
||||||
import {ExternalDir} from './dir';
|
import {ExternalDir} from './dir';
|
||||||
|
|
||||||
export declare class ExternalModule {
|
export declare class ExternalModule {
|
||||||
static ɵmod: ɵɵNgModuleDefWithMeta<ExternalModule, [typeof ExternalDir], never, [typeof ExternalDir]>;
|
static ɵmod: ɵɵNgModuleDefWithMeta<ExternalModule, [typeof ExternalDir], never, [typeof ExternalDir]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {ExternalDir as ɵngExportɵExternalModuleɵExternalDir};
|
export {ExternalDir as ɵngExportɵExternalModuleɵExternalDir};
|
||||||
`);
|
`);
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
import {Component, Directive, NgModule} from '@angular/core';
|
import {Component, Directive, NgModule} from '@angular/core';
|
||||||
import {ExternalModule} from 'external/module';
|
import {ExternalModule} from 'external/module';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'test-cmp',
|
selector: 'test-cmp',
|
||||||
template: '<div test></div>',
|
template: '<div test></div>',
|
||||||
})
|
})
|
||||||
class Cmp {}
|
class Cmp {}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [Cmp],
|
declarations: [Cmp],
|
||||||
imports: [ExternalModule],
|
imports: [ExternalModule],
|
||||||
|
|
|
@ -101,7 +101,7 @@ export {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata
|
||||||
export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler';
|
export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler';
|
||||||
export {makeBindingParser, parseTemplate, ParseTemplateOptions} from './render3/view/template';
|
export {makeBindingParser, parseTemplate, ParseTemplateOptions} from './render3/view/template';
|
||||||
export {R3Reference} from './render3/util';
|
export {R3Reference} from './render3/util';
|
||||||
export {compileBaseDefFromMetadata, R3BaseRefMetaData, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, ParsedHostBindings, verifyHostBindings} from './render3/view/compiler';
|
export {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, ParsedHostBindings, verifyHostBindings} from './render3/view/compiler';
|
||||||
export {publishFacade} from './jit_compiler_facade';
|
export {publishFacade} from './jit_compiler_facade';
|
||||||
// This file only reexports content of the `src` folder. Keep it that way.
|
// This file only reexports content of the `src` folder. Keep it that way.
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ export interface CompilerFacade {
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
|
||||||
compileComponent(
|
compileComponent(
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
|
||||||
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade):
|
|
||||||
any;
|
|
||||||
compileFactory(
|
compileFactory(
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade): any;
|
||||||
|
|
||||||
|
@ -160,16 +158,6 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
|
||||||
changeDetection?: ChangeDetectionStrategy;
|
changeDetection?: ChangeDetectionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface R3BaseMetadataFacade {
|
|
||||||
name: string;
|
|
||||||
type: any;
|
|
||||||
propMetadata: {[key: string]: any[]};
|
|
||||||
inputs?: {[key: string]: string | [string, string]};
|
|
||||||
outputs?: {[key: string]: string};
|
|
||||||
queries?: R3QueryMetadataFacade[];
|
|
||||||
viewQueries?: R3QueryMetadataFacade[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface R3FactoryDefMetadataFacade {
|
export interface R3FactoryDefMetadataFacade {
|
||||||
name: string;
|
name: string;
|
||||||
type: any;
|
type: any;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3BaseMetadataFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3FactoryDefMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
|
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3FactoryDefMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
|
||||||
import {ConstantPool} from './constant_pool';
|
import {ConstantPool} from './constant_pool';
|
||||||
import {HostBinding, HostListener, Input, Output, Type} from './core';
|
import {HostBinding, HostListener, Input, Output, Type} from './core';
|
||||||
import {Identifiers} from './identifiers';
|
import {Identifiers} from './identifiers';
|
||||||
|
@ -22,7 +22,7 @@ import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule
|
||||||
import {compilePipeFromMetadata} from './render3/r3_pipe_compiler';
|
import {compilePipeFromMetadata} from './render3/r3_pipe_compiler';
|
||||||
import {R3Reference} from './render3/util';
|
import {R3Reference} from './render3/util';
|
||||||
import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api';
|
import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api';
|
||||||
import {ParsedHostBindings, compileBaseDefFromMetadata, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
|
import {ParsedHostBindings, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
|
||||||
import {makeBindingParser, parseTemplate} from './render3/view/template';
|
import {makeBindingParser, parseTemplate} from './render3/view/template';
|
||||||
import {ResourceLoader} from './resource_loader';
|
import {ResourceLoader} from './resource_loader';
|
||||||
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
||||||
|
@ -169,24 +169,6 @@ export class CompilerFacadeImpl implements CompilerFacade {
|
||||||
factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements);
|
factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3BaseMetadataFacade):
|
|
||||||
any {
|
|
||||||
const constantPool = new ConstantPool();
|
|
||||||
const typeSourceSpan =
|
|
||||||
this.createParseSourceSpan('Base', facade.name, `ng:///${facade.name}.js`);
|
|
||||||
const meta = {
|
|
||||||
...facade,
|
|
||||||
typeSourceSpan,
|
|
||||||
viewQueries: facade.viewQueries ? facade.viewQueries.map(convertToR3QueryMetadata) :
|
|
||||||
facade.viewQueries,
|
|
||||||
queries: facade.queries ? facade.queries.map(convertToR3QueryMetadata) : facade.queries,
|
|
||||||
host: extractHostBindings(facade.propMetadata, typeSourceSpan)
|
|
||||||
};
|
|
||||||
const res = compileBaseDefFromMetadata(meta, constantPool, makeBindingParser());
|
|
||||||
return this.jitExpression(
|
|
||||||
res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
|
|
||||||
}
|
|
||||||
|
|
||||||
createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan {
|
createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan {
|
||||||
return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
|
return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,13 +220,6 @@ export class Identifiers {
|
||||||
static resolveDocument: o.ExternalReference = {name: 'ɵɵresolveDocument', moduleName: CORE};
|
static resolveDocument: o.ExternalReference = {name: 'ɵɵresolveDocument', moduleName: CORE};
|
||||||
static resolveBody: o.ExternalReference = {name: 'ɵɵresolveBody', moduleName: CORE};
|
static resolveBody: o.ExternalReference = {name: 'ɵɵresolveBody', moduleName: CORE};
|
||||||
|
|
||||||
static defineBase: o.ExternalReference = {name: 'ɵɵdefineBase', moduleName: CORE};
|
|
||||||
|
|
||||||
static BaseDef: o.ExternalReference = {
|
|
||||||
name: 'ɵɵBaseDef',
|
|
||||||
moduleName: CORE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defineComponent: o.ExternalReference = {name: 'ɵɵdefineComponent', moduleName: CORE};
|
static defineComponent: o.ExternalReference = {name: 'ɵɵdefineComponent', moduleName: CORE};
|
||||||
|
|
||||||
static setComponentScope: o.ExternalReference = {name: 'ɵɵsetComponentScope', moduleName: CORE};
|
static setComponentScope: o.ExternalReference = {name: 'ɵɵsetComponentScope', moduleName: CORE};
|
||||||
|
|
|
@ -129,61 +129,6 @@ export function compileDirectiveFromMetadata(
|
||||||
return {expression, type};
|
return {expression, type};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface R3BaseRefMetaData {
|
|
||||||
name: string;
|
|
||||||
type: o.Expression;
|
|
||||||
typeSourceSpan: ParseSourceSpan;
|
|
||||||
inputs?: {[key: string]: string | [string, string]};
|
|
||||||
outputs?: {[key: string]: string};
|
|
||||||
viewQueries?: R3QueryMetadata[];
|
|
||||||
queries?: R3QueryMetadata[];
|
|
||||||
host?: R3HostMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile a base definition for the render3 runtime as defined by {@link R3BaseRefMetadata}
|
|
||||||
* @param meta the metadata used for compilation.
|
|
||||||
*/
|
|
||||||
export function compileBaseDefFromMetadata(
|
|
||||||
meta: R3BaseRefMetaData, constantPool: ConstantPool, bindingParser: BindingParser) {
|
|
||||||
const definitionMap = new DefinitionMap();
|
|
||||||
if (meta.inputs) {
|
|
||||||
const inputs = meta.inputs;
|
|
||||||
const inputsMap = Object.keys(inputs).map(key => {
|
|
||||||
const v = inputs[key];
|
|
||||||
const value = Array.isArray(v) ? o.literalArr(v.map(vx => o.literal(vx))) : o.literal(v);
|
|
||||||
return {key, value, quoted: false};
|
|
||||||
});
|
|
||||||
definitionMap.set('inputs', o.literalMap(inputsMap));
|
|
||||||
}
|
|
||||||
if (meta.outputs) {
|
|
||||||
const outputs = meta.outputs;
|
|
||||||
const outputsMap = Object.keys(outputs).map(key => {
|
|
||||||
const value = o.literal(outputs[key]);
|
|
||||||
return {key, value, quoted: false};
|
|
||||||
});
|
|
||||||
definitionMap.set('outputs', o.literalMap(outputsMap));
|
|
||||||
}
|
|
||||||
if (meta.viewQueries && meta.viewQueries.length > 0) {
|
|
||||||
definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool));
|
|
||||||
}
|
|
||||||
if (meta.queries && meta.queries.length > 0) {
|
|
||||||
definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool));
|
|
||||||
}
|
|
||||||
if (meta.host) {
|
|
||||||
definitionMap.set(
|
|
||||||
'hostBindings',
|
|
||||||
createHostBindingsFunction(
|
|
||||||
meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
const expression = o.importExpr(R3.defineBase).callFn([definitionMap.toLiteralMap()]);
|
|
||||||
const type = new o.ExpressionType(
|
|
||||||
o.importExpr(R3.BaseDef), /* modifiers */ null, [o.expressionType(meta.type)]);
|
|
||||||
|
|
||||||
return {expression, type};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
|
* Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -103,10 +103,6 @@ const coreR3ComponentMetadataFacade: core.R3ComponentMetadataFacade =
|
||||||
const compilerR3ComponentMetadataFacade: compiler.R3ComponentMetadataFacade =
|
const compilerR3ComponentMetadataFacade: compiler.R3ComponentMetadataFacade =
|
||||||
null !as core.R3ComponentMetadataFacade;
|
null !as core.R3ComponentMetadataFacade;
|
||||||
|
|
||||||
const coreR3BaseMetadataFacade: core.R3BaseMetadataFacade = null !as compiler.R3BaseMetadataFacade;
|
|
||||||
const compilerR3BaseMetadataFacade: compiler.R3BaseMetadataFacade =
|
|
||||||
null !as core.R3BaseMetadataFacade;
|
|
||||||
|
|
||||||
const coreViewEncapsulation: core.ViewEncapsulation = null !as compiler.ViewEncapsulation;
|
const coreViewEncapsulation: core.ViewEncapsulation = null !as compiler.ViewEncapsulation;
|
||||||
const compilerViewEncapsulation: compiler.ViewEncapsulation = null !as core.ViewEncapsulation;
|
const compilerViewEncapsulation: compiler.ViewEncapsulation = null !as core.ViewEncapsulation;
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ export interface CompilerFacade {
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
|
||||||
compileComponent(
|
compileComponent(
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
|
||||||
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade):
|
|
||||||
any;
|
|
||||||
compileFactory(
|
compileFactory(
|
||||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade): any;
|
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade): any;
|
||||||
|
|
||||||
|
@ -160,16 +158,6 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
|
||||||
changeDetection?: ChangeDetectionStrategy;
|
changeDetection?: ChangeDetectionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface R3BaseMetadataFacade {
|
|
||||||
name: string;
|
|
||||||
type: any;
|
|
||||||
propMetadata: {[key: string]: any[]};
|
|
||||||
inputs?: {[key: string]: string | [string, string]};
|
|
||||||
outputs?: {[key: string]: string};
|
|
||||||
queries?: R3QueryMetadataFacade[];
|
|
||||||
viewQueries?: R3QueryMetadataFacade[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface R3FactoryDefMetadataFacade {
|
export interface R3FactoryDefMetadataFacade {
|
||||||
name: string;
|
name: string;
|
||||||
type: any;
|
type: any;
|
||||||
|
|
|
@ -18,7 +18,6 @@ export {
|
||||||
ɵɵattributeInterpolate7,
|
ɵɵattributeInterpolate7,
|
||||||
ɵɵattributeInterpolate8,
|
ɵɵattributeInterpolate8,
|
||||||
ɵɵattributeInterpolateV,
|
ɵɵattributeInterpolateV,
|
||||||
ɵɵdefineBase,
|
|
||||||
ɵɵdefineComponent,
|
ɵɵdefineComponent,
|
||||||
ɵɵdefineDirective,
|
ɵɵdefineDirective,
|
||||||
ɵɵdefinePipe,
|
ɵɵdefinePipe,
|
||||||
|
@ -153,7 +152,6 @@ export {
|
||||||
ɵɵembeddedViewEnd,
|
ɵɵembeddedViewEnd,
|
||||||
store as ɵstore,
|
store as ɵstore,
|
||||||
ɵɵpipe,
|
ɵɵpipe,
|
||||||
ɵɵBaseDef,
|
|
||||||
ComponentDef as ɵComponentDef,
|
ComponentDef as ɵComponentDef,
|
||||||
ɵɵComponentDefWithMeta,
|
ɵɵComponentDefWithMeta,
|
||||||
ɵɵFactoryDef,
|
ɵɵFactoryDef,
|
||||||
|
@ -227,7 +225,6 @@ export {
|
||||||
NG_DIR_DEF as ɵNG_DIR_DEF,
|
NG_DIR_DEF as ɵNG_DIR_DEF,
|
||||||
NG_PIPE_DEF as ɵNG_PIPE_DEF,
|
NG_PIPE_DEF as ɵNG_PIPE_DEF,
|
||||||
NG_MOD_DEF as ɵNG_MOD_DEF,
|
NG_MOD_DEF as ɵNG_MOD_DEF,
|
||||||
NG_BASE_DEF as ɵNG_BASE_DEF
|
|
||||||
} from './render3/fields';
|
} from './render3/fields';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -16,8 +16,8 @@ import {initNgDevMode} from '../util/ng_dev_mode';
|
||||||
import {stringify} from '../util/stringify';
|
import {stringify} from '../util/stringify';
|
||||||
|
|
||||||
import {EMPTY_ARRAY, EMPTY_OBJ} from './empty';
|
import {EMPTY_ARRAY, EMPTY_OBJ} from './empty';
|
||||||
import {NG_BASE_DEF, NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF, NG_LOC_ID_DEF, NG_MOD_DEF, NG_PIPE_DEF} from './fields';
|
import {NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF, NG_LOC_ID_DEF, NG_MOD_DEF, NG_PIPE_DEF} from './fields';
|
||||||
import {ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveType, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction, ɵɵBaseDef} from './interfaces/definition';
|
import {ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction} from './interfaces/definition';
|
||||||
import {TAttributes} from './interfaces/node';
|
import {TAttributes} from './interfaces/node';
|
||||||
// while SelectorFlags is unused here, it's required so that types don't get resolved lazily
|
// while SelectorFlags is unused here, it's required so that types don't get resolved lazily
|
||||||
// see: https://github.com/Microsoft/web-build-tools/issues/1050
|
// see: https://github.com/Microsoft/web-build-tools/issues/1050
|
||||||
|
@ -484,107 +484,6 @@ function invertObject<T>(
|
||||||
return newLookup;
|
return newLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a base definition
|
|
||||||
*
|
|
||||||
* # Example
|
|
||||||
* ```ts
|
|
||||||
* class ShouldBeInherited {
|
|
||||||
* static ngBaseDef = ɵɵdefineBase({
|
|
||||||
* ...
|
|
||||||
* })
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param baseDefinition The base definition parameters
|
|
||||||
*
|
|
||||||
* @codeGenApi
|
|
||||||
*/
|
|
||||||
export function ɵɵdefineBase<T>(baseDefinition: {
|
|
||||||
/**
|
|
||||||
* A map of input names.
|
|
||||||
*
|
|
||||||
* The format is in: `{[actualPropertyName: string]:(string|[string, string])}`.
|
|
||||||
*
|
|
||||||
* Given:
|
|
||||||
* ```
|
|
||||||
* class MyComponent {
|
|
||||||
* @Input()
|
|
||||||
* publicInput1: string;
|
|
||||||
*
|
|
||||||
* @Input('publicInput2')
|
|
||||||
* declaredInput2: string;
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* is described as:
|
|
||||||
* ```
|
|
||||||
* {
|
|
||||||
* publicInput1: 'publicInput1',
|
|
||||||
* declaredInput2: ['declaredInput2', 'publicInput2'],
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Which the minifier may translate to:
|
|
||||||
* ```
|
|
||||||
* {
|
|
||||||
* minifiedPublicInput1: 'publicInput1',
|
|
||||||
* minifiedDeclaredInput2: [ 'declaredInput2', 'publicInput2'],
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* This allows the render to re-construct the minified, public, and declared names
|
|
||||||
* of properties.
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* - Because declared and public name are usually same we only generate the array
|
|
||||||
* `['declared', 'public']` format when they differ.
|
|
||||||
* - The reason why this API and `outputs` API is not the same is that `NgOnChanges` has
|
|
||||||
* inconsistent behavior in that it uses declared names rather than minified or public. For
|
|
||||||
* this reason `NgOnChanges` will be deprecated and removed in future version and this
|
|
||||||
* API will be simplified to be consistent with `outputs`.
|
|
||||||
*/
|
|
||||||
inputs?: {[P in keyof T]?: string | [string, string]};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of output names.
|
|
||||||
*
|
|
||||||
* The format is in: `{[actualPropertyName: string]:string}`.
|
|
||||||
*
|
|
||||||
* Which the minifier may translate to: `{[minifiedPropertyName: string]:string}`.
|
|
||||||
*
|
|
||||||
* This allows the render to re-construct the minified and non-minified names
|
|
||||||
* of properties.
|
|
||||||
*/
|
|
||||||
outputs?: {[P in keyof T]?: string};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to create instances of content queries associated with a given directive.
|
|
||||||
*/
|
|
||||||
contentQueries?: ContentQueriesFunction<T>| null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional set of instructions specific to view query processing. This could be seen as a
|
|
||||||
* set of instructions to be inserted into the template function.
|
|
||||||
*/
|
|
||||||
viewQuery?: ViewQueriesFunction<T>| null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function executed by the parent template to allow children to apply host bindings.
|
|
||||||
*/
|
|
||||||
hostBindings?: HostBindingsFunction<T>;
|
|
||||||
}): ɵɵBaseDef<T> {
|
|
||||||
const declaredInputs: {[P in keyof T]: string} = {} as any;
|
|
||||||
return {
|
|
||||||
inputs: invertObject<T>(baseDefinition.inputs as any, declaredInputs),
|
|
||||||
declaredInputs: declaredInputs,
|
|
||||||
outputs: invertObject<T>(baseDefinition.outputs as any),
|
|
||||||
viewQuery: baseDefinition.viewQuery || null,
|
|
||||||
contentQueries: baseDefinition.contentQueries || null,
|
|
||||||
hostBindings: baseDefinition.hostBindings || null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a directive definition object.
|
* Create a directive definition object.
|
||||||
*
|
*
|
||||||
|
@ -751,10 +650,6 @@ export function getPipeDef<T>(type: any): PipeDef<T>|null {
|
||||||
return type[NG_PIPE_DEF] || null;
|
return type[NG_PIPE_DEF] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBaseDef<T>(type: any): ɵɵBaseDef<T>|null {
|
|
||||||
return type[NG_BASE_DEF] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFactoryDef<T>(type: any, throwNotFound: true): FactoryFn<T>;
|
export function getFactoryDef<T>(type: any, throwNotFound: true): FactoryFn<T>;
|
||||||
export function getFactoryDef<T>(type: any): FactoryFn<T>|null;
|
export function getFactoryDef<T>(type: any): FactoryFn<T>|null;
|
||||||
export function getFactoryDef<T>(type: any, throwNotFound?: boolean): FactoryFn<T>|null {
|
export function getFactoryDef<T>(type: any, throwNotFound?: boolean): FactoryFn<T>|null {
|
||||||
|
|
|
@ -12,8 +12,6 @@ import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
||||||
import {ComponentDef, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, HostBindingsFunction, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
|
import {ComponentDef, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, HostBindingsFunction, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
|
||||||
import {isComponentDef} from '../interfaces/type_checks';
|
import {isComponentDef} from '../interfaces/type_checks';
|
||||||
|
|
||||||
import {ɵɵNgOnChangesFeature} from './ng_onchanges_feature';
|
|
||||||
|
|
||||||
export function getSuperType(type: Type<any>): Type<any>&
|
export function getSuperType(type: Type<any>): Type<any>&
|
||||||
{ɵcmp?: ComponentDef<any>, ɵdir?: DirectiveDef<any>} {
|
{ɵcmp?: ComponentDef<any>, ɵdir?: DirectiveDef<any>} {
|
||||||
return Object.getPrototypeOf(type.prototype).constructor;
|
return Object.getPrototypeOf(type.prototype).constructor;
|
||||||
|
@ -41,30 +39,14 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef<any>| Comp
|
||||||
superDef = superType.ɵdir;
|
superDef = superType.ɵdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseDef = (superType as any).ngBaseDef;
|
if (superDef) {
|
||||||
|
// Some fields in the definition may be empty, if there were no values to put in them that
|
||||||
// Some fields in the definition may be empty, if there were no values to put in them that
|
// would've justified object creation. Unwrap them if necessary.
|
||||||
// would've justified object creation. Unwrap them if necessary.
|
|
||||||
if (baseDef || superDef) {
|
|
||||||
const writeableDef = definition as any;
|
const writeableDef = definition as any;
|
||||||
writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
|
writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
|
||||||
writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
|
writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
|
||||||
writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
|
writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
|
||||||
}
|
|
||||||
|
|
||||||
if (baseDef) {
|
|
||||||
const baseViewQuery = baseDef.viewQuery;
|
|
||||||
const baseContentQueries = baseDef.contentQueries;
|
|
||||||
const baseHostBindings = baseDef.hostBindings;
|
|
||||||
baseHostBindings && inheritHostBindings(definition, baseHostBindings);
|
|
||||||
baseViewQuery && inheritViewQuery(definition, baseViewQuery);
|
|
||||||
baseContentQueries && inheritContentQueries(definition, baseContentQueries);
|
|
||||||
fillProperties(definition.inputs, baseDef.inputs);
|
|
||||||
fillProperties(definition.declaredInputs, baseDef.declaredInputs);
|
|
||||||
fillProperties(definition.outputs, baseDef.outputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superDef) {
|
|
||||||
// Merge hostBindings
|
// Merge hostBindings
|
||||||
const superHostBindings = superDef.hostBindings;
|
const superHostBindings = superDef.hostBindings;
|
||||||
superHostBindings && inheritHostBindings(definition, superHostBindings);
|
superHostBindings && inheritHostBindings(definition, superHostBindings);
|
||||||
|
@ -101,25 +83,6 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef<any>| Comp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Even if we don't have a definition, check the type for the hooks and use those if need be
|
|
||||||
const superPrototype = superType.prototype;
|
|
||||||
if (superPrototype) {
|
|
||||||
definition.afterContentChecked =
|
|
||||||
definition.afterContentChecked || superPrototype.ngAfterContentChecked;
|
|
||||||
definition.afterContentInit =
|
|
||||||
definition.afterContentInit || superPrototype.ngAfterContentInit;
|
|
||||||
definition.afterViewChecked =
|
|
||||||
definition.afterViewChecked || superPrototype.ngAfterViewChecked;
|
|
||||||
definition.afterViewInit = definition.afterViewInit || superPrototype.ngAfterViewInit;
|
|
||||||
definition.doCheck = definition.doCheck || superPrototype.ngDoCheck;
|
|
||||||
definition.onDestroy = definition.onDestroy || superPrototype.ngOnDestroy;
|
|
||||||
definition.onInit = definition.onInit || superPrototype.ngOnInit;
|
|
||||||
|
|
||||||
if (superPrototype.ngOnChanges) {
|
|
||||||
ɵɵNgOnChangesFeature()(definition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
superType = Object.getPrototypeOf(superType);
|
superType = Object.getPrototypeOf(superType);
|
||||||
|
|
|
@ -13,7 +13,6 @@ export const NG_DIR_DEF = getClosureSafeProperty({ɵdir: getClosureSafeProperty}
|
||||||
export const NG_PIPE_DEF = getClosureSafeProperty({ɵpipe: getClosureSafeProperty});
|
export const NG_PIPE_DEF = getClosureSafeProperty({ɵpipe: getClosureSafeProperty});
|
||||||
export const NG_MOD_DEF = getClosureSafeProperty({ɵmod: getClosureSafeProperty});
|
export const NG_MOD_DEF = getClosureSafeProperty({ɵmod: getClosureSafeProperty});
|
||||||
export const NG_LOC_ID_DEF = getClosureSafeProperty({ɵloc: getClosureSafeProperty});
|
export const NG_LOC_ID_DEF = getClosureSafeProperty({ɵloc: getClosureSafeProperty});
|
||||||
export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProperty});
|
|
||||||
export const NG_FACTORY_DEF = getClosureSafeProperty({ɵfac: getClosureSafeProperty});
|
export const NG_FACTORY_DEF = getClosureSafeProperty({ɵfac: getClosureSafeProperty});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {LifecycleHooksFeature, renderComponent, whenRendered} from './component';
|
import {LifecycleHooksFeature, renderComponent, whenRendered} from './component';
|
||||||
import {ɵɵdefineBase, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵsetComponentScope, ɵɵsetNgModuleScope} from './definition';
|
import {ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵsetComponentScope, ɵɵsetNgModuleScope} from './definition';
|
||||||
import {ɵɵCopyDefinitionFeature} from './features/copy_definition_feature';
|
import {ɵɵCopyDefinitionFeature} from './features/copy_definition_feature';
|
||||||
import {ɵɵInheritDefinitionFeature} from './features/inherit_definition_feature';
|
import {ɵɵInheritDefinitionFeature} from './features/inherit_definition_feature';
|
||||||
import {ɵɵNgOnChangesFeature} from './features/ng_onchanges_feature';
|
import {ɵɵNgOnChangesFeature} from './features/ng_onchanges_feature';
|
||||||
import {ɵɵProvidersFeature} from './features/providers_feature';
|
import {ɵɵProvidersFeature} from './features/providers_feature';
|
||||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PipeDef, ɵɵBaseDef, ɵɵComponentDefWithMeta, ɵɵDirectiveDefWithMeta, ɵɵFactoryDef, ɵɵPipeDefWithMeta} from './interfaces/definition';
|
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PipeDef, ɵɵComponentDefWithMeta, ɵɵDirectiveDefWithMeta, ɵɵFactoryDef, ɵɵPipeDefWithMeta} from './interfaces/definition';
|
||||||
import {getComponent, getDirectives, getHostElement, getRenderedText} from './util/discovery_utils';
|
import {getComponent, getDirectives, getHostElement, getRenderedText} from './util/discovery_utils';
|
||||||
|
|
||||||
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref';
|
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref';
|
||||||
|
@ -99,7 +99,7 @@ export {
|
||||||
|
|
||||||
ɵɵreference,
|
ɵɵreference,
|
||||||
|
|
||||||
// TODO: remove `select` once we're refactored all of the tests not to use it.
|
// TODO: remove `select` once we've refactored all of the tests not to use it.
|
||||||
ɵɵselect,
|
ɵɵselect,
|
||||||
ɵɵadvance,
|
ɵɵadvance,
|
||||||
ɵɵstyleMap,
|
ɵɵstyleMap,
|
||||||
|
@ -202,7 +202,6 @@ export {ɵɵresolveWindow, ɵɵresolveDocument, ɵɵresolveBody} from './util/mi
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ɵɵBaseDef,
|
|
||||||
ComponentDef,
|
ComponentDef,
|
||||||
ɵɵComponentDefWithMeta,
|
ɵɵComponentDefWithMeta,
|
||||||
ɵɵFactoryDef,
|
ɵɵFactoryDef,
|
||||||
|
@ -221,7 +220,6 @@ export {
|
||||||
ɵɵdefineComponent,
|
ɵɵdefineComponent,
|
||||||
ɵɵdefineDirective,
|
ɵɵdefineDirective,
|
||||||
ɵɵdefineNgModule,
|
ɵɵdefineNgModule,
|
||||||
ɵɵdefineBase,
|
|
||||||
ɵɵdefinePipe,
|
ɵɵdefinePipe,
|
||||||
getHostElement,
|
getHostElement,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
|
|
@ -97,17 +97,20 @@ export type ɵɵDirectiveDefWithMeta<
|
||||||
OutputMap extends{[key: string]: string}, QueryFields extends string[]> = DirectiveDef<T>;
|
OutputMap extends{[key: string]: string}, QueryFields extends string[]> = DirectiveDef<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runtime information for classes that are inherited by components or directives
|
* Runtime link information for Directives.
|
||||||
* that aren't defined as components or directives.
|
|
||||||
*
|
*
|
||||||
* This is an internal data structure used by the renderer to determine what inputs
|
* This is an internal data structure used by the render to link
|
||||||
* and outputs should be inherited.
|
* directives into templates.
|
||||||
*
|
*
|
||||||
* See: {@link defineBase}
|
* NOTE: Always use `defineDirective` function to create this object,
|
||||||
|
* never create the object directly since the shape of this object
|
||||||
|
* can change between versions.
|
||||||
*
|
*
|
||||||
* @codeGenApi
|
* @param Selector type metadata specifying the selector of the directive or component
|
||||||
|
*
|
||||||
|
* See: {@link defineDirective}
|
||||||
*/
|
*/
|
||||||
export interface ɵɵBaseDef<T> {
|
export interface DirectiveDef<T> {
|
||||||
/**
|
/**
|
||||||
* A dictionary mapping the inputs' minified property names to their public API names, which
|
* A dictionary mapping the inputs' minified property names to their public API names, which
|
||||||
* are their aliases if any, or their original unminified property names
|
* are their aliases if any, or their original unminified property names
|
||||||
|
@ -144,23 +147,7 @@ export interface ɵɵBaseDef<T> {
|
||||||
* Refreshes host bindings on the associated directive.
|
* Refreshes host bindings on the associated directive.
|
||||||
*/
|
*/
|
||||||
hostBindings: HostBindingsFunction<T>|null;
|
hostBindings: HostBindingsFunction<T>|null;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime link information for Directives.
|
|
||||||
*
|
|
||||||
* This is internal data structure used by the render to link
|
|
||||||
* directives into templates.
|
|
||||||
*
|
|
||||||
* NOTE: Always use `defineDirective` function to create this object,
|
|
||||||
* never create the object directly since the shape of this object
|
|
||||||
* can change between versions.
|
|
||||||
*
|
|
||||||
* @param Selector type metadata specifying the selector of the directive or component
|
|
||||||
*
|
|
||||||
* See: {@link defineDirective}
|
|
||||||
*/
|
|
||||||
export interface DirectiveDef<T> extends ɵɵBaseDef<T> {
|
|
||||||
/** Token representing the directive. Used by DI. */
|
/** Token representing the directive. Used by DI. */
|
||||||
type: Type<T>;
|
type: Type<T>;
|
||||||
|
|
||||||
|
@ -219,7 +206,7 @@ export type ɵɵFactoryDef<T> = () => T;
|
||||||
/**
|
/**
|
||||||
* Runtime link information for Components.
|
* Runtime link information for Components.
|
||||||
*
|
*
|
||||||
* This is internal data structure used by the render to link
|
* This is an internal data structure used by the render to link
|
||||||
* components into templates.
|
* components into templates.
|
||||||
*
|
*
|
||||||
* NOTE: Always use `defineComponent` function to create this object,
|
* NOTE: Always use `defineComponent` function to create this object,
|
||||||
|
@ -331,7 +318,7 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||||
/**
|
/**
|
||||||
* Runtime link information for Pipes.
|
* Runtime link information for Pipes.
|
||||||
*
|
*
|
||||||
* This is internal data structure used by the renderer to link
|
* This is an internal data structure used by the renderer to link
|
||||||
* pipes into templates.
|
* pipes into templates.
|
||||||
*
|
*
|
||||||
* NOTE: Always use `definePipe` function to create this object,
|
* NOTE: Always use `definePipe` function to create this object,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {R3DirectiveMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade';
|
import {R3DirectiveMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade';
|
||||||
import {R3BaseMetadataFacade, R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface';
|
import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface';
|
||||||
import {resolveForwardRef} from '../../di/forward_ref';
|
import {resolveForwardRef} from '../../di/forward_ref';
|
||||||
import {getReflect, reflectDependencies} from '../../di/jit/util';
|
import {getReflect, reflectDependencies} from '../../di/jit/util';
|
||||||
import {Type} from '../../interface/type';
|
import {Type} from '../../interface/type';
|
||||||
|
@ -16,9 +16,9 @@ import {Component, Directive, Input} from '../../metadata/directives';
|
||||||
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
||||||
import {ViewEncapsulation} from '../../metadata/view';
|
import {ViewEncapsulation} from '../../metadata/view';
|
||||||
import {initNgDevMode} from '../../util/ng_dev_mode';
|
import {initNgDevMode} from '../../util/ng_dev_mode';
|
||||||
import {getBaseDef, getComponentDef, getDirectiveDef} from '../definition';
|
import {getComponentDef, getDirectiveDef} from '../definition';
|
||||||
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
||||||
import {NG_BASE_DEF, NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF} from '../fields';
|
import {NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF} from '../fields';
|
||||||
import {ComponentType} from '../interfaces/definition';
|
import {ComponentType} from '../interfaces/definition';
|
||||||
import {stringifyForError} from '../util/misc_utils';
|
import {stringifyForError} from '../util/misc_utils';
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||||
viewProviders: metadata.viewProviders || null,
|
viewProviders: metadata.viewProviders || null,
|
||||||
};
|
};
|
||||||
if (meta.usesInheritance) {
|
if (meta.usesInheritance) {
|
||||||
addBaseDefToUndecoratedParents(type);
|
addDirectiveDefToUndecoratedParents(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
|
ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
|
||||||
|
@ -153,7 +153,7 @@ function getDirectiveMetadata(type: Type<any>, metadata: Directive) {
|
||||||
const facade = directiveMetadata(type as ComponentType<any>, metadata);
|
const facade = directiveMetadata(type as ComponentType<any>, metadata);
|
||||||
facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl);
|
facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl);
|
||||||
if (facade.usesInheritance) {
|
if (facade.usesInheritance) {
|
||||||
addBaseDefToUndecoratedParents(type);
|
addDirectiveDefToUndecoratedParents(type);
|
||||||
}
|
}
|
||||||
return {metadata: facade, sourceMapUrl};
|
return {metadata: facade, sourceMapUrl};
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ export function directiveMetadata(type: Type<any>, metadata: Directive): R3Direc
|
||||||
inputs: metadata.inputs || EMPTY_ARRAY,
|
inputs: metadata.inputs || EMPTY_ARRAY,
|
||||||
outputs: metadata.outputs || EMPTY_ARRAY,
|
outputs: metadata.outputs || EMPTY_ARRAY,
|
||||||
queries: extractQueriesMetadata(type, propMetadata, isContentQuery),
|
queries: extractQueriesMetadata(type, propMetadata, isContentQuery),
|
||||||
lifecycle: {usesOnChanges: type.prototype.hasOwnProperty('ngOnChanges')},
|
lifecycle: {usesOnChanges: usesLifecycleHook(type, 'ngOnChanges')},
|
||||||
typeSourceSpan: null !,
|
typeSourceSpan: null !,
|
||||||
usesInheritance: !extendsDirectlyFromObject(type),
|
usesInheritance: !extendsDirectlyFromObject(type),
|
||||||
exportAs: extractExportAs(metadata.exportAs),
|
exportAs: extractExportAs(metadata.exportAs),
|
||||||
|
@ -212,76 +212,24 @@ export function directiveMetadata(type: Type<any>, metadata: Directive): R3Direc
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an `ngBaseDef` to all parent classes of a type that don't have an Angular decorator.
|
* Adds a directive definition to all parent classes of a type that don't have an Angular decorator.
|
||||||
*/
|
*/
|
||||||
function addBaseDefToUndecoratedParents(type: Type<any>) {
|
function addDirectiveDefToUndecoratedParents(type: Type<any>) {
|
||||||
const objPrototype = Object.prototype;
|
const objPrototype = Object.prototype;
|
||||||
let parent = Object.getPrototypeOf(type);
|
let parent = Object.getPrototypeOf(type);
|
||||||
|
|
||||||
// Go up the prototype until we hit `Object`.
|
// Go up the prototype until we hit `Object`.
|
||||||
while (parent && parent !== objPrototype) {
|
while (parent && parent !== objPrototype) {
|
||||||
// Since inheritance works if the class was annotated already, we only need to add
|
// Since inheritance works if the class was annotated already, we only need to add
|
||||||
// the base def if there are no annotations and the base def hasn't been created already.
|
// the def if there are no annotations and the def hasn't been created already.
|
||||||
if (!getDirectiveDef(parent) && !getComponentDef(parent) && !getBaseDef(parent)) {
|
if (!getDirectiveDef(parent) && !getComponentDef(parent) &&
|
||||||
const facade = extractBaseDefMetadata(parent);
|
shouldAddAbstractDirective(parent)) {
|
||||||
facade && compileBase(parent, facade);
|
compileDirective(parent, null);
|
||||||
}
|
}
|
||||||
parent = Object.getPrototypeOf(parent);
|
parent = Object.getPrototypeOf(parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compiles the base metadata into a base definition. */
|
|
||||||
function compileBase(type: Type<any>, facade: R3BaseMetadataFacade): void {
|
|
||||||
let ngBaseDef: any = null;
|
|
||||||
Object.defineProperty(type, NG_BASE_DEF, {
|
|
||||||
get: () => {
|
|
||||||
if (ngBaseDef === null) {
|
|
||||||
const name = type && type.name;
|
|
||||||
const sourceMapUrl = `ng://${name}/ngBaseDef.js`;
|
|
||||||
const compiler = getCompilerFacade();
|
|
||||||
ngBaseDef = compiler.compileBase(angularCoreEnv, sourceMapUrl, facade);
|
|
||||||
}
|
|
||||||
return ngBaseDef;
|
|
||||||
},
|
|
||||||
// Make the property configurable in dev mode to allow overriding in tests
|
|
||||||
configurable: !!ngDevMode,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Extracts the metadata necessary to construct an `ngBaseDef` from a class. */
|
|
||||||
function extractBaseDefMetadata(type: Type<any>): R3BaseMetadataFacade|null {
|
|
||||||
const propMetadata = getReflect().ownPropMetadata(type);
|
|
||||||
const viewQueries = extractQueriesMetadata(type, propMetadata, isViewQuery);
|
|
||||||
const queries = extractQueriesMetadata(type, propMetadata, isContentQuery);
|
|
||||||
let inputs: {[key: string]: string | [string, string]}|undefined;
|
|
||||||
let outputs: {[key: string]: string}|undefined;
|
|
||||||
// We only need to know whether there are any HostListener or HostBinding
|
|
||||||
// decorators present, the parsing logic is in the compiler already.
|
|
||||||
let hasHostDecorators = false;
|
|
||||||
|
|
||||||
for (const field in propMetadata) {
|
|
||||||
propMetadata[field].forEach(ann => {
|
|
||||||
const metadataName = ann.ngMetadataName;
|
|
||||||
if (metadataName === 'Input') {
|
|
||||||
inputs = inputs || {};
|
|
||||||
inputs[field] = ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
|
|
||||||
} else if (metadataName === 'Output') {
|
|
||||||
outputs = outputs || {};
|
|
||||||
outputs[field] = ann.bindingPropertyName || field;
|
|
||||||
} else if (metadataName === 'HostBinding' || metadataName === 'HostListener') {
|
|
||||||
hasHostDecorators = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only generate the base def if there's any info inside it.
|
|
||||||
if (inputs || outputs || viewQueries.length || queries.length || hasHostDecorators) {
|
|
||||||
return {name: type.name, type, inputs, outputs, viewQueries, queries, propMetadata};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertToR3QueryPredicate(selector: any): any|string[] {
|
function convertToR3QueryPredicate(selector: any): any|string[] {
|
||||||
return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector);
|
return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector);
|
||||||
}
|
}
|
||||||
|
@ -310,7 +258,7 @@ function extractQueriesMetadata(
|
||||||
`Can't construct a query for the property "${field}" of ` +
|
`Can't construct a query for the property "${field}" of ` +
|
||||||
`"${stringifyForError(type)}" since the query selector wasn't defined.`);
|
`"${stringifyForError(type)}" since the query selector wasn't defined.`);
|
||||||
}
|
}
|
||||||
if (annotations.some(isInputAnn)) {
|
if (annotations.some(isInputAnnotation)) {
|
||||||
throw new Error(`Cannot combine @Input decorators with query decorators`);
|
throw new Error(`Cannot combine @Input decorators with query decorators`);
|
||||||
}
|
}
|
||||||
queriesMeta.push(convertToR3QueryMetadata(field, ann));
|
queriesMeta.push(convertToR3QueryMetadata(field, ann));
|
||||||
|
@ -322,11 +270,7 @@ function extractQueriesMetadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractExportAs(exportAs: string | undefined): string[]|null {
|
function extractExportAs(exportAs: string | undefined): string[]|null {
|
||||||
if (exportAs === undefined) {
|
return exportAs === undefined ? null : splitByComma(exportAs);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return exportAs.split(',').map(part => part.trim());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isContentQuery(value: any): value is Query {
|
function isContentQuery(value: any): value is Query {
|
||||||
|
@ -339,10 +283,45 @@ function isViewQuery(value: any): value is Query {
|
||||||
return name === 'ViewChild' || name === 'ViewChildren';
|
return name === 'ViewChild' || name === 'ViewChildren';
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInputAnn(value: any): value is Input {
|
function isInputAnnotation(value: any): value is Input {
|
||||||
return value.ngMetadataName === 'Input';
|
return value.ngMetadataName === 'Input';
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitByComma(value: string): string[] {
|
function splitByComma(value: string): string[] {
|
||||||
return value.split(',').map(piece => piece.trim());
|
return value.split(',').map(piece => piece.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usesLifecycleHook(type: Type<any>, name: string): boolean {
|
||||||
|
const prototype = type.prototype;
|
||||||
|
return prototype && prototype.hasOwnProperty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LIFECYCLE_HOOKS = [
|
||||||
|
'ngOnChanges', 'ngOnInit', 'ngOnDestroy', 'ngDoCheck', 'ngAfterViewInit', 'ngAfterViewChecked',
|
||||||
|
'ngAfterContentInit', 'ngAfterContentChecked'
|
||||||
|
];
|
||||||
|
|
||||||
|
function shouldAddAbstractDirective(type: Type<any>): boolean {
|
||||||
|
if (LIFECYCLE_HOOKS.some(hookName => usesLifecycleHook(type, hookName))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const propMetadata = getReflect().ownPropMetadata(type);
|
||||||
|
|
||||||
|
for (const field in propMetadata) {
|
||||||
|
const annotations = propMetadata[field];
|
||||||
|
|
||||||
|
for (let i = 0; i < annotations.length; i++) {
|
||||||
|
const current = annotations[i];
|
||||||
|
const metadataName = current.ngMetadataName;
|
||||||
|
|
||||||
|
if (isInputAnnotation(current) || isContentQuery(current) || isViewQuery(current) ||
|
||||||
|
metadataName === 'Output' || metadataName === 'HostBinding' ||
|
||||||
|
metadataName === 'HostListener') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||||
'ɵɵattributeInterpolate7': r3.ɵɵattributeInterpolate7,
|
'ɵɵattributeInterpolate7': r3.ɵɵattributeInterpolate7,
|
||||||
'ɵɵattributeInterpolate8': r3.ɵɵattributeInterpolate8,
|
'ɵɵattributeInterpolate8': r3.ɵɵattributeInterpolate8,
|
||||||
'ɵɵattributeInterpolateV': r3.ɵɵattributeInterpolateV,
|
'ɵɵattributeInterpolateV': r3.ɵɵattributeInterpolateV,
|
||||||
'ɵɵdefineBase': r3.ɵɵdefineBase,
|
|
||||||
'ɵɵdefineComponent': r3.ɵɵdefineComponent,
|
'ɵɵdefineComponent': r3.ɵɵdefineComponent,
|
||||||
'ɵɵdefineDirective': r3.ɵɵdefineDirective,
|
'ɵɵdefineDirective': r3.ɵɵdefineDirective,
|
||||||
'ɵɵdefineInjectable': ɵɵdefineInjectable,
|
'ɵɵdefineInjectable': ɵɵdefineInjectable,
|
||||||
|
|
|
@ -214,6 +214,37 @@ describe('inheritance', () => {
|
||||||
|
|
||||||
expect(log).toEqual(['on changes!']);
|
expect(log).toEqual(['on changes!']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be inherited from undecorated super class which inherits from decorated one', () => {
|
||||||
|
let changes = 0;
|
||||||
|
|
||||||
|
abstract class Base {
|
||||||
|
// Add an Input so that we have at least one Angular decorator on a class field.
|
||||||
|
@Input() inputBase: any;
|
||||||
|
abstract input: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class UndecoratedBase extends Base {
|
||||||
|
abstract input: any;
|
||||||
|
ngOnChanges() { changes++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'my-comp', template: ''})
|
||||||
|
class MyComp extends UndecoratedBase {
|
||||||
|
@Input() input: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({template: '<my-comp [input]="value"></my-comp>'})
|
||||||
|
class App {
|
||||||
|
value = 'hello';
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({declarations: [MyComp, App]});
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(changes).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('of bare super class by a directive', () => {
|
describe('of bare super class by a directive', () => {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {Identifiers} from '@angular/compiler/src/render3/r3_identifiers';
|
||||||
import {angularCoreEnv} from '../../src/render3/jit/environment';
|
import {angularCoreEnv} from '../../src/render3/jit/environment';
|
||||||
|
|
||||||
const INTERFACE_EXCEPTIONS = new Set<string>([
|
const INTERFACE_EXCEPTIONS = new Set<string>([
|
||||||
'ɵɵBaseDef',
|
|
||||||
'ɵɵComponentDefWithMeta',
|
'ɵɵComponentDefWithMeta',
|
||||||
'ɵɵDirectiveDefWithMeta',
|
'ɵɵDirectiveDefWithMeta',
|
||||||
'ɵɵInjectorDef',
|
'ɵɵInjectorDef',
|
||||||
|
|
|
@ -701,21 +701,6 @@ export declare function ɵɵattributeInterpolate8(attrName: string, prefix: stri
|
||||||
|
|
||||||
export declare function ɵɵattributeInterpolateV(attrName: string, values: any[], sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009;
|
export declare function ɵɵattributeInterpolateV(attrName: string, values: any[], sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009;
|
||||||
|
|
||||||
export interface ɵɵBaseDef<T> {
|
|
||||||
contentQueries: ContentQueriesFunction<T> | null;
|
|
||||||
/** @deprecated */ readonly declaredInputs: {
|
|
||||||
[P in keyof T]: string;
|
|
||||||
};
|
|
||||||
hostBindings: HostBindingsFunction<T> | null;
|
|
||||||
readonly inputs: {
|
|
||||||
[P in keyof T]: string;
|
|
||||||
};
|
|
||||||
readonly outputs: {
|
|
||||||
[P in keyof T]: string;
|
|
||||||
};
|
|
||||||
viewQuery: ViewQueriesFunction<T> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export declare function ɵɵclassMap(classes: {
|
export declare function ɵɵclassMap(classes: {
|
||||||
[className: string]: any;
|
[className: string]: any;
|
||||||
} | NO_CHANGE | string | null): void;
|
} | NO_CHANGE | string | null): void;
|
||||||
|
@ -760,18 +745,6 @@ export declare function ɵɵCopyDefinitionFeature(definition: DirectiveDef<any>
|
||||||
|
|
||||||
export declare const ɵɵdefaultStyleSanitizer: StyleSanitizeFn;
|
export declare const ɵɵdefaultStyleSanitizer: StyleSanitizeFn;
|
||||||
|
|
||||||
export declare function ɵɵdefineBase<T>(baseDefinition: {
|
|
||||||
inputs?: {
|
|
||||||
[P in keyof T]?: string | [string, string];
|
|
||||||
};
|
|
||||||
outputs?: {
|
|
||||||
[P in keyof T]?: string;
|
|
||||||
};
|
|
||||||
contentQueries?: ContentQueriesFunction<T> | null;
|
|
||||||
viewQuery?: ViewQueriesFunction<T> | null;
|
|
||||||
hostBindings?: HostBindingsFunction<T>;
|
|
||||||
}): ɵɵBaseDef<T>;
|
|
||||||
|
|
||||||
export declare function ɵɵdefineComponent<T>(componentDefinition: {
|
export declare function ɵɵdefineComponent<T>(componentDefinition: {
|
||||||
type: Type<T>;
|
type: Type<T>;
|
||||||
selectors: CssSelectorList;
|
selectors: CssSelectorList;
|
||||||
|
|
Loading…
Reference in New Issue