@@ -78,12 +78,29 @@ export function mapGetOrInsert<K, V>(map: Map<K, V>, key: K, defaultValue: V): V
78
78
79
79
export function cwdFilePathToURL ( path : string , base : string = document . baseURI ) : URL {
80
80
let url = new URL ( base ) ;
81
+ // Implicitly percent-encodes and doesn't trim path on the ends.
81
82
url . pathname = path ;
82
83
return url ;
83
84
}
84
85
85
86
export function cwdFilePathFromURL ( url : URL ) : string {
86
- return paths . stripRoot ( decodeURI ( url . pathname ) ) ;
87
+ // Why use decodeURIComponent here instead of decodeURI, you might ask? You
88
+ // see, the crucial difference between the two is that decodeURIComponent
89
+ // decodes every percent-encoded character without exceptions, while
90
+ // decodeURI, as the ES262 specification says, does not decode "escape
91
+ // sequences that could not have been introduced by encodeURI", which, in
92
+ // practice, means that it doesn't decode percent-encodings of these
93
+ // characters: ;/?:@&=+$,# . Now, how is this behavior useful in practice?
94
+ // Perhaps the intended usecase is to make URLs look nicer by decoding stuff
95
+ // like Unicode characters, yet preserving the validity and meaning of the
96
+ // original URL. But it may lead to obscure bugs in handling file paths
97
+ // because, albeit seldom used, all of the mentioned characters, with the
98
+ // exception of slash, are valid in filenames on UNIX, and, except colon and
99
+ // question mark, the rest is also valid on Windows, and so those characters
100
+ // will be kept undecoded. Here are some specification links:
101
+ // <https://tc39.es/ecma262/multipage/global-object.html#sec-decodeuri-encodeduri>
102
+ // <https://tc39.es/ecma262/multipage/global-object.html#sec-decodeuricomponent-encodeduricomponent>
103
+ return paths . stripRoot ( decodeURIComponent ( url . pathname ) ) ;
87
104
}
88
105
89
106
export function html < K extends keyof HTMLElementTagNameMap > (
0 commit comments