Skip to content

Commit

Permalink
fix(compiler-cli): allow declaration-only template type check members (
Browse files Browse the repository at this point in the history
…#34296)

The metadata collector for View Engine compilations emits error symbols
for static class members that have not been initialized, which prevents
a library from building successfully when `strictMetadataEmit` is
enabled, which is recommended for libraries to avoid issues in library
consumers. This is troublesome for libraries that are adopting static
members for the Ivy template type checker: these members don't need a
value assignment as only their type is of importance, however this
causes metadata errors. As such, a library used to be required to
initialize the special static members to workaround this error,
undesirably introducing a code-size overhead in terms of emitted
JavaScript code.

This commit modifies the collector logic to specifically ignore
the special static members for Ivy's template type checker, preventing
any errors from being recorded during the metadata collection.

PR Close #34296
  • Loading branch information
JoostK authored and AndrewKushnir committed Dec 11, 2019
1 parent edfaab6 commit bbb9412
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
6 changes: 5 additions & 1 deletion packages/compiler-cli/src/metadata/collector.ts
Expand Up @@ -230,7 +230,7 @@ export class MetadataCollector {
const property = <ts.PropertyDeclaration>member;
if (isStatic(property)) {
const name = evaluator.nameOf(property.name);
if (!isMetadataError(name)) {
if (!isMetadataError(name) && !shouldIgnoreStaticMember(name)) {
if (property.initializer) {
const value = evaluator.evaluateNode(property.initializer);
recordStaticMember(name, value);
Expand Down Expand Up @@ -744,6 +744,10 @@ function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] {
return result;
}

function shouldIgnoreStaticMember(memberName: string): boolean {
return memberName.startsWith('ngAcceptInputType_') || memberName.startsWith('ngTemplateGuard_');
}

function expandedMessage(error: any): string {
switch (error.message) {
case 'Reference to non-exported class':
Expand Down
25 changes: 24 additions & 1 deletion packages/compiler-cli/test/metadata/collector_spec.ts
Expand Up @@ -37,7 +37,7 @@ describe('Collector', () => {
'static-method.ts', 'static-method-call.ts',
'static-method-with-if.ts', 'static-method-with-default.ts',
'class-inheritance.ts', 'class-inheritance-parent.ts',
'interface-reference.ts'
'interface-reference.ts', 'static-type-check-members.ts',
]);
service = ts.createLanguageService(host, documentRegistry);
program = service.getProgram() !;
Expand Down Expand Up @@ -547,6 +547,18 @@ describe('Collector', () => {
expect(classData.statics).toEqual({VALUE: 'Some string'});
});

it('should ignore static type check members without a value', () => {
const typeCheckMembers = program.getSourceFile('/static-type-check-members.ts') !;
const metadata = collector.getMetadata(typeCheckMembers) !;
const classData = <ClassMetadata>metadata.metadata['MyDirective'];
expect(classData.statics).toEqual({
foo: 'bar',
declared: {__symbolic: 'error', message: 'Variable not initialized', line: 3, character: 13},
ngTemplateContextGuard: {__symbolic: 'function', parameters: ['dir', 'ctx'], value: true},
ngTemplateGuard_value: {__symbolic: 'function', parameters: ['dir', 'expr'], value: true},
});
});

it('should be able to collect a reference to a static field', () => {
const staticSource = program.getSourceFile('/static-field-reference.ts') !;
const metadata = collector.getMetadata(staticSource) !;
Expand Down Expand Up @@ -1472,6 +1484,17 @@ const FILES: Directory = {
static VALUE = 'Some string';
}
`,
'static-type-check-members.ts': `
export class MyDirective<T> {
static foo = 'bar';
static declared: string;
static ngAcceptInputType_disabled: boolean|string;
static ngTemplateContextGuard(dir: any, ctx: any): any { return true; };
static ngTemplateGuard_declared: 'binding';
static ngTemplateGuard_value(dir: any, expr: any): any { return true; };
}
`,
'static-field-reference.ts': `
import {Component} from 'angular2/core';
import {MyModule} from './static-field';
Expand Down

0 comments on commit bbb9412

Please sign in to comment.