2020-10-30 23:45:15 +01:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright Google LLC 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 * as o from '../../output/output_ast';
|
|
|
|
|
import {Identifiers as R3} from '../r3_identifiers';
|
|
|
|
|
import {R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from '../view/api';
|
2020-11-16 18:04:49 +01:00
|
|
|
import {createDirectiveType} from '../view/compiler';
|
2020-10-30 23:45:15 +01:00
|
|
|
import {asLiteral, conditionallyCreateMapObjectLiteral, DefinitionMap} from '../view/util';
|
2020-12-03 23:03:23 +01:00
|
|
|
import {R3DeclareDirectiveMetadata, R3DeclareQueryMetadata} from './api';
|
2020-11-16 18:04:49 +01:00
|
|
|
import {toOptionalLiteralMap} from './util';
|
2020-10-30 23:45:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compile a directive declaration defined by the `R3DirectiveMetadata`.
|
|
|
|
|
*/
|
|
|
|
|
export function compileDeclareDirectiveFromMetadata(meta: R3DirectiveMetadata): R3DirectiveDef {
|
|
|
|
|
const definitionMap = createDirectiveDefinitionMap(meta);
|
|
|
|
|
|
|
|
|
|
const expression = o.importExpr(R3.declareDirective).callFn([definitionMap.toLiteralMap()]);
|
2020-11-16 18:04:49 +01:00
|
|
|
const type = createDirectiveType(meta);
|
2020-10-30 23:45:15 +01:00
|
|
|
|
|
|
|
|
return {expression, type};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing
|
|
|
|
|
* this logic for components, as they extend the directive metadata.
|
|
|
|
|
*/
|
2020-12-03 23:03:23 +01:00
|
|
|
export function createDirectiveDefinitionMap(meta: R3DirectiveMetadata):
|
|
|
|
|
DefinitionMap<R3DeclareDirectiveMetadata> {
|
|
|
|
|
const definitionMap = new DefinitionMap<R3DeclareDirectiveMetadata>();
|
2020-10-30 23:45:15 +01:00
|
|
|
|
2020-11-25 21:03:02 +00:00
|
|
|
definitionMap.set('version', o.literal('0.0.0-PLACEHOLDER'));
|
2020-10-30 23:45:15 +01:00
|
|
|
|
|
|
|
|
// e.g. `type: MyDirective`
|
|
|
|
|
definitionMap.set('type', meta.internalType);
|
|
|
|
|
|
|
|
|
|
// e.g. `selector: 'some-dir'`
|
|
|
|
|
if (meta.selector !== null) {
|
|
|
|
|
definitionMap.set('selector', o.literal(meta.selector));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
|
|
|
|
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
|
|
|
|
|
|
|
|
|
|
definitionMap.set('host', compileHostMetadata(meta.host));
|
|
|
|
|
|
|
|
|
|
definitionMap.set('providers', meta.providers);
|
|
|
|
|
|
|
|
|
|
if (meta.queries.length > 0) {
|
|
|
|
|
definitionMap.set('queries', o.literalArr(meta.queries.map(compileQuery)));
|
|
|
|
|
}
|
|
|
|
|
if (meta.viewQueries.length > 0) {
|
|
|
|
|
definitionMap.set('viewQueries', o.literalArr(meta.viewQueries.map(compileQuery)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (meta.exportAs !== null) {
|
|
|
|
|
definitionMap.set('exportAs', asLiteral(meta.exportAs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (meta.usesInheritance) {
|
|
|
|
|
definitionMap.set('usesInheritance', o.literal(true));
|
|
|
|
|
}
|
|
|
|
|
if (meta.lifecycle.usesOnChanges) {
|
|
|
|
|
definitionMap.set('usesOnChanges', o.literal(true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
definitionMap.set('ngImport', o.importExpr(R3.core));
|
|
|
|
|
|
|
|
|
|
return definitionMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compiles the metadata of a single query into its partial declaration form as declared
|
|
|
|
|
* by `R3DeclareQueryMetadata`.
|
|
|
|
|
*/
|
|
|
|
|
function compileQuery(query: R3QueryMetadata): o.LiteralMapExpr {
|
2020-12-03 23:03:23 +01:00
|
|
|
const meta = new DefinitionMap<R3DeclareQueryMetadata>();
|
2020-10-30 23:45:15 +01:00
|
|
|
meta.set('propertyName', o.literal(query.propertyName));
|
|
|
|
|
if (query.first) {
|
|
|
|
|
meta.set('first', o.literal(true));
|
|
|
|
|
}
|
|
|
|
|
meta.set(
|
|
|
|
|
'predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : query.predicate);
|
2020-12-10 15:10:56 -08:00
|
|
|
if (!query.emitDistinctChangesOnly) {
|
|
|
|
|
// `emitDistinctChangesOnly` is special because in future we expect it to be `true`. For this
|
|
|
|
|
// reason the absence should be interpreted as `true`.
|
|
|
|
|
meta.set('emitDistinctChangesOnly', o.literal(false));
|
|
|
|
|
}
|
2020-10-30 23:45:15 +01:00
|
|
|
if (query.descendants) {
|
|
|
|
|
meta.set('descendants', o.literal(true));
|
|
|
|
|
}
|
|
|
|
|
meta.set('read', query.read);
|
|
|
|
|
if (query.static) {
|
|
|
|
|
meta.set('static', o.literal(true));
|
|
|
|
|
}
|
|
|
|
|
return meta.toLiteralMap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compiles the host metadata into its partial declaration form as declared
|
|
|
|
|
* in `R3DeclareDirectiveMetadata['host']`
|
|
|
|
|
*/
|
|
|
|
|
function compileHostMetadata(meta: R3HostMetadata): o.LiteralMapExpr|null {
|
2020-12-03 23:03:23 +01:00
|
|
|
const hostMetadata = new DefinitionMap<NonNullable<R3DeclareDirectiveMetadata['host']>>();
|
2020-10-30 23:45:15 +01:00
|
|
|
hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression));
|
|
|
|
|
hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, o.literal));
|
|
|
|
|
hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, o.literal));
|
|
|
|
|
|
|
|
|
|
if (meta.specialAttributes.styleAttr) {
|
|
|
|
|
hostMetadata.set('styleAttribute', o.literal(meta.specialAttributes.styleAttr));
|
|
|
|
|
}
|
|
|
|
|
if (meta.specialAttributes.classAttr) {
|
|
|
|
|
hostMetadata.set('classAttribute', o.literal(meta.specialAttributes.classAttr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hostMetadata.values.length > 0) {
|
|
|
|
|
return hostMetadata.toLiteralMap();
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|