Project

General

Profile

1
"use strict";
2
/**
3
 * @license
4
 * Copyright Google Inc. All Rights Reserved.
5
 *
6
 * Use of this source code is governed by an MIT-style license that can be
7
 * found in the LICENSE file at https://angular.io/license
8
 */
9
Object.defineProperty(exports, "__esModule", { value: true });
10
var path = require("path");
11
var ts = require("typescript");
12
var EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
13
var DTS = /\.d\.ts$/;
14
var NODE_MODULES = '/node_modules/';
15
var IS_GENERATED = /\.(ngfactory|ngstyle|ngsummary)$/;
16
var SHALLOW_IMPORT = /^((\w|-)+|(@(\w|-)+(\/(\w|-)+)+))$/;
17
function createModuleFilenameResolver(tsHost, options) {
18
    var host = createModuleFilenameResolverHost(tsHost);
19
    return options.rootDirs && options.rootDirs.length > 0 ?
20
        new MultipleRootDirModuleFilenameResolver(host, options) :
21
        new SingleRootDirModuleFilenameResolver(host, options);
22
}
23
exports.createModuleFilenameResolver = createModuleFilenameResolver;
24
var SingleRootDirModuleFilenameResolver = (function () {
25
    function SingleRootDirModuleFilenameResolver(host, options) {
26
        this.host = host;
27
        this.options = options;
28
        this.moduleFileNames = new Map();
29
        // normalize the path so that it never ends with '/'.
30
        this.basePath = path.normalize(path.join(options.basePath, '.')).replace(/\\/g, '/');
31
        this.genDir = path.normalize(path.join(options.genDir, '.')).replace(/\\/g, '/');
32
        var genPath = path.relative(this.basePath, this.genDir);
33
        this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
34
    }
35
    SingleRootDirModuleFilenameResolver.prototype.moduleNameToFileName = function (m, containingFile) {
36
        var key = m + ':' + (containingFile || '');
37
        var result = this.moduleFileNames.get(key) || null;
38
        if (!result) {
39
            if (!containingFile) {
40
                if (m.indexOf('.') === 0) {
41
                    throw new Error('Resolution of relative paths requires a containing file.');
42
                }
43
                // Any containing file gives the same result for absolute imports
44
                containingFile = this.getNgCanonicalFileName(path.join(this.basePath, 'index.ts'));
45
            }
46
            m = m.replace(EXT, '');
47
            var resolved = ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.host)
48
                .resolvedModule;
49
            result = resolved ? this.getNgCanonicalFileName(resolved.resolvedFileName) : null;
50
            this.moduleFileNames.set(key, result);
51
        }
52
        return result;
53
    };
54
    /**
55
     * We want a moduleId that will appear in import statements in the generated code.
56
     * These need to be in a form that system.js can load, so absolute file paths don't work.
57
     *
58
     * The `containingFile` is always in the `genDir`, where as the `importedFile` can be in
59
     * `genDir`, `node_module` or `basePath`.  The `importedFile` is either a generated file or
60
     * existing file.
61
     *
62
     *               | genDir   | node_module |  rootDir
63
     * --------------+----------+-------------+----------
64
     * generated     | relative |   relative  |   n/a
65
     * existing file |   n/a    |   absolute  |  relative(*)
66
     *
67
     * NOTE: (*) the relative path is computed depending on `isGenDirChildOfRootDir`.
68
     */
69
    SingleRootDirModuleFilenameResolver.prototype.fileNameToModuleName = function (importedFile, containingFile) {
70
        // If a file does not yet exist (because we compile it later), we still need to
71
        // assume it exists it so that the `resolve` method works!
72
        if (!this.host.fileExists(importedFile)) {
73
            this.host.assumeFileExists(importedFile);
74
        }
75
        containingFile = this.rewriteGenDirPath(containingFile);
76
        var containingDir = path.dirname(containingFile);
77
        // drop extension
78
        importedFile = importedFile.replace(EXT, '');
79
        var nodeModulesIndex = importedFile.indexOf(NODE_MODULES);
80
        var importModule = nodeModulesIndex === -1 ?
81
            null :
82
            importedFile.substring(nodeModulesIndex + NODE_MODULES.length);
83
        var isGeneratedFile = IS_GENERATED.test(importedFile);
84
        if (isGeneratedFile) {
85
            // rewrite to genDir path
86
            if (importModule) {
87
                // it is generated, therefore we do a relative path to the factory
88
                return this.dotRelative(containingDir, this.genDir + NODE_MODULES + importModule);
89
            }
90
            else {
91
                // assume that import is also in `genDir`
92
                importedFile = this.rewriteGenDirPath(importedFile);
93
                return this.dotRelative(containingDir, importedFile);
94
            }
95
        }
96
        else {
97
            // user code import
98
            if (importModule) {
99
                return importModule;
100
            }
101
            else {
102
                if (!this.isGenDirChildOfRootDir) {
103
                    // assume that they are on top of each other.
104
                    importedFile = importedFile.replace(this.basePath, this.genDir);
105
                }
106
                if (SHALLOW_IMPORT.test(importedFile)) {
107
                    return importedFile;
108
                }
109
                return this.dotRelative(containingDir, importedFile);
110
            }
111
        }
112
    };
113
    // We use absolute paths on disk as canonical.
114
    SingleRootDirModuleFilenameResolver.prototype.getNgCanonicalFileName = function (fileName) { return fileName; };
115
    SingleRootDirModuleFilenameResolver.prototype.assumeFileExists = function (fileName) { this.host.assumeFileExists(fileName); };
116
    SingleRootDirModuleFilenameResolver.prototype.dotRelative = function (from, to) {
117
        var rPath = path.relative(from, to).replace(/\\/g, '/');
118
        return rPath.startsWith('.') ? rPath : './' + rPath;
119
    };
120
    /**
121
     * Moves the path into `genDir` folder while preserving the `node_modules` directory.
122
     */
123
    SingleRootDirModuleFilenameResolver.prototype.rewriteGenDirPath = function (filepath) {
124
        var nodeModulesIndex = filepath.indexOf(NODE_MODULES);
125
        if (nodeModulesIndex !== -1) {
126
            // If we are in node_module, transplant them into `genDir`.
127
            return path.join(this.genDir, filepath.substring(nodeModulesIndex));
128
        }
129
        else {
130
            // pretend that containing file is on top of the `genDir` to normalize the paths.
131
            // we apply the `genDir` => `rootDir` delta through `rootDirPrefix` later.
132
            return filepath.replace(this.basePath, this.genDir);
133
        }
134
    };
135
    return SingleRootDirModuleFilenameResolver;
136
}());
137
/**
138
 * This version of the AotCompilerHost expects that the program will be compiled
139
 * and executed with a "path mapped" directory structure, where generated files
140
 * are in a parallel tree with the sources, and imported using a `./` relative
141
 * import. This requires using TS `rootDirs` option and also teaching the module
142
 * loader what to do.
143
 */
144
var MultipleRootDirModuleFilenameResolver = (function () {
145
    function MultipleRootDirModuleFilenameResolver(host, options) {
146
        this.host = host;
147
        this.options = options;
148
        // normalize the path so that it never ends with '/'.
149
        this.basePath = path.normalize(path.join(options.basePath, '.')).replace(/\\/g, '/');
150
    }
151
    MultipleRootDirModuleFilenameResolver.prototype.getNgCanonicalFileName = function (fileName) {
152
        if (!fileName)
153
            return fileName;
154
        // NB: the rootDirs should have been sorted longest-first
155
        for (var _i = 0, _a = this.options.rootDirs || []; _i < _a.length; _i++) {
156
            var dir = _a[_i];
157
            if (fileName.indexOf(dir) === 0) {
158
                fileName = fileName.substring(dir.length);
159
            }
160
        }
161
        return fileName;
162
    };
163
    MultipleRootDirModuleFilenameResolver.prototype.assumeFileExists = function (fileName) { this.host.assumeFileExists(fileName); };
164
    MultipleRootDirModuleFilenameResolver.prototype.moduleNameToFileName = function (m, containingFile) {
165
        if (!containingFile) {
166
            if (m.indexOf('.') === 0) {
167
                throw new Error('Resolution of relative paths requires a containing file.');
168
            }
169
            // Any containing file gives the same result for absolute imports
170
            containingFile = this.getNgCanonicalFileName(path.join(this.basePath, 'index.ts'));
171
        }
172
        for (var _i = 0, _a = this.options.rootDirs || ['']; _i < _a.length; _i++) {
173
            var root = _a[_i];
174
            var rootedContainingFile = path.join(root, containingFile);
175
            var resolved = ts.resolveModuleName(m, rootedContainingFile, this.options, this.host).resolvedModule;
176
            if (resolved) {
177
                if (this.options.traceResolution) {
178
                    console.error('resolve', m, containingFile, '=>', resolved.resolvedFileName);
179
                }
180
                return this.getNgCanonicalFileName(resolved.resolvedFileName);
181
            }
182
        }
183
        return null;
184
    };
185
    /**
186
     * We want a moduleId that will appear in import statements in the generated code.
187
     * These need to be in a form that system.js can load, so absolute file paths don't work.
188
     * Relativize the paths by checking candidate prefixes of the absolute path, to see if
189
     * they are resolvable by the moduleResolution strategy from the CompilerHost.
190
     */
191
    MultipleRootDirModuleFilenameResolver.prototype.fileNameToModuleName = function (importedFile, containingFile) {
192
        var _this = this;
193
        if (this.options.traceResolution) {
194
            console.error('getImportPath from containingFile', containingFile, 'to importedFile', importedFile);
195
        }
196
        // If a file does not yet exist (because we compile it later), we still need to
197
        // assume it exists so that the `resolve` method works!
198
        if (!this.host.fileExists(importedFile)) {
199
            if (this.options.rootDirs && this.options.rootDirs.length > 0) {
200
                this.host.assumeFileExists(path.join(this.options.rootDirs[0], importedFile));
201
            }
202
            else {
203
                this.host.assumeFileExists(importedFile);
204
            }
205
        }
206
        var resolvable = function (candidate) {
207
            var resolved = _this.moduleNameToFileName(candidate, importedFile);
208
            return resolved && resolved.replace(EXT, '') === importedFile.replace(EXT, '');
209
        };
210
        var importModuleName = importedFile.replace(EXT, '');
211
        var parts = importModuleName.split(path.sep).filter(function (p) { return !!p; });
212
        var foundRelativeImport;
213
        for (var index = parts.length - 1; index >= 0; index--) {
214
            var candidate_1 = parts.slice(index, parts.length).join(path.sep);
215
            if (resolvable(candidate_1)) {
216
                return candidate_1;
217
            }
218
            candidate_1 = '.' + path.sep + candidate_1;
219
            if (resolvable(candidate_1)) {
220
                foundRelativeImport = candidate_1;
221
            }
222
        }
223
        if (foundRelativeImport)
224
            return foundRelativeImport;
225
        // Try a relative import
226
        var candidate = path.relative(path.dirname(containingFile), importModuleName);
227
        if (resolvable(candidate)) {
228
            return candidate;
229
        }
230
        throw new Error("Unable to find any resolvable import for " + importedFile + " relative to " + containingFile);
231
    };
232
    return MultipleRootDirModuleFilenameResolver;
233
}());
234
function createModuleFilenameResolverHost(host) {
235
    var assumedExists = new Set();
236
    var resolveModuleNameHost = Object.create(host);
237
    // When calling ts.resolveModuleName, additional allow checks for .d.ts files to be done based on
238
    // checks for .ngsummary.json files, so that our codegen depends on fewer inputs and requires
239
    // to be called less often.
240
    // This is needed as we use ts.resolveModuleName in reflector_host and it should be able to
241
    // resolve summary file names.
242
    resolveModuleNameHost.fileExists = function (fileName) {
243
        if (assumedExists.has(fileName)) {
244
            return true;
245
        }
246
        if (host.fileExists(fileName)) {
247
            return true;
248
        }
249
        if (DTS.test(fileName)) {
250
            var base = fileName.substring(0, fileName.length - 5);
251
            return host.fileExists(base + '.ngsummary.json');
252
        }
253
        return false;
254
    };
255
    resolveModuleNameHost.assumeFileExists = function (fileName) { return assumedExists.add(fileName); };
256
    // Make sure we do not `host.realpath()` from TS as we do not want to resolve symlinks.
257
    // https://github.com/Microsoft/TypeScript/issues/9552
258
    resolveModuleNameHost.realpath = function (fileName) { return fileName; };
259
    return resolveModuleNameHost;
260
}
261
//# sourceMappingURL=module_filename_resolver.js.map
(8-8/18)