UNPKG

5.95 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15Object.defineProperty(exports, "__esModule", { value: true });
16const pathlib = require("path");
17const path_1 = require("path");
18const url_1 = require("url");
19const vscode_uri_1 = require("vscode-uri");
20const utils_1 = require("../core/utils");
21const url_resolver_1 = require("./url-resolver");
22const isWindows = process.platform === 'win32';
23/**
24 * Resolves package-relative urls to a configured root directory.
25 *
26 * For file-relative URLs it does the normal URL resolution algorithm relative
27 * to the base url.
28 *
29 * It does no remapping of urls in source to urls on the filesystem, but a
30 * subclass can override modifyFsPath for this purpose.
31 */
32class FsUrlResolver extends url_resolver_1.UrlResolver {
33 constructor(packageDir,
34 // If provided, any URL which matches `host` will attempt to resolve
35 // to a `file` protocol URL regardless of the protocol represented in the
36 // URL to-be-resolved.
37 host,
38 // When attempting to resolve a protocol-relative URL (that is a URL which
39 // begins `//`), the default protocol to resolve to if the resolver can
40 // not produce a `file` URL.
41 protocol = 'https') {
42 super();
43 this.host = host;
44 this.protocol = protocol;
45 this.packageDir =
46 normalizeFsPath(pathlib.resolve(packageDir || process.cwd()));
47 this.packageUrl =
48 this.brandAsResolved(vscode_uri_1.default.file(this.packageDir).toString());
49 if (!this.packageUrl.endsWith('/')) {
50 this.packageUrl = this.brandAsResolved(this.packageUrl + '/');
51 }
52 }
53 resolve(firstHref, secondHref, _import) {
54 const [baseUrl = this.packageUrl, unresolvedHref] = this.getBaseAndUnresolved(firstHref, secondHref);
55 const resolvedHref = this.simpleUrlResolve(baseUrl, unresolvedHref, this.protocol);
56 if (resolvedHref === undefined) {
57 return undefined;
58 }
59 const url = utils_1.parseUrl(resolvedHref);
60 if (this.shouldHandleAsFileUrl(url)) {
61 return this.handleFileUrl(url, unresolvedHref);
62 }
63 return this.brandAsResolved(resolvedHref);
64 }
65 shouldHandleAsFileUrl(url) {
66 const isLocalFileUrl = url.protocol === 'file:' && (!url.host || url.host === 'localhost');
67 const isOurHost = url.host === this.host;
68 return isLocalFileUrl || isOurHost;
69 }
70 /**
71 * Take the given URL which is either a file:// url or a url with the
72 * configured hostname, and treat its pathname as though it points to a file
73 * on the local filesystem, producing a file:/// url.
74 *
75 * Also corrects sibling URLs like `../foo` to point to
76 * `./${component_dir}/foo`
77 */
78 handleFileUrl(url, unresolvedHref) {
79 let pathname;
80 const unresolvedUrl = utils_1.parseUrl(unresolvedHref);
81 if (unresolvedUrl.pathname && unresolvedUrl.pathname.startsWith('/') &&
82 unresolvedUrl.protocol !== 'file:') {
83 // Absolute urls point to the package root.
84 let unresolvedPathname;
85 try {
86 unresolvedPathname =
87 path_1.posix.normalize(decodeURIComponent(unresolvedUrl.pathname));
88 }
89 catch (e) {
90 return undefined; // undecodable url
91 }
92 pathname = pathlib.join(this.packageDir, unresolvedPathname);
93 }
94 else {
95 // Otherwise, consider the url that has already been resolved
96 // against the baseUrl
97 try {
98 pathname = path_1.posix.normalize(decodeURIComponent(url.pathname || ''));
99 }
100 catch (e) {
101 return undefined; // undecodable url
102 }
103 }
104 const path = this.modifyFsPath(this.filesystemPathForPathname(pathname));
105 // TODO(rictic): investigate moving to whatwg URLs internally:
106 // https://github.com/Polymer/polymer-analyzer/issues/804
107 // Re-encode URI, since it is expected we are emitting a relative URL.
108 const resolvedUrl = utils_1.parseUrl(vscode_uri_1.default.file(path).toString());
109 resolvedUrl.search = url.search;
110 resolvedUrl.hash = url.hash;
111 return this.brandAsResolved(url_1.format(resolvedUrl));
112 }
113 /**
114 * Overridable method, for subclasses that want to redirect some filesystem
115 * paths.
116 *
117 * @param fsPath An absolute path on the file system. Note that it will be
118 * OS-specific.
119 * @return An absolute path on the file system that we should resolve to.
120 */
121 modifyFsPath(fsPath) {
122 return fsPath;
123 }
124 relative(fromOrTo, maybeTo, _kind) {
125 const [from, to] = (maybeTo !== undefined) ? [fromOrTo, maybeTo] :
126 [this.packageUrl, fromOrTo];
127 return this.simpleUrlRelative(from, to);
128 }
129 filesystemPathForPathname(decodedPathname) {
130 return normalizeFsPath(vscode_uri_1.default.file(decodedPathname).fsPath);
131 }
132}
133exports.FsUrlResolver = FsUrlResolver;
134/**
135 * Normalizes slashes, `..`, `.`, and on Windows the capitalization of the
136 * drive letter.
137 */
138function normalizeFsPath(fsPath) {
139 fsPath = pathlib.normalize(fsPath);
140 if (isWindows && /^[a-z]:/.test(fsPath)) {
141 // Upper case the drive letter
142 fsPath = fsPath[0].toUpperCase() + fsPath.slice(1);
143 }
144 return fsPath;
145}
146//# sourceMappingURL=fs-url-resolver.js.map
\No newline at end of file