-
Notifications
You must be signed in to change notification settings - Fork 25.7k
/
Copy pathmetadata_reader.ts
129 lines (118 loc) Β· 4.44 KB
/
metadata_reader.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* @license
* Copyright Google Inc. 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 ts from 'typescript';
import {METADATA_VERSION, ModuleMetadata} from '../metadata';
import {DTS} from './util';
export interface MetadataReaderHost {
getSourceFileMetadata(filePath: string): ModuleMetadata|undefined;
cacheMetadata?(fileName: string): boolean;
fileExists(filePath: string): boolean;
readFile(filePath: string): string;
}
export interface MetadataReaderCache {
/**
* @internal
*/
data: Map<string, ModuleMetadata[]|undefined>;
}
export function createMetadataReaderCache(): MetadataReaderCache {
const data = new Map<string, ModuleMetadata[]|undefined>();
return {data};
}
export function readMetadata(
filePath: string, host: MetadataReaderHost, cache?: MetadataReaderCache): ModuleMetadata[]|
undefined {
let metadatas = cache && cache.data.get(filePath);
if (metadatas) {
return metadatas;
}
if (host.fileExists(filePath)) {
// If the file doesn't exists then we cannot return metadata for the file.
// This will occur if the user referenced a declared module for which no file
// exists for the module (i.e. jQuery or angularjs).
if (DTS.test(filePath)) {
metadatas = readMetadataFile(host, filePath);
if (!metadatas) {
// If there is a .d.ts file but no metadata file we need to produce a
// metadata from the .d.ts file as metadata files capture reexports
// (starting with v3).
metadatas = [upgradeMetadataWithDtsData(
host, {'__symbolic': 'module', 'version': 1, 'metadata': {}}, filePath)];
}
} else {
const metadata = host.getSourceFileMetadata(filePath);
metadatas = metadata ? [metadata] : [];
}
}
if (cache && (!host.cacheMetadata || host.cacheMetadata(filePath))) {
cache.data.set(filePath, metadatas);
}
return metadatas;
}
function readMetadataFile(host: MetadataReaderHost, dtsFilePath: string): ModuleMetadata[]|
undefined {
const metadataPath = dtsFilePath.replace(DTS, '.metadata.json');
if (!host.fileExists(metadataPath)) {
return undefined;
}
try {
const metadataOrMetadatas = JSON.parse(host.readFile(metadataPath));
const metadatas: ModuleMetadata[] = metadataOrMetadatas ?
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
[];
if (metadatas.length) {
let maxMetadata = metadatas.reduce((p, c) => p.version > c.version ? p : c);
if (maxMetadata.version < METADATA_VERSION) {
metadatas.push(upgradeMetadataWithDtsData(host, maxMetadata, dtsFilePath));
}
}
return metadatas;
} catch (e) {
console.error(`Failed to read JSON file ${metadataPath}`);
throw e;
}
}
function upgradeMetadataWithDtsData(
host: MetadataReaderHost, oldMetadata: ModuleMetadata, dtsFilePath: string): ModuleMetadata {
// patch v1 to v3 by adding exports and the `extends` clause.
// patch v3 to v4 by adding `interface` symbols for TypeAlias
let newMetadata: ModuleMetadata = {
'__symbolic': 'module',
'version': METADATA_VERSION,
'metadata': {...oldMetadata.metadata},
};
if (oldMetadata.exports) {
newMetadata.exports = oldMetadata.exports;
}
if (oldMetadata.importAs) {
newMetadata.importAs = oldMetadata.importAs;
}
if (oldMetadata.origins) {
newMetadata.origins = oldMetadata.origins;
}
const dtsMetadata = host.getSourceFileMetadata(dtsFilePath);
if (dtsMetadata) {
for (let prop in dtsMetadata.metadata) {
if (!newMetadata.metadata[prop]) {
newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
}
}
if (dtsMetadata['importAs']) newMetadata['importAs'] = dtsMetadata['importAs'];
// Only copy exports from exports from metadata prior to version 3.
// Starting with version 3 the collector began collecting exports and
// this should be redundant. Also, with bundler will rewrite the exports
// which will hoist the exports from modules referenced indirectly causing
// the imports to be different than the .d.ts files and using the .d.ts file
// exports would cause the StaticSymbolResolver to redirect symbols to the
// incorrect location.
if ((!oldMetadata.version || oldMetadata.version < 3) && dtsMetadata.exports) {
newMetadata.exports = dtsMetadata.exports;
}
}
return newMetadata;
}