|
5 | 5 |
|
6 | 6 | "use strict"; |
7 | 7 |
|
| 8 | +const memorize = require("./memoize"); |
| 9 | + |
| 10 | +const getUrl = memorize(() => require("url")); |
| 11 | + |
8 | 12 | const PATH_QUERY_FRAGMENT_REGEXP = |
9 | 13 | /^(#?(?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/; |
10 | 14 | const ZERO_ESCAPE_REGEXP = /\0(.)/g; |
| 15 | +const FILE_REG_EXP = /file:/i; |
11 | 16 |
|
12 | 17 | /** |
13 | 18 | * @param {string} identifier identifier |
14 | | - * @returns {[string, string, string]|null} parsed identifier |
| 19 | + * @returns {[string, string, string] | null} parsed identifier |
15 | 20 | */ |
16 | 21 | function parseIdentifier(identifier) { |
17 | 22 | if (!identifier) { |
18 | 23 | return null; |
19 | 24 | } |
20 | 25 |
|
| 26 | + if (FILE_REG_EXP.test(identifier)) { |
| 27 | + identifier = getUrl().fileURLToPath(identifier); |
| 28 | + } |
| 29 | + |
21 | 30 | const firstEscape = identifier.indexOf("\0"); |
22 | | - if (firstEscape < 0) { |
23 | | - // Fast path for inputs that don't use \0 escaping. |
24 | | - const queryStart = identifier.indexOf("?"); |
25 | | - // Start at index 1 to ignore a possible leading hash. |
26 | | - const fragmentStart = identifier.indexOf("#", 1); |
27 | | - |
28 | | - if (fragmentStart < 0) { |
29 | | - if (queryStart < 0) { |
30 | | - // No fragment, no query |
31 | | - return [identifier, "", ""]; |
32 | | - } |
33 | | - // Query, no fragment |
34 | | - return [ |
35 | | - identifier.slice(0, queryStart), |
36 | | - identifier.slice(queryStart), |
37 | | - "", |
38 | | - ]; |
39 | | - } |
40 | 31 |
|
41 | | - if (queryStart < 0 || fragmentStart < queryStart) { |
42 | | - // Fragment, no query |
43 | | - return [ |
44 | | - identifier.slice(0, fragmentStart), |
45 | | - "", |
46 | | - identifier.slice(fragmentStart), |
47 | | - ]; |
48 | | - } |
| 32 | + // Handle `\0` |
| 33 | + if (firstEscape !== -1) { |
| 34 | + const match = PATH_QUERY_FRAGMENT_REGEXP.exec(identifier); |
| 35 | + |
| 36 | + if (!match) return null; |
49 | 37 |
|
50 | | - // Query and fragment |
51 | 38 | return [ |
52 | | - identifier.slice(0, queryStart), |
53 | | - identifier.slice(queryStart, fragmentStart), |
54 | | - identifier.slice(fragmentStart), |
| 39 | + match[1].replace(ZERO_ESCAPE_REGEXP, "$1"), |
| 40 | + match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : "", |
| 41 | + match[3] || "", |
55 | 42 | ]; |
56 | 43 | } |
57 | 44 |
|
58 | | - const match = PATH_QUERY_FRAGMENT_REGEXP.exec(identifier); |
| 45 | + // Fast path for inputs that don't use \0 escaping. |
| 46 | + const queryStart = identifier.indexOf("?"); |
| 47 | + // Start at index 1 to ignore a possible leading hash. |
| 48 | + const fragmentStart = identifier.indexOf("#", 1); |
59 | 49 |
|
60 | | - if (!match) return null; |
| 50 | + if (fragmentStart < 0) { |
| 51 | + if (queryStart < 0) { |
| 52 | + // No fragment, no query |
| 53 | + return [identifier, "", ""]; |
| 54 | + } |
| 55 | + |
| 56 | + // Query, no fragment |
| 57 | + return [identifier.slice(0, queryStart), identifier.slice(queryStart), ""]; |
| 58 | + } |
| 59 | + |
| 60 | + if (queryStart < 0 || fragmentStart < queryStart) { |
| 61 | + // Fragment, no query |
| 62 | + return [ |
| 63 | + identifier.slice(0, fragmentStart), |
| 64 | + "", |
| 65 | + identifier.slice(fragmentStart), |
| 66 | + ]; |
| 67 | + } |
61 | 68 |
|
| 69 | + // Query and fragment |
62 | 70 | return [ |
63 | | - match[1].replace(ZERO_ESCAPE_REGEXP, "$1"), |
64 | | - match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : "", |
65 | | - match[3] || "", |
| 71 | + identifier.slice(0, queryStart), |
| 72 | + identifier.slice(queryStart, fragmentStart), |
| 73 | + identifier.slice(fragmentStart), |
66 | 74 | ]; |
67 | 75 | } |
68 | 76 |
|
|
0 commit comments