UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

381 lines (341 loc) 10.9 kB
/* * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @unrestricted */ Common.ParsedURL = class { /** * @param {string} url */ constructor(url) { this.isValid = false; this.url = url; this.scheme = ''; this.user = ''; this.host = ''; this.port = ''; this.path = ''; this.queryParams = ''; this.fragment = ''; this.folderPathComponents = ''; this.lastPathComponent = ''; const match = url.match(Common.ParsedURL._urlRegex()); if (match) { this.isValid = true; this.scheme = match[2].toLowerCase(); this.user = match[3]; this.host = match[4]; this.port = match[5]; this.path = match[6] || '/'; this.queryParams = match[7] || ''; this.fragment = match[8]; } else { if (this.url.startsWith('data:')) { this.scheme = 'data'; return; } if (this.url === 'about:blank') { this.scheme = 'about'; return; } this.path = this.url; } const lastSlashIndex = this.path.lastIndexOf('/'); if (lastSlashIndex !== -1) { this.folderPathComponents = this.path.substring(0, lastSlashIndex); this.lastPathComponent = this.path.substring(lastSlashIndex + 1); } else { this.lastPathComponent = this.path; } } /** * @param {string} fileSystemPath * @return {string} */ static platformPathToURL(fileSystemPath) { fileSystemPath = fileSystemPath.replace(/\\/g, '/'); if (!fileSystemPath.startsWith('file://')) { if (fileSystemPath.startsWith('/')) fileSystemPath = 'file://' + fileSystemPath; else fileSystemPath = 'file:///' + fileSystemPath; } return fileSystemPath; } /** * @param {string} fileURL * @param {boolean} isWindows * @return {string} */ static urlToPlatformPath(fileURL, isWindows) { console.assert(fileURL.startsWith('file://'), 'This must be a file URL.'); if (isWindows) return fileURL.substr('file:///'.length).replace(/\//g, '\\'); return fileURL.substr('file://'.length); } /** * @param {string} url * @return {string} */ static urlWithoutHash(url) { const hashIndex = url.indexOf('#'); if (hashIndex !== -1) return url.substr(0, hashIndex); return url; } /** * @return {!RegExp} */ static _urlRegex() { if (Common.ParsedURL._urlRegexInstance) return Common.ParsedURL._urlRegexInstance; // RegExp groups: // 1 - scheme, hostname, ?port // 2 - scheme (using the RFC3986 grammar) // 3 - ?user:password // 4 - hostname // 5 - ?port // 6 - ?path // 7 - ?query // 8 - ?fragment const schemeRegex = /([A-Za-z][A-Za-z0-9+.-]*):\/\//; const userRegex = /(?:([A-Za-z0-9\-._~%!$&'()*+,;=:]*)@)?/; const hostRegex = /((?:\[::\d?\])|(?:[^\s\/:]*))/; const portRegex = /(?::([\d]+))?/; const pathRegex = /(\/[^#?]*)?/; const queryRegex = /(?:\?([^#]*))?/; const fragmentRegex = /(?:#(.*))?/; Common.ParsedURL._urlRegexInstance = new RegExp( '^(' + schemeRegex.source + userRegex.source + hostRegex.source + portRegex.source + ')' + pathRegex.source + queryRegex.source + fragmentRegex.source + '$'); return Common.ParsedURL._urlRegexInstance; } /** * @param {string} url * @return {string} */ static extractPath(url) { const parsedURL = url.asParsedURL(); return parsedURL ? parsedURL.path : ''; } /** * @param {string} url * @return {string} */ static extractOrigin(url) { const parsedURL = url.asParsedURL(); return parsedURL ? parsedURL.securityOrigin() : ''; } /** * @param {string} url * @return {string} */ static extractExtension(url) { url = Common.ParsedURL.urlWithoutHash(url); const indexOfQuestionMark = url.indexOf('?'); if (indexOfQuestionMark !== -1) url = url.substr(0, indexOfQuestionMark); const lastIndexOfSlash = url.lastIndexOf('/'); if (lastIndexOfSlash !== -1) url = url.substr(lastIndexOfSlash + 1); const lastIndexOfDot = url.lastIndexOf('.'); if (lastIndexOfDot !== -1) { url = url.substr(lastIndexOfDot + 1); const lastIndexOfPercent = url.indexOf('%'); if (lastIndexOfPercent !== -1) return url.substr(0, lastIndexOfPercent); return url; } return ''; } /** * @param {string} url * @return {string} */ static extractName(url) { let index = url.lastIndexOf('/'); const pathAndQuery = index !== -1 ? url.substr(index + 1) : url; index = pathAndQuery.indexOf('?'); return index < 0 ? pathAndQuery : pathAndQuery.substr(0, index); } /** * @param {string} baseURL * @param {string} href * @return {?string} */ static completeURL(baseURL, href) { // Return special URLs as-is. const trimmedHref = href.trim(); if (trimmedHref.startsWith('data:') || trimmedHref.startsWith('blob:') || trimmedHref.startsWith('javascript:')) return href; // Return absolute URLs as-is. const parsedHref = trimmedHref.asParsedURL(); if (parsedHref && parsedHref.scheme) return trimmedHref; const parsedURL = baseURL.asParsedURL(); if (!parsedURL) return null; if (parsedURL.isDataURL()) return href; if (href.length > 1 && href.charAt(0) === '/' && href.charAt(1) === '/') { // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol). return parsedURL.scheme + ':' + href; } const securityOrigin = parsedURL.securityOrigin(); const pathText = parsedURL.path; const queryText = parsedURL.queryParams ? '?' + parsedURL.queryParams : ''; // Empty href resolves to a URL without fragment. if (!href.length) return securityOrigin + pathText + queryText; if (href.charAt(0) === '#') return securityOrigin + pathText + queryText + href; if (href.charAt(0) === '?') return securityOrigin + pathText + href; let hrefPath = href.match(/^[^#?]*/)[0]; const hrefSuffix = href.substring(hrefPath.length); if (hrefPath.charAt(0) !== '/') hrefPath = parsedURL.folderPathComponents + '/' + hrefPath; return securityOrigin + Runtime.normalizePath(hrefPath) + hrefSuffix; } /** * @param {string} string * @return {!{url: string, lineNumber: (number|undefined), columnNumber: (number|undefined)}} */ static splitLineAndColumn(string) { // Only look for line and column numbers in the path to avoid matching port numbers. const beforePathMatch = string.match(Common.ParsedURL._urlRegex()); let beforePath = ''; let pathAndAfter = string; if (beforePathMatch) { beforePath = beforePathMatch[1]; pathAndAfter = string.substring(beforePathMatch[1].length); } const lineColumnRegEx = /(?::(\d+))?(?::(\d+))?$/; const lineColumnMatch = lineColumnRegEx.exec(pathAndAfter); let lineNumber; let columnNumber; console.assert(lineColumnMatch); if (typeof(lineColumnMatch[1]) === 'string') { lineNumber = parseInt(lineColumnMatch[1], 10); // Immediately convert line and column to 0-based numbers. lineNumber = isNaN(lineNumber) ? undefined : lineNumber - 1; } if (typeof(lineColumnMatch[2]) === 'string') { columnNumber = parseInt(lineColumnMatch[2], 10); columnNumber = isNaN(columnNumber) ? undefined : columnNumber - 1; } return { url: beforePath + pathAndAfter.substring(0, pathAndAfter.length - lineColumnMatch[0].length), lineNumber: lineNumber, columnNumber: columnNumber }; } /** * @param {string} url * @return {boolean} */ static isRelativeURL(url) { return !(/^[A-Za-z][A-Za-z0-9+.-]*:/.test(url)); } get displayName() { if (this._displayName) return this._displayName; if (this.isDataURL()) return this.dataURLDisplayName(); if (this.isAboutBlank()) return this.url; this._displayName = this.lastPathComponent; if (!this._displayName) this._displayName = (this.host || '') + '/'; if (this._displayName === '/') this._displayName = this.url; return this._displayName; } /** * @return {string} */ dataURLDisplayName() { if (this._dataURLDisplayName) return this._dataURLDisplayName; if (!this.isDataURL()) return ''; this._dataURLDisplayName = this.url.trimEnd(20); return this._dataURLDisplayName; } /** * @return {boolean} */ isAboutBlank() { return this.url === 'about:blank'; } /** * @return {boolean} */ isDataURL() { return this.scheme === 'data'; } /** * @return {string} */ lastPathComponentWithFragment() { return this.lastPathComponent + (this.fragment ? '#' + this.fragment : ''); } /** * @return {string} */ domain() { if (this.isDataURL()) return 'data:'; return this.host + (this.port ? ':' + this.port : ''); } /** * @return {string} */ securityOrigin() { if (this.isDataURL()) return 'data:'; return this.scheme + '://' + this.domain(); } /** * @return {string} */ urlWithoutScheme() { if (this.scheme && this.url.startsWith(this.scheme + '://')) return this.url.substring(this.scheme.length + 3); return this.url; } }; /** * @return {?Common.ParsedURL} */ String.prototype.asParsedURL = function() { const parsedURL = new Common.ParsedURL(this.toString()); if (parsedURL.isValid) return parsedURL; return null; };