refactor(compiler): add type information to `DefinitionMap` (#39961)

This allows the code generation to correspond with a type, which is
helpful for documentation and discoverability purposes. This does not
offer any type-safety with respect to the actually generated code.

PR Close #39961
This commit is contained in:
JoostK 2020-12-03 23:03:23 +01:00 committed by Misko Hevery
parent 5848439a48
commit 5fa026fd81
3 changed files with 22 additions and 13 deletions

View File

@ -9,10 +9,11 @@ import * as core from '../../core';
import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config'; import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config';
import * as o from '../../output/output_ast'; import * as o from '../../output/output_ast';
import {Identifiers as R3} from '../r3_identifiers'; import {Identifiers as R3} from '../r3_identifiers';
import {R3ComponentDef, R3ComponentMetadata} from '../view/api'; import {R3ComponentDef, R3ComponentMetadata, R3UsedDirectiveMetadata} from '../view/api';
import {createComponentType} from '../view/compiler'; import {createComponentType} from '../view/compiler';
import {ParsedTemplate} from '../view/template'; import {ParsedTemplate} from '../view/template';
import {DefinitionMap} from '../view/util'; import {DefinitionMap} from '../view/util';
import {R3DeclareComponentMetadata} from './api';
import {createDirectiveDefinitionMap} from './directive'; import {createDirectiveDefinitionMap} from './directive';
import {toOptionalLiteralArray} from './util'; import {toOptionalLiteralArray} from './util';
@ -34,9 +35,10 @@ export function compileDeclareComponentFromMetadata(
/** /**
* Gathers the declaration fields for a component into a `DefinitionMap`. * Gathers the declaration fields for a component into a `DefinitionMap`.
*/ */
export function createComponentDefinitionMap( export function createComponentDefinitionMap(meta: R3ComponentMetadata, template: ParsedTemplate):
meta: R3ComponentMetadata, template: ParsedTemplate): DefinitionMap { DefinitionMap<R3DeclareComponentMetadata> {
const definitionMap = createDirectiveDefinitionMap(meta); const definitionMap: DefinitionMap<R3DeclareComponentMetadata> =
createDirectiveDefinitionMap(meta);
const templateMap = compileTemplateDefinition(template); const templateMap = compileTemplateDefinition(template);
@ -76,7 +78,7 @@ export function createComponentDefinitionMap(
* Compiles the provided template into its partial definition. * Compiles the provided template into its partial definition.
*/ */
function compileTemplateDefinition(template: ParsedTemplate): o.LiteralMapExpr { function compileTemplateDefinition(template: ParsedTemplate): o.LiteralMapExpr {
const templateMap = new DefinitionMap(); const templateMap = new DefinitionMap<R3DeclareComponentMetadata['template']>();
const templateExpr = const templateExpr =
typeof template.template === 'string' ? o.literal(template.template) : template.template; typeof template.template === 'string' ? o.literal(template.template) : template.template;
templateMap.set('source', templateExpr); templateMap.set('source', templateExpr);
@ -94,7 +96,7 @@ function compileUsedDirectiveMetadata(meta: R3ComponentMetadata): o.LiteralArray
(expr: o.Expression) => expr; (expr: o.Expression) => expr;
return toOptionalLiteralArray(meta.directives, directive => { return toOptionalLiteralArray(meta.directives, directive => {
const dirMeta = new DefinitionMap(); const dirMeta = new DefinitionMap<R3UsedDirectiveMetadata>();
dirMeta.set('type', wrapType(directive.type)); dirMeta.set('type', wrapType(directive.type));
dirMeta.set('selector', o.literal(directive.selector)); dirMeta.set('selector', o.literal(directive.selector));
dirMeta.set('inputs', toOptionalLiteralArray(directive.inputs, o.literal)); dirMeta.set('inputs', toOptionalLiteralArray(directive.inputs, o.literal));

View File

@ -10,6 +10,7 @@ import {Identifiers as R3} from '../r3_identifiers';
import {R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from '../view/api'; import {R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from '../view/api';
import {createDirectiveType} from '../view/compiler'; import {createDirectiveType} from '../view/compiler';
import {asLiteral, conditionallyCreateMapObjectLiteral, DefinitionMap} from '../view/util'; import {asLiteral, conditionallyCreateMapObjectLiteral, DefinitionMap} from '../view/util';
import {R3DeclareDirectiveMetadata, R3DeclareQueryMetadata} from './api';
import {toOptionalLiteralMap} from './util'; import {toOptionalLiteralMap} from './util';
@ -29,8 +30,9 @@ export function compileDeclareDirectiveFromMetadata(meta: R3DirectiveMetadata):
* Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing * Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing
* this logic for components, as they extend the directive metadata. * this logic for components, as they extend the directive metadata.
*/ */
export function createDirectiveDefinitionMap(meta: R3DirectiveMetadata): DefinitionMap { export function createDirectiveDefinitionMap(meta: R3DirectiveMetadata):
const definitionMap = new DefinitionMap(); DefinitionMap<R3DeclareDirectiveMetadata> {
const definitionMap = new DefinitionMap<R3DeclareDirectiveMetadata>();
definitionMap.set('version', o.literal('0.0.0-PLACEHOLDER')); definitionMap.set('version', o.literal('0.0.0-PLACEHOLDER'));
@ -77,7 +79,7 @@ export function createDirectiveDefinitionMap(meta: R3DirectiveMetadata): Definit
* by `R3DeclareQueryMetadata`. * by `R3DeclareQueryMetadata`.
*/ */
function compileQuery(query: R3QueryMetadata): o.LiteralMapExpr { function compileQuery(query: R3QueryMetadata): o.LiteralMapExpr {
const meta = new DefinitionMap(); const meta = new DefinitionMap<R3DeclareQueryMetadata>();
meta.set('propertyName', o.literal(query.propertyName)); meta.set('propertyName', o.literal(query.propertyName));
if (query.first) { if (query.first) {
meta.set('first', o.literal(true)); meta.set('first', o.literal(true));
@ -99,7 +101,7 @@ function compileQuery(query: R3QueryMetadata): o.LiteralMapExpr {
* in `R3DeclareDirectiveMetadata['host']` * in `R3DeclareDirectiveMetadata['host']`
*/ */
function compileHostMetadata(meta: R3HostMetadata): o.LiteralMapExpr|null { function compileHostMetadata(meta: R3HostMetadata): o.LiteralMapExpr|null {
const hostMetadata = new DefinitionMap(); const hostMetadata = new DefinitionMap<NonNullable<R3DeclareDirectiveMetadata['host']>>();
hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression)); hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression));
hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, o.literal)); hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, o.literal));
hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, o.literal)); hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, o.literal));

View File

@ -142,12 +142,17 @@ export function getQueryPredicate(
} }
} }
export class DefinitionMap { /**
* A representation for an object literal used during codegen of definition objects. The generic
* type `T` allows to reference a documented type of the generated structure, such that the
* property names that are set can be resolved to their documented declaration.
*/
export class DefinitionMap<T = any> {
values: {key: string, quoted: boolean, value: o.Expression}[] = []; values: {key: string, quoted: boolean, value: o.Expression}[] = [];
set(key: string, value: o.Expression|null): void { set(key: keyof T, value: o.Expression|null): void {
if (value) { if (value) {
this.values.push({key, value, quoted: false}); this.values.push({key: key as string, value, quoted: false});
} }
} }