/** * @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 */ /** * Create a {@link UrlResolver} with no package prefix. */ export function createUrlResolverWithoutPackagePrefix(): UrlResolver { return new UrlResolver(); } export function createOfflineCompileUrlResolver(): UrlResolver { return new UrlResolver('.'); } /** * Used by the {@link Compiler} when resolving HTML and CSS template URLs. * * This class can be overridden by the application developer to create custom behavior. * * See {@link Compiler} * * ## Example * * {@example compiler/ts/url_resolver/url_resolver.ts region='url_resolver'} * * @security When compiling templates at runtime, you must * ensure that the entire template comes from a trusted source. * Attacker-controlled data introduced by a template could expose your * application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security). */ export interface UrlResolver { resolve(baseUrl: string, url: string): string; } export interface UrlResolverCtor { new (packagePrefix?: string|null): UrlResolver; } export const UrlResolver: UrlResolverCtor = class UrlResolverImpl { constructor(private _packagePrefix: string|null = null) {} /** * Resolves the `url` given the `baseUrl`: * - when the `url` is null, the `baseUrl` is returned, * - if `url` is relative ('path/to/here', './path/to/here'), the resolved url is a combination of * `baseUrl` and `url`, * - if `url` is absolute (it has a scheme: 'http://', 'https://' or start with '/'), the `url` is * returned as is (ignoring the `baseUrl`) */ resolve(baseUrl: string, url: string): string { let resolvedUrl = url; if (baseUrl != null && baseUrl.length > 0) { resolvedUrl = _resolveUrl(baseUrl, resolvedUrl); } const resolvedParts = _split(resolvedUrl); let prefix = this._packagePrefix; if (prefix != null && resolvedParts != null && resolvedParts[_ComponentIndex.Scheme] == 'package') { let path = resolvedParts[_ComponentIndex.Path]; prefix = prefix.replace(/\/+$/, ''); path = path.replace(/^\/+/, ''); return `${prefix}/${path}`; } return resolvedUrl; } }; /** * Extract the scheme of a URL. */ export function getUrlScheme(url: string): string { const match = _split(url); return (match && match[_ComponentIndex.Scheme]) || ''; } // The code below is adapted from Traceur: // https://github.com/google/traceur-compiler/blob/9511c1dafa972bf0de1202a8a863bad02f0f95a8/src/runtime/url.js /** * Builds a URI string from already-encoded parts. * * No encoding is performed. Any component may be omitted as either null or * undefined. * * @param opt_scheme The scheme such as 'http'. * @param opt_userInfo The user name before the '@'. * @param opt_domain The domain such as 'www.google.com', already * URI-encoded. * @param opt_port The port number. * @param opt_path The path, already URI-encoded. If it is not * empty, it must begin with a slash. * @param opt_queryData The URI-encoded query data. * @param opt_fragment The URI-encoded fragment identifier. * @return The fully combined URI. */ function _buildFromEncodedParts( opt_scheme?: string, opt_userInfo?: string, opt_domain?: string, opt_port?: string, opt_path?: string, opt_queryData?: string, opt_fragment?: string): string { const out: string[] = []; if (opt_scheme != null) { out.push(opt_scheme + ':'); } if (opt_domain != null) { out.push('//'); if (opt_userInfo != null) { out.push(opt_userInfo + '@'); } out.push(opt_domain); if (opt_port != null) { out.push(':' + opt_port); } } if (opt_path != null) { out.push(opt_path); } if (opt_queryData != null) { out.push('?' + opt_queryData); } if (opt_fragment != null) { out.push('#' + opt_fragment); } return out.join(''); } /** * A regular expression for breaking a URI into its component parts. * * {@link http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#RFC2234} says * As the "first-match-wins" algorithm is identical to the "greedy" * disambiguation method used by POSIX regular expressions, it is natural and * commonplace to use a regular expression for parsing the potential five * components of a URI reference. * * The following line is the regular expression for breaking-down a * well-formed URI reference into its components. * *
* ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? * 12 3 4 5 6 7 8 9 ** * The numbers in the second line above are only to assist readability; they * indicate the reference points for each subexpression (i.e., each paired * parenthesis). We refer to the value matched for subexpression
* http://www.ics.uci.edu/pub/ietf/uri/#Related ** results in the following subexpression matches: *
* $1 = http: * $2 = http * $3 = //www.ics.uci.edu * $4 = www.ics.uci.edu * $5 = /pub/ietf/uri/ * $6 =* where* $7 = * $8 = #Related * $9 = Related *
* scheme = $2 * authority = $4 * path = $5 * query = $7 * fragment = $9 ** * The regular expression has been modified slightly to expose the * userInfo, domain, and port separately from the authority. * The modified version yields *
* $1 = http scheme * $2 =* @internal */ const _splitRe = new RegExp( '^' + '(?:' + '([^:/?#.]+)' + // scheme - ignore special characters // used by other URL parts such as :, // ?, /, #, and . ':)?' + '(?://' + '(?:([^/?#]*)@)?' + // userInfo '([\\w\\d\\-\\u0100-\\uffff.%]*)' + // domain - restrict to letters, // digits, dashes, dots, percent // escapes, and unicode characters. '(?::([0-9]+))?' + // port ')?' + '([^?#]+)?' + // path '(?:\\?([^#]*))?' + // query '(?:#(.*))?' + // fragment '$'); /** * The index of each URI component in the return value of goog.uri.utils.split. * @enum {number} */ enum _ComponentIndex { Scheme = 1, UserInfo, Domain, Port, Path, QueryData, Fragment } /** * Splits a URI into its component parts. * * Each component can be accessed via the component indices; for example: *userInfo -\ * $3 = www.ics.uci.edu domain | authority * $4 = port -/ * $5 = /pub/ietf/uri/ path * $6 = query without ? * $7 = Related fragment without # *
* goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA]; ** * @param uri The URI string to examine. * @return Each component still URI-encoded. * Each component that is present will contain the encoded value, whereas * components that are not present will be undefined or empty, depending * on the browser's regular expression implementation. Never null, since * arbitrary strings may still look like path names. */ function _split(uri: string): Array