Skip to content

Commit b6078f5

Browse files
chuckjazvicb
authored andcommitted
fix(compiler): update to metadata version 3 (angular#13464)
This change retracts support for metadata version 2. The collector used to produce version 2 metadata was incomplete and can cause the AOT compiler to fail to resolve symbols or produce other spurious errors. All libraries compiled and published with 2.3.0 ngc will need to be recompiled and updated with this change.
1 parent c65b4fa commit b6078f5

File tree

8 files changed

+66
-59
lines changed

8 files changed

+66
-59
lines changed

modules/@angular/compiler-cli/src/compiler_host.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,31 +177,31 @@ export class CompilerHost implements AotCompilerHost {
177177
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
178178
[];
179179
const v1Metadata = metadatas.find((m: any) => m['version'] === 1);
180-
let v2Metadata = metadatas.find((m: any) => m['version'] === 2);
181-
if (!v2Metadata && v1Metadata) {
182-
// patch up v1 to v2 by merging the metadata with metadata collected from the d.ts file
180+
let v3Metadata = metadatas.find((m: any) => m['version'] === 3);
181+
if (!v3Metadata && v1Metadata) {
182+
// patch up v1 to v3 by merging the metadata with metadata collected from the d.ts file
183183
// as the only difference between the versions is whether all exports are contained in
184184
// the metadata and the `extends` clause.
185-
v2Metadata = {'__symbolic': 'module', 'version': 2, 'metadata': {}};
185+
v3Metadata = {'__symbolic': 'module', 'version': 3, 'metadata': {}};
186186
if (v1Metadata.exports) {
187-
v2Metadata.exports = v1Metadata.exports;
187+
v3Metadata.exports = v1Metadata.exports;
188188
}
189189
for (let prop in v1Metadata.metadata) {
190-
v2Metadata.metadata[prop] = v1Metadata.metadata[prop];
190+
v3Metadata.metadata[prop] = v1Metadata.metadata[prop];
191191
}
192192

193193
const exports = this.metadataCollector.getMetadata(this.getSourceFile(dtsFilePath));
194194
if (exports) {
195195
for (let prop in exports.metadata) {
196-
if (!v2Metadata.metadata[prop]) {
197-
v2Metadata.metadata[prop] = exports.metadata[prop];
196+
if (!v3Metadata.metadata[prop]) {
197+
v3Metadata.metadata[prop] = exports.metadata[prop];
198198
}
199199
}
200200
if (exports.exports) {
201201
v2Metadata.exports = exports.exports;
202202
}
203203
}
204-
metadatas.push(v2Metadata);
204+
metadatas.push(v3Metadata);
205205
}
206206
this.resolverCache.set(filePath, metadatas);
207207
return metadatas;

modules/@angular/compiler-cli/test/aot_host_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,11 @@ describe('CompilerHost', () => {
166166
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts')).toBeUndefined();
167167
});
168168

169-
it('should add missing v2 metadata from v1 metadata and .d.ts files', () => {
169+
it('should add missing v3 metadata from v1 metadata and .d.ts files', () => {
170170
expect(hostNestedGenDir.getMetadataFor('metadata_versions/v1.d.ts')).toEqual([
171171
{__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}}, {
172172
__symbolic: 'module',
173-
version: 2,
173+
version: 3,
174174
metadata: {
175175
foo: {__symbolic: 'class'},
176176
Bar: {__symbolic: 'class', members: {ngOnInit: [{__symbolic: 'method'}]}},

modules/@angular/compiler/src/aot/static_reflector.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, Ho
1010
import {ReflectorReader} from '../private_import_core';
1111
import {StaticSymbol} from './static_symbol';
1212

13-
const SUPPORTED_SCHEMA_VERSION = 2;
13+
const SUPPORTED_SCHEMA_VERSION = 3;
1414
const ANGULAR_IMPORT_LOCATIONS = {
1515
coreDecorators: '@angular/core/src/metadata',
1616
diDecorators: '@angular/core/src/di/metadata',
@@ -754,10 +754,10 @@ export class StaticReflector implements ReflectorReader {
754754
{__symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {}};
755755
}
756756
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
757-
this.reportError(
758-
new Error(
759-
`Metadata version mismatch for module ${module}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`),
760-
null);
757+
const errorMessage = moduleMetadata['version'] == 2 ?
758+
`Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
759+
`Metadata version mismatch for module ${module}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
760+
this.reportError(new Error(errorMessage), null);
761761
}
762762
this.metadataCache.set(module, moduleMetadata);
763763
}

modules/@angular/compiler/test/aot/static_reflector_spec.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ describe('StaticReflector', () => {
8080
it('should throw an exception for unsupported metadata versions', () => {
8181
expect(() => reflector.findDeclaration('src/version-error', 'e'))
8282
.toThrow(new Error(
83-
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 2'));
83+
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 3'));
84+
});
85+
86+
it('should throw an exception for version 2 metadata', () => {
87+
expect(() => reflector.findDeclaration('src/version-2-error', 'e'))
88+
.toThrowError(
89+
'Unsupported metadata version 2 for module /tmp/src/version-2-error.d.ts. This module should be compiled with a newer version of ngc');
8490
});
8591

8692
it('should get and empty annotation list for an unknown class', () => {
@@ -384,7 +390,7 @@ describe('StaticReflector', () => {
384390
const metadata = reflector.getModuleMetadata('/tmp/src/custom-decorator-reference.ts');
385391
expect(metadata).toEqual({
386392
__symbolic: 'module',
387-
version: 2,
393+
version: 3,
388394
metadata: {
389395
Foo: {
390396
__symbolic: 'class',
@@ -775,7 +781,7 @@ export class MockStaticReflectorHost implements StaticReflectorHost {
775781
const DEFAULT_TEST_DATA: {[key: string]: any} = {
776782
'/tmp/@angular/common/src/forms-deprecated/directives.d.ts': [{
777783
'__symbolic': 'module',
778-
'version': 2,
784+
'version': 3,
779785
'metadata': {
780786
'FORM_DIRECTIVES': [
781787
{
@@ -788,7 +794,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
788794
}],
789795
'/tmp/@angular/common/src/directives/ng_for.d.ts': {
790796
'__symbolic': 'module',
791-
'version': 2,
797+
'version': 3,
792798
'metadata': {
793799
'NgFor': {
794800
'__symbolic': 'class',
@@ -841,16 +847,16 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
841847
}
842848
},
843849
'/tmp/@angular/core/src/linker/view_container_ref.d.ts':
844-
{version: 2, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
850+
{version: 3, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
845851
'/tmp/@angular/core/src/linker/template_ref.d.ts':
846-
{version: 2, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
852+
{version: 3, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
847853
'/tmp/@angular/core/src/change_detection/differs/iterable_differs.d.ts':
848-
{version: 2, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
854+
{version: 3, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
849855
'/tmp/@angular/core/src/change_detection/change_detector_ref.d.ts':
850-
{version: 2, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
856+
{version: 3, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
851857
'/tmp/src/app/hero-detail.component.d.ts': {
852858
'__symbolic': 'module',
853-
'version': 2,
859+
'version': 3,
854860
'metadata': {
855861
'HeroDetailComponent': {
856862
'__symbolic': 'class',
@@ -1001,11 +1007,12 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
10011007
}
10021008
}
10031009
},
1004-
'/src/extern.d.ts': {'__symbolic': 'module', 'version': 2, metadata: {s: 's'}},
1010+
'/src/extern.d.ts': {'__symbolic': 'module', 'version': 3, metadata: {s: 's'}},
10051011
'/tmp/src/version-error.d.ts': {'__symbolic': 'module', 'version': 100, metadata: {e: 's'}},
1012+
'/tmp/src/version-2-error.d.ts': {'__symbolic': 'module', 'version': 2, metadata: {e: 's'}},
10061013
'/tmp/src/error-reporting.d.ts': {
10071014
__symbolic: 'module',
1008-
version: 2,
1015+
version: 3,
10091016
metadata: {
10101017
SomeClass: {
10111018
__symbolic: 'class',
@@ -1035,7 +1042,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
10351042
},
10361043
'/tmp/src/error-references.d.ts': {
10371044
__symbolic: 'module',
1038-
version: 2,
1045+
version: 3,
10391046
metadata: {
10401047
Link1: {
10411048
__symbolic: 'reference',
@@ -1057,7 +1064,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
10571064
},
10581065
'/tmp/src/function-declaration.d.ts': {
10591066
__symbolic: 'module',
1060-
version: 2,
1067+
version: 3,
10611068
metadata: {
10621069
one: {
10631070
__symbolic: 'function',
@@ -1086,7 +1093,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
10861093
},
10871094
'/tmp/src/function-reference.ts': {
10881095
__symbolic: 'module',
1089-
version: 2,
1096+
version: 3,
10901097
metadata: {
10911098
one: {
10921099
__symbolic: 'call',
@@ -1128,7 +1135,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
11281135
},
11291136
'/tmp/src/function-recursive.d.ts': {
11301137
__symbolic: 'modules',
1131-
version: 2,
1138+
version: 3,
11321139
metadata: {
11331140
recursive: {
11341141
__symbolic: 'function',
@@ -1188,7 +1195,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
11881195
},
11891196
'/tmp/src/spread.ts': {
11901197
__symbolic: 'module',
1191-
version: 2,
1198+
version: 3,
11921199
metadata: {
11931200
spread: [0, {__symbolic: 'spread', expression: [1, 2, 3, 4]}, 5]
11941201
}
@@ -1338,7 +1345,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
13381345
`,
13391346
'/tmp/src/reexport/reexport.d.ts': {
13401347
__symbolic: 'module',
1341-
version: 2,
1348+
version: 3,
13421349
metadata: {},
13431350
exports: [
13441351
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
@@ -1347,7 +1354,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
13471354
},
13481355
'/tmp/src/reexport/src/origin1.d.ts': {
13491356
__symbolic: 'module',
1350-
version: 2,
1357+
version: 3,
13511358
metadata: {
13521359
One: {__symbolic: 'class'},
13531360
Two: {__symbolic: 'class'},
@@ -1356,26 +1363,26 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
13561363
},
13571364
'/tmp/src/reexport/src/origin5.d.ts': {
13581365
__symbolic: 'module',
1359-
version: 2,
1366+
version: 3,
13601367
metadata: {
13611368
Five: {__symbolic: 'class'},
13621369
},
13631370
},
13641371
'/tmp/src/reexport/src/origin30.d.ts': {
13651372
__symbolic: 'module',
1366-
version: 2,
1373+
version: 3,
13671374
metadata: {
13681375
Thirty: {__symbolic: 'class'},
13691376
},
13701377
},
13711378
'/tmp/src/reexport/src/originNone.d.ts': {
13721379
__symbolic: 'module',
1373-
version: 2,
1380+
version: 3,
13741381
metadata: {},
13751382
},
13761383
'/tmp/src/reexport/src/reexport2.d.ts': {
13771384
__symbolic: 'module',
1378-
version: 2,
1385+
version: 3,
13791386
metadata: {},
13801387
exports: [{from: './originNone'}, {from: './origin30'}]
13811388
}

tools/@angular/tsc-wrapped/src/collector.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import {Symbols} from './symbols';
1717
* A set of collector options to use when collecting metadata.
1818
*/
1919
export class CollectorOptions {
20+
/**
21+
* Version of the metadata to collect.
22+
*/
23+
version?: number;
24+
2025
/**
2126
* Collect a hidden field "$quoted$" in objects literals that record when the key was quoted in
2227
* the source.
@@ -430,7 +435,10 @@ export class MetadataCollector {
430435
else if (strict) {
431436
validateMetadata(sourceFile, nodeMap, metadata);
432437
}
433-
const result: ModuleMetadata = {__symbolic: 'module', version: VERSION, metadata};
438+
const result: ModuleMetadata = {
439+
__symbolic: 'module',
440+
version: this.options.version || VERSION, metadata
441+
};
434442
if (exports) result.exports = exports;
435443
return result;
436444
}

tools/@angular/tsc-wrapped/src/compiler_host.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ export class TsickleCompilerHost extends DelegatingHost {
110110
const IGNORED_FILES = /\.ngfactory\.js$|\.ngstyle\.js$/;
111111

112112
export class MetadataWriterHost extends DelegatingHost {
113-
private metadataCollector = new MetadataCollector();
113+
private metadataCollector = new MetadataCollector({quotedNames: true});
114+
private metadataCollector1 = new MetadataCollector({version: 1});
114115
constructor(delegate: ts.CompilerHost, private ngOptions: NgOptions) { super(delegate); }
115116

116117
private writeMetadata(emitFilePath: string, sourceFile: ts.SourceFile) {
@@ -120,18 +121,9 @@ export class MetadataWriterHost extends DelegatingHost {
120121
const path = emitFilePath.replace(/*DTS*/ /\.js$/, '.metadata.json');
121122
const metadata =
122123
this.metadataCollector.getMetadata(sourceFile, !!this.ngOptions.strictMetadataEmit);
123-
const metadatas: ModuleMetadata[] = [metadata];
124-
if (metadata && metadata.metadata) {
125-
if (metadata.version === 2) {
126-
// Also emit a version 1 so that older clients can consume new metadata files as well.
127-
// We can write the same data as version 2 is a strict super set.
128-
metadatas.push({
129-
__symbolic: metadata.__symbolic,
130-
exports: metadata.exports,
131-
metadata: metadata.metadata,
132-
version: 1
133-
});
134-
}
124+
const metadata1 = this.metadataCollector1.getMetadata(sourceFile, false);
125+
const metadatas: ModuleMetadata[] = [metadata, metadata1].filter(e => !!e);
126+
if (metadatas.length) {
135127
const metadataText = JSON.stringify(metadatas);
136128
writeFileSync(path, metadataText, {encoding: 'utf-8'});
137129
}

tools/@angular/tsc-wrapped/src/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// semantics of the file in an array. For example, when generating a version 2 file, if version 1
1616
// can accurately represent the metadata, generate both version 1 and version 2 in an array.
1717

18-
export const VERSION = 2;
18+
export const VERSION = 3;
1919

2020
export type MetadataEntry = ClassMetadata | FunctionMetadata | MetadataValue;
2121

tools/@angular/tsc-wrapped/test/collector.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('Collector', () => {
6767
const metadata = collector.getMetadata(sourceFile);
6868
expect(metadata).toEqual({
6969
__symbolic: 'module',
70-
version: 2,
70+
version: 3,
7171
metadata: {
7272
HeroDetailComponent: {
7373
__symbolic: 'class',
@@ -108,7 +108,7 @@ describe('Collector', () => {
108108
const metadata = collector.getMetadata(sourceFile);
109109
expect(metadata).toEqual({
110110
__symbolic: 'module',
111-
version: 2,
111+
version: 3,
112112
metadata: {
113113
AppComponent: {
114114
__symbolic: 'class',
@@ -162,7 +162,7 @@ describe('Collector', () => {
162162
const metadata = collector.getMetadata(sourceFile);
163163
expect(metadata).toEqual({
164164
__symbolic: 'module',
165-
version: 2,
165+
version: 3,
166166
metadata: {
167167
HEROES: [
168168
{'id': 11, 'name': 'Mr. Nice', '$quoted$': ['id', 'name']},
@@ -241,7 +241,7 @@ describe('Collector', () => {
241241
const metadata = collector.getMetadata(unsupported1);
242242
expect(metadata).toEqual({
243243
__symbolic: 'module',
244-
version: 2,
244+
version: 3,
245245
metadata: {
246246
a: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 16},
247247
b: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 19},
@@ -283,7 +283,7 @@ describe('Collector', () => {
283283
const metadata = collector.getMetadata(sourceFile);
284284
expect(metadata).toEqual({
285285
__symbolic: 'module',
286-
version: 2,
286+
version: 3,
287287
metadata: {
288288
SimpleClass: {__symbolic: 'class'},
289289
AbstractClass: {__symbolic: 'class'},
@@ -297,7 +297,7 @@ describe('Collector', () => {
297297
const metadata = collector.getMetadata(exportedFunctions);
298298
expect(metadata).toEqual({
299299
__symbolic: 'module',
300-
version: 2,
300+
version: 3,
301301
metadata: {
302302
one: {
303303
__symbolic: 'function',

0 commit comments

Comments
 (0)