polyfill.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. const { URL, domainToUnicode } = require('url')
  2. const CHAR_LOWERCASE_A = 97
  3. const CHAR_LOWERCASE_Z = 122
  4. const isWindows = process.platform === 'win32'
  5. class ERR_INVALID_FILE_URL_HOST extends TypeError {
  6. constructor (platform) {
  7. super(`File URL host must be "localhost" or empty on ${platform}`)
  8. this.code = 'ERR_INVALID_FILE_URL_HOST'
  9. }
  10. toString () {
  11. return `${this.name} [${this.code}]: ${this.message}`
  12. }
  13. }
  14. class ERR_INVALID_FILE_URL_PATH extends TypeError {
  15. constructor (msg) {
  16. super(`File URL path ${msg}`)
  17. this.code = 'ERR_INVALID_FILE_URL_PATH'
  18. }
  19. toString () {
  20. return `${this.name} [${this.code}]: ${this.message}`
  21. }
  22. }
  23. class ERR_INVALID_ARG_TYPE extends TypeError {
  24. constructor (name, actual) {
  25. super(`The "${name}" argument must be one of type string or an instance ` +
  26. `of URL. Received type ${typeof actual} ${actual}`)
  27. this.code = 'ERR_INVALID_ARG_TYPE'
  28. }
  29. toString () {
  30. return `${this.name} [${this.code}]: ${this.message}`
  31. }
  32. }
  33. class ERR_INVALID_URL_SCHEME extends TypeError {
  34. constructor (expected) {
  35. super(`The URL must be of scheme ${expected}`)
  36. this.code = 'ERR_INVALID_URL_SCHEME'
  37. }
  38. toString () {
  39. return `${this.name} [${this.code}]: ${this.message}`
  40. }
  41. }
  42. const isURLInstance = (input) => {
  43. return input != null && input.href && input.origin
  44. }
  45. const getPathFromURLWin32 = (url) => {
  46. const hostname = url.hostname
  47. let pathname = url.pathname
  48. for (let n = 0; n < pathname.length; n++) {
  49. if (pathname[n] === '%') {
  50. const third = pathname.codePointAt(n + 2) | 0x20
  51. if ((pathname[n + 1] === '2' && third === 102) ||
  52. (pathname[n + 1] === '5' && third === 99)) {
  53. throw new ERR_INVALID_FILE_URL_PATH('must not include encoded \\ or / characters')
  54. }
  55. }
  56. }
  57. pathname = pathname.replace(/\//g, '\\')
  58. pathname = decodeURIComponent(pathname)
  59. if (hostname !== '') {
  60. return `\\\\${domainToUnicode(hostname)}${pathname}`
  61. }
  62. const letter = pathname.codePointAt(1) | 0x20
  63. const sep = pathname[2]
  64. if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z ||
  65. (sep !== ':')) {
  66. throw new ERR_INVALID_FILE_URL_PATH('must be absolute')
  67. }
  68. return pathname.slice(1)
  69. }
  70. const getPathFromURLPosix = (url) => {
  71. if (url.hostname !== '') {
  72. throw new ERR_INVALID_FILE_URL_HOST(process.platform)
  73. }
  74. const pathname = url.pathname
  75. for (let n = 0; n < pathname.length; n++) {
  76. if (pathname[n] === '%') {
  77. const third = pathname.codePointAt(n + 2) | 0x20
  78. if (pathname[n + 1] === '2' && third === 102) {
  79. throw new ERR_INVALID_FILE_URL_PATH('must not include encoded / characters')
  80. }
  81. }
  82. }
  83. return decodeURIComponent(pathname)
  84. }
  85. const fileURLToPath = (path) => {
  86. if (typeof path === 'string') {
  87. path = new URL(path)
  88. } else if (!isURLInstance(path)) {
  89. throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path)
  90. }
  91. if (path.protocol !== 'file:') {
  92. throw new ERR_INVALID_URL_SCHEME('file')
  93. }
  94. return isWindows
  95. ? getPathFromURLWin32(path)
  96. : getPathFromURLPosix(path)
  97. }
  98. module.exports = fileURLToPath