UNPKG

gltf-pipeline

Version:
122 lines (109 loc) 4.32 kB
'use strict'; const { Check, RuntimeError } = require('cesium'); const os = require('os'); const path = require('path'); const { domainToUnicode, URL } = require('url'); module.exports = { fileURLToPath: fileURLToPath, pathToFileURL: pathToFileURL }; const isWindows = os.platform() === 'win32'; const forwardSlashRegEx = /\//g; const CHAR_LOWERCASE_A = 97; const CHAR_LOWERCASE_Z = 122; const CHAR_FORWARD_SLASH = 47; const CHAR_BACKWARD_SLASH = 92; const percentRegEx = /%/g; const backslashRegEx = /\\/g; const newlineRegEx = /\n/g; const carriageReturnRegEx = /\r/g; const tabRegEx = /\t/g; // The following function is copied from Node.js implementation of url module // https://github.com/nodejs/node/blob/7237eaa3353aacf284289c8b59b0a5e0fa5744bb/lib/internal/url.js#L1345-L1383 // pathToFileURL & fileURLToPath were added in 10.12 so we want to maintain ability run under older versions. function fileURLToPath(path) { Check.defined('path', path); if (typeof path === 'string') { path = new URL(path); } if (path.protocol !== 'file:') { throw new RuntimeError('Expected path.protocol to start with file:'); } return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); } function pathToFileURL(filepath) { let resolved = path.resolve(filepath); // path.resolve strips trailing slashes so we must add them back const filePathLast = filepath.charCodeAt(filepath.length - 1); if ((filePathLast === CHAR_FORWARD_SLASH || isWindows && filePathLast === CHAR_BACKWARD_SLASH) && resolved[resolved.length - 1] !== path.sep) { resolved += '/'; } const outURL = new URL('file://'); if (resolved.includes('%')) { resolved = resolved.replace(percentRegEx, '%25'); } // in posix, "/" is a valid character in paths if (!isWindows && resolved.includes('\\')) { resolved = resolved.replace(backslashRegEx, '%5C'); } if (resolved.includes('\n')) { resolved = resolved.replace(newlineRegEx, '%0A'); } if (resolved.includes('\r')) { resolved = resolved.replace(carriageReturnRegEx, '%0D'); } if (resolved.includes('\t')) { resolved = resolved.replace(tabRegEx, '%09'); } outURL.pathname = resolved; return outURL; } function getPathFromURLWin32(url) { const hostname = url.hostname; let pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { const third = pathname.codePointAt(n + 2) | 0x20; if ((pathname[n + 1] === '2' && third === 102) || // 2f 2F / (pathname[n + 1] === '5' && third === 99)) { // 5c 5C \ throw new RuntimeError('file URL must not include encoded \\ or / characters'); } } } pathname = pathname.replace(forwardSlashRegEx, '\\'); pathname = decodeURIComponent(pathname); if (hostname !== '') { // If hostname is set, then we have a UNC path // Pass the hostname through domainToUnicode just in case // it is an IDN using punycode encoding. We do not need to worry // about percent encoding because the URL parser will have // already taken care of that for us. Note that this only // causes IDNs with an appropriate `xn--` prefix to be decoded. return `\\\\${domainToUnicode(hostname)}${pathname}`; } // Otherwise, it's a local path that requires a drive letter const letter = pathname.codePointAt(1) | 0x20; const sep = pathname[2]; if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || // a..z A..Z (sep !== ':')) { throw new RuntimeError('file URL must be absolute'); } return pathname.slice(1); } function getPathFromURLPosix(url) { if (url.hostname !== '') { throw new RuntimeError('Invalid platform'); } const pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { const third = pathname.codePointAt(n + 2) | 0x20; if (pathname[n + 1] === '2' && third === 102) { throw new RuntimeError('file URL must not include encoded \\ or / characters'); } } } return decodeURIComponent(pathname); }