ParsedURL.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. export class ParsedURL{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 isBlobUrl=this.url.startsWith('blob:');const urlToMatch=isBlobUrl?url.substring(5):url;const match=urlToMatch.match(ParsedURL._urlRegex());if(match){this.isValid=true;if(isBlobUrl){this._blobInnerScheme=match[2].toLowerCase();this.scheme='blob';}else{this.scheme=match[2].toLowerCase();}
  2. 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;}
  3. if(this.url.startsWith('blob:')){this.scheme='blob';return;}
  4. if(this.url==='about:blank'){this.scheme='about';return;}
  5. this.path=this.url;}
  6. 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;}}
  7. static platformPathToURL(fileSystemPath){fileSystemPath=fileSystemPath.replace(/\\/g,'/');if(!fileSystemPath.startsWith('file://')){if(fileSystemPath.startsWith('/')){fileSystemPath='file://'+fileSystemPath;}else{fileSystemPath='file:///'+fileSystemPath;}}
  8. return fileSystemPath;}
  9. static urlToPlatformPath(fileURL,isWindows){console.assert(fileURL.startsWith('file://'),'This must be a file URL.');if(isWindows){return fileURL.substr('file:///'.length).replace(/\//g,'\\');}
  10. return fileURL.substr('file://'.length);}
  11. static urlWithoutHash(url){const hashIndex=url.indexOf('#');if(hashIndex!==-1){return url.substr(0,hashIndex);}
  12. return url;}
  13. static _urlRegex(){if(ParsedURL._urlRegexInstance){return ParsedURL._urlRegexInstance;}
  14. 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=/(?:#(.*))?/;ParsedURL._urlRegexInstance=new RegExp('^('+schemeRegex.source+userRegex.source+hostRegex.source+portRegex.source+')'+pathRegex.source+
  15. queryRegex.source+fragmentRegex.source+'$');return ParsedURL._urlRegexInstance;}
  16. static extractPath(url){const parsedURL=url.asParsedURL();return parsedURL?parsedURL.path:'';}
  17. static extractOrigin(url){const parsedURL=url.asParsedURL();return parsedURL?parsedURL.securityOrigin():'';}
  18. static extractExtension(url){url=ParsedURL.urlWithoutHash(url);const indexOfQuestionMark=url.indexOf('?');if(indexOfQuestionMark!==-1){url=url.substr(0,indexOfQuestionMark);}
  19. const lastIndexOfSlash=url.lastIndexOf('/');if(lastIndexOfSlash!==-1){url=url.substr(lastIndexOfSlash+1);}
  20. const lastIndexOfDot=url.lastIndexOf('.');if(lastIndexOfDot!==-1){url=url.substr(lastIndexOfDot+1);const lastIndexOfPercent=url.indexOf('%');if(lastIndexOfPercent!==-1){return url.substr(0,lastIndexOfPercent);}
  21. return url;}
  22. return'';}
  23. 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);}
  24. static completeURL(baseURL,href){const trimmedHref=href.trim();if(trimmedHref.startsWith('data:')||trimmedHref.startsWith('blob:')||trimmedHref.startsWith('javascript:')||trimmedHref.startsWith('mailto:')){return href;}
  25. const parsedHref=trimmedHref.asParsedURL();if(parsedHref&&parsedHref.scheme){return trimmedHref;}
  26. const parsedURL=baseURL.asParsedURL();if(!parsedURL){return null;}
  27. if(parsedURL.isDataURL()){return href;}
  28. if(href.length>1&&href.charAt(0)==='/'&&href.charAt(1)==='/'){return parsedURL.scheme+':'+href;}
  29. const securityOrigin=parsedURL.securityOrigin();const pathText=parsedURL.path;const queryText=parsedURL.queryParams?'?'+parsedURL.queryParams:'';if(!href.length){return securityOrigin+pathText+queryText;}
  30. if(href.charAt(0)==='#'){return securityOrigin+pathText+queryText+href;}
  31. if(href.charAt(0)==='?'){return securityOrigin+pathText+href;}
  32. let hrefPath=href.match(/^[^#?]*/)[0];const hrefSuffix=href.substring(hrefPath.length);if(hrefPath.charAt(0)!=='/'){hrefPath=parsedURL.folderPathComponents+'/'+hrefPath;}
  33. return securityOrigin+Root.Runtime.normalizePath(hrefPath)+hrefSuffix;}
  34. static splitLineAndColumn(string){const beforePathMatch=string.match(ParsedURL._urlRegex());let beforePath='';let pathAndAfter=string;if(beforePathMatch){beforePath=beforePathMatch[1];pathAndAfter=string.substring(beforePathMatch[1].length);}
  35. 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);lineNumber=isNaN(lineNumber)?undefined:lineNumber-1;}
  36. if(typeof(lineColumnMatch[2])==='string'){columnNumber=parseInt(lineColumnMatch[2],10);columnNumber=isNaN(columnNumber)?undefined:columnNumber-1;}
  37. return{url:beforePath+pathAndAfter.substring(0,pathAndAfter.length-lineColumnMatch[0].length),lineNumber:lineNumber,columnNumber:columnNumber};}
  38. static isRelativeURL(url){return!(/^[A-Za-z][A-Za-z0-9+.-]*:/.test(url));}
  39. get displayName(){if(this._displayName){return this._displayName;}
  40. if(this.isDataURL()){return this.dataURLDisplayName();}
  41. if(this.isBlobURL()){return this.url;}
  42. if(this.isAboutBlank()){return this.url;}
  43. this._displayName=this.lastPathComponent;if(!this._displayName){this._displayName=(this.host||'')+'/';}
  44. if(this._displayName==='/'){this._displayName=this.url;}
  45. return this._displayName;}
  46. dataURLDisplayName(){if(this._dataURLDisplayName){return this._dataURLDisplayName;}
  47. if(!this.isDataURL()){return'';}
  48. this._dataURLDisplayName=this.url.trimEndWithMaxLength(20);return this._dataURLDisplayName;}
  49. isAboutBlank(){return this.url==='about:blank';}
  50. isDataURL(){return this.scheme==='data';}
  51. isBlobURL(){return this.url.startsWith('blob:');}
  52. lastPathComponentWithFragment(){return this.lastPathComponent+(this.fragment?'#'+this.fragment:'');}
  53. domain(){if(this.isDataURL()){return'data:';}
  54. return this.host+(this.port?':'+this.port:'');}
  55. securityOrigin(){if(this.isDataURL()){return'data:';}
  56. const scheme=this.isBlobURL()?this._blobInnerScheme:this.scheme;return scheme+'://'+this.domain();}
  57. urlWithoutScheme(){if(this.scheme&&this.url.startsWith(this.scheme+'://')){return this.url.substring(this.scheme.length+3);}
  58. return this.url;}}
  59. String.prototype.asParsedURL=function(){const parsedURL=new ParsedURL(this.toString());if(parsedURL.isValid){return parsedURL;}
  60. return null;};self.Common=self.Common||{};Common=Common||{};Common.ParsedURL=ParsedURL;