From 142553abc61b76bfc2cd2ab4651ba940ba62461c Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Tue, 8 Jan 2019 16:30:57 -0800 Subject: [PATCH] feat(ivy): accept multiple values for exportAs in the compiler (#28001) exportAs in @Directive metadata supports multiple values, separated by commas. Previously it was treated as a single value string. This commit modifies the compiler to understand that exportAs is a string[]. It stops short of carrying the multiple values through to the runtime. Instead, it only emits the first one. A future commit will modify the runtime to accept all the values. PR Close #28001 --- .../src/ngtsc/annotations/src/directive.ts | 4 ++-- .../src/ngtsc/annotations/src/selector_scope.ts | 2 +- packages/compiler/src/compiler_facade_interface.ts | 2 +- packages/compiler/src/render3/view/api.ts | 2 +- packages/compiler/src/render3/view/compiler.ts | 7 +++++-- packages/compiler/src/render3/view/t2_api.ts | 2 +- packages/compiler/src/render3/view/t2_binder.ts | 5 ++++- packages/core/src/render3/interfaces/definition.ts | 4 ++-- .../core/src/render3/jit/compiler_facade_interface.ts | 2 +- packages/core/src/render3/jit/directive.ts | 10 +++++++++- 10 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index a581461bd7..a7a89500b2 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -177,7 +177,7 @@ export function extractDirectiveMetadata( member.name === 'ngOnChanges'); // Parse exportAs. - let exportAs: string|null = null; + let exportAs: string[]|null = null; if (directive.has('exportAs')) { const expr = directive.get('exportAs') !; const resolved = evaluator.evaluate(expr); @@ -185,7 +185,7 @@ export function extractDirectiveMetadata( throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`); } - exportAs = resolved; + exportAs = resolved.split(',').map(part => part.trim()); } // Detect if the component inherits from another class diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts index 928b499461..65a853ac8e 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts @@ -366,7 +366,7 @@ export class SelectorScopeRegistry { name: clazz.name !.text, directive: ref, isComponent: def.name === 'ngComponentDef', selector, - exportAs: readStringType(def.type.typeArguments[2]), + exportAs: readStringArrayType(def.type.typeArguments[2]), inputs: readStringMapType(def.type.typeArguments[3]), outputs: readStringMapType(def.type.typeArguments[4]), queries: readStringArrayType(def.type.typeArguments[5]), diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index 372483897a..5e659a47af 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -119,7 +119,7 @@ export interface R3DirectiveMetadataFacade { inputs: string[]; outputs: string[]; usesInheritance: boolean; - exportAs: string|null; + exportAs: string[]|null; providers: Provider[]|null; } diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index bc12edc082..afe470a482 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -104,7 +104,7 @@ export interface R3DirectiveMetadata { * Reference name under which to export the directive's type in a template, * if any. */ - exportAs: string|null; + exportAs: string[]|null; /** * The list of providers defined in the directive. diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index fcec424ed4..93bf899c89 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -117,7 +117,9 @@ function baseDirectiveFields( definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs)); if (meta.exportAs !== null) { - definitionMap.set('exportAs', o.literal(meta.exportAs)); + // TODO: handle multiple exportAs values (currently only the first is taken). + const [exportAs] = meta.exportAs; + definitionMap.set('exportAs', o.literal(exportAs)); } return {definitionMap, statements: result.statements}; @@ -605,7 +607,8 @@ function createTypeForDef(meta: R3DirectiveMetadata, typeBase: o.ExternalReferen return o.expressionType(o.importExpr(typeBase, [ typeWithParameters(meta.type, meta.typeArgumentCount), stringAsType(selectorForType), - meta.exportAs !== null ? stringAsType(meta.exportAs) : o.NONE_TYPE, + // TODO: handle multiple exportAs values (currently only the first is taken). + meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : o.NONE_TYPE, stringMapAsType(meta.inputs), stringMapAsType(meta.outputs), stringArrayAsType(meta.queries.map(q => q.propertyName)), diff --git a/packages/compiler/src/render3/view/t2_api.ts b/packages/compiler/src/render3/view/t2_api.ts index 0b6f104316..e484760e86 100644 --- a/packages/compiler/src/render3/view/t2_api.ts +++ b/packages/compiler/src/render3/view/t2_api.ts @@ -58,7 +58,7 @@ export interface DirectiveMeta { * * Null otherwise */ - exportAs: string|null; + exportAs: string[]|null; } /** diff --git a/packages/compiler/src/render3/view/t2_binder.ts b/packages/compiler/src/render3/view/t2_binder.ts index 6d73a35c8a..2cde692372 100644 --- a/packages/compiler/src/render3/view/t2_binder.ts +++ b/packages/compiler/src/render3/view/t2_binder.ts @@ -259,7 +259,10 @@ class DirectiveBinder implements Visitor { dirTarget = directives.find(dir => dir.isComponent) || null; } else { // This is a reference to a directive exported via exportAs. One should exist. - dirTarget = directives.find(dir => dir.exportAs === ref.value) || null; + dirTarget = + directives.find( + dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) || + null; // Check if a matching directive was found, and error if it wasn't. if (dirTarget === null) { diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index f530b5cea2..2c3570c48f 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -60,7 +60,7 @@ export const enum DirectiveDefFlags {ContentQuery = 0b10} export interface PipeType extends Type { ngPipeDef: never; } export type DirectiveDefWithMeta< - T, Selector extends string, ExportAs extends string, InputMap extends{[key: string]: string}, + T, Selector extends string, ExportAs extends string[], InputMap extends{[key: string]: string}, OutputMap extends{[key: string]: string}, QueryFields extends string[]> = DirectiveDef; /** @@ -163,7 +163,7 @@ export interface DirectiveDef extends BaseDef { } export type ComponentDefWithMeta< - T, Selector extends String, ExportAs extends string, InputMap extends{[key: string]: string}, + T, Selector extends String, ExportAs extends string[], InputMap extends{[key: string]: string}, OutputMap extends{[key: string]: string}, QueryFields extends string[]> = ComponentDef; /** diff --git a/packages/core/src/render3/jit/compiler_facade_interface.ts b/packages/core/src/render3/jit/compiler_facade_interface.ts index fe230636ff..8c424454b3 100644 --- a/packages/core/src/render3/jit/compiler_facade_interface.ts +++ b/packages/core/src/render3/jit/compiler_facade_interface.ts @@ -119,7 +119,7 @@ export interface R3DirectiveMetadataFacade { inputs: string[]; outputs: string[]; usesInheritance: boolean; - exportAs: string|null; + exportAs: string[]|null; providers: Provider[]|null; } diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 11c28ecfc2..bb060abfee 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -150,7 +150,7 @@ function directiveMetadata(type: Type, metadata: Directive): R3DirectiveMet }, typeSourceSpan: null !, usesInheritance: !extendsDirectlyFromObject(type), - exportAs: metadata.exportAs || null, + exportAs: extractExportAs(metadata.exportAs), providers: metadata.providers || null, }; } @@ -189,6 +189,14 @@ function extractQueriesMetadata( return queriesMeta; } +function extractExportAs(exportAs: string | undefined): string[]|null { + if (exportAs === undefined) { + return null; + } + + return exportAs.split(',').map(part => part.trim()); +} + function isContentQuery(value: any): value is Query { const name = value.ngMetadataName; return name === 'ContentChild' || name === 'ContentChildren';