MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

update url spec

+367 -32
+299 -32
examples/spec/url.js
··· 1 - import { test, summary } from './helpers.js'; 1 + import { test, testThrows, testDeep, summary } from './helpers.js'; 2 2 3 - console.log('URL Tests\n'); 3 + console.log('URL constructor\n'); 4 4 5 5 const url = new URL('https://user:pass@example.com:8080/path/to?query=value#hash'); 6 - 7 - test('URL href', url.href, 'https://user:pass@example.com:8080/path/to?query=value#hash'); 8 - test('URL protocol', url.protocol, 'https:'); 9 - test('URL username', url.username, 'user'); 10 - test('URL password', url.password, 'pass'); 11 - test('URL host', url.host, 'example.com:8080'); 12 - test('URL hostname', url.hostname, 'example.com'); 13 - test('URL port', url.port, '8080'); 14 - test('URL pathname', url.pathname, '/path/to'); 15 - test('URL search', url.search, '?query=value'); 16 - test('URL hash', url.hash, '#hash'); 17 - test('URL origin', url.origin, 'https://example.com:8080'); 6 + test('full URL href', url.href, 'https://user:pass@example.com:8080/path/to?query=value#hash'); 18 7 19 8 const url2 = new URL('/other', 'https://example.com'); 20 9 test('URL with base', url2.href, 'https://example.com/other'); 21 10 22 - const url3 = new URL('https://example.com'); 23 - url3.pathname = '/new/path'; 24 - test('URL set pathname', url3.pathname, '/new/path'); 11 + const url2b = new URL('foo', 'https://example.com/bar/baz'); 12 + test('URL with base resolves relative', url2b.href, 'https://example.com/bar/foo'); 13 + 14 + const url2c = new URL('//other.com/path', 'https://example.com'); 15 + test('URL with base protocol-relative', url2c.href, 'https://other.com/path'); 16 + 17 + testThrows('requires new', () => URL()); 18 + testThrows('invalid URL throws TypeError', () => new URL('not a url')); 19 + testThrows('invalid URL with base throws', () => new URL('http://%', 'https://example.com')); 20 + 21 + test('toString() returns href', url.toString(), url.href); 22 + test('toJSON() returns href', url.toJSON(), url.href); 23 + 24 + test('URL.canParse valid', URL.canParse('https://example.com'), true); 25 + test('URL.canParse invalid', URL.canParse('not a url'), false); 26 + test('URL.canParse with base', URL.canParse('/path', 'https://example.com'), true); 27 + 28 + const parsed = URL.parse('https://example.com/test'); 29 + test('URL.parse valid returns URL', parsed instanceof URL, true); 30 + test('URL.parse valid href', parsed.href, 'https://example.com/test'); 31 + test('URL.parse invalid returns null', URL.parse('not a url'), null); 32 + 33 + const parsedBase = URL.parse('/path', 'https://example.com'); 34 + test('URL.parse with base', parsedBase.href, 'https://example.com/path'); 35 + 36 + console.log('\nURL properties (getters)\n'); 37 + 38 + test('protocol', url.protocol, 'https:'); 39 + test('username', url.username, 'user'); 40 + test('password', url.password, 'pass'); 41 + test('hostname', url.hostname, 'example.com'); 42 + test('host (hostname:port)', url.host, 'example.com:8080'); 43 + test('port', url.port, '8080'); 44 + test('pathname', url.pathname, '/path/to'); 45 + test('search', url.search, '?query=value'); 46 + test('hash', url.hash, '#hash'); 47 + test('origin', url.origin, 'https://example.com:8080'); 48 + 49 + const urlNoSearch = new URL('https://example.com/path'); 50 + test('search empty string when absent', urlNoSearch.search, ''); 51 + 52 + const urlNoHash = new URL('https://example.com/path'); 53 + test('hash empty string when absent', urlNoHash.hash, ''); 54 + 55 + const urlDefaultHost = new URL('https://example.com/'); 56 + test('host without port', urlDefaultHost.host, 'example.com'); 57 + 58 + const urlNoUser = new URL('https://example.com/'); 59 + test('username empty when absent', urlNoUser.username, ''); 60 + test('password empty when absent', urlNoUser.password, ''); 61 + 62 + console.log('\nURL property setters\n'); 63 + 64 + const us1 = new URL('https://example.com/old'); 65 + us1.href = 'https://other.com/new?q=1'; 66 + test('set href reparses', us1.hostname, 'other.com'); 67 + test('set href pathname', us1.pathname, '/new'); 68 + test('set href search', us1.search, '?q=1'); 69 + 70 + const us2 = new URL('https://example.com/path'); 71 + us2.protocol = 'http:'; 72 + test('set protocol', us2.protocol, 'http:'); 73 + 74 + const us3 = new URL('https://example.com/path'); 75 + us3.hostname = 'other.com'; 76 + test('set hostname', us3.hostname, 'other.com'); 77 + test('set hostname updates host', us3.host, 'other.com'); 78 + 79 + const us4 = new URL('https://example.com/path'); 80 + us4.port = '9090'; 81 + test('set port', us4.port, '9090'); 82 + test('set port updates host', us4.host, 'example.com:9090'); 83 + 84 + const us4b = new URL('https://example.com:9090/path'); 85 + us4b.port = '443'; 86 + test('set default port elides', us4b.port, ''); 87 + 88 + const us5 = new URL('https://example.com/old'); 89 + us5.pathname = '/new/path'; 90 + test('set pathname', us5.pathname, '/new/path'); 91 + 92 + const us6 = new URL('https://example.com/path'); 93 + us6.search = '?x=1&y=2'; 94 + test('set search', us6.search, '?x=1&y=2'); 95 + 96 + const us6b = new URL('https://example.com/path?old=1'); 97 + us6b.search = ''; 98 + test('set search empty clears', us6b.search, ''); 99 + 100 + const us7 = new URL('https://example.com/path'); 101 + us7.hash = '#section'; 102 + test('set hash', us7.hash, '#section'); 103 + 104 + const us7b = new URL('https://example.com/path#old'); 105 + us7b.hash = ''; 106 + test('set hash empty clears', us7b.hash, ''); 107 + 108 + const us8 = new URL('https://example.com/path'); 109 + us8.username = 'alice'; 110 + test('set username', us8.username, 'alice'); 111 + 112 + const us9 = new URL('https://example.com/path'); 113 + us9.password = 'secret'; 114 + test('set password', us9.password, 'secret'); 115 + 116 + console.log('\ndefault port handling\n'); 117 + 118 + const httpDefault = new URL('http://example.com:80/'); 119 + test('http port 80 elided', httpDefault.port, ''); 120 + test('http port 80 host omits port', httpDefault.host, 'example.com'); 121 + 122 + const httpsDefault = new URL('https://example.com:443/'); 123 + test('https port 443 elided', httpsDefault.port, ''); 124 + test('https port 443 host omits port', httpsDefault.host, 'example.com'); 125 + 126 + const httpNonDefault = new URL('http://example.com:3000/'); 127 + test('http non-default port shown', httpNonDefault.port, '3000'); 128 + test('http non-default host includes port', httpNonDefault.host, 'example.com:3000'); 129 + 130 + const httpsNonDefault = new URL('https://example.com:8443/'); 131 + test('https non-default port shown', httpsNonDefault.port, '8443'); 132 + 133 + console.log('\nURLSearchParams constructor\n'); 134 + 135 + const sp0 = new URLSearchParams(); 136 + test('empty constructor toString', sp0.toString(), ''); 137 + test('empty constructor size', sp0.size, 0); 138 + 139 + const sp1 = new URLSearchParams('a=1&b=2'); 140 + test('from string get a', sp1.get('a'), '1'); 141 + test('from string get b', sp1.get('b'), '2'); 142 + test('from string size', sp1.size, 2); 143 + 144 + const sp1b = new URLSearchParams('?a=1&b=2'); 145 + test('from string with leading ?', sp1b.get('a'), '1'); 146 + test('from string with leading ? get b', sp1b.get('b'), '2'); 147 + 148 + const sp2 = new URLSearchParams([ 149 + ['a', '1'], 150 + ['b', '2'] 151 + ]); 152 + test('from array get a', sp2.get('a'), '1'); 153 + test('from array get b', sp2.get('b'), '2'); 154 + test('from array size', sp2.size, 2); 155 + 156 + const sp3 = new URLSearchParams({ a: '1', b: '2' }); 157 + test('from object get a', sp3.get('a'), '1'); 158 + test('from object get b', sp3.get('b'), '2'); 159 + 160 + const sp4 = new URLSearchParams(new URLSearchParams('x=9&y=8')); 161 + test('from another URLSearchParams get x', sp4.get('x'), '9'); 162 + test('from another URLSearchParams get y', sp4.get('y'), '8'); 163 + 164 + testThrows('pair with 1 element throws', () => new URLSearchParams([['only_key']])); 165 + testThrows('pair with 3 elements throws', () => new URLSearchParams([['a', 'b', 'c']])); 166 + 167 + console.log('\nURLSearchParams methods\n'); 168 + 169 + const sp = new URLSearchParams('a=1&b=2&a=3'); 170 + 171 + test('get returns first value', sp.get('a'), '1'); 172 + test('get missing returns null', sp.get('z'), null); 173 + 174 + testDeep('getAll returns all values', sp.getAll('a'), ['1', '3']); 175 + testDeep('getAll missing returns empty', sp.getAll('z'), []); 176 + 177 + test('has returns true', sp.has('a'), true); 178 + test('has missing returns false', sp.has('z'), false); 179 + 180 + test('has with matching value', sp.has('a', '1'), true); 181 + test('has with non-matching value', sp.has('a', '999'), false); 182 + 183 + const spSet = new URLSearchParams('a=1&b=2&a=3'); 184 + spSet.set('a', '99'); 185 + test('set replaces all', spSet.get('a'), '99'); 186 + test('set getAll length', spSet.getAll('a').length, 1); 187 + test('set preserves others', spSet.get('b'), '2'); 188 + 189 + const spApp = new URLSearchParams('a=1'); 190 + spApp.append('a', '2'); 191 + test('append adds entry', spApp.getAll('a').length, 2); 192 + test('append second value', spApp.getAll('a')[1], '2'); 193 + 194 + const spDel = new URLSearchParams('a=1&b=2&a=3'); 195 + spDel.delete('a'); 196 + test('delete removes all with name', spDel.has('a'), false); 197 + test('delete preserves others', spDel.has('b'), true); 198 + 199 + const spDelVal = new URLSearchParams('a=1&a=2&a=3'); 200 + spDelVal.delete('a', '2'); 201 + test('delete with value removes specific', spDelVal.getAll('a').length, 2); 202 + test('delete with value keeps others', spDelVal.get('a'), '1'); 203 + 204 + const spSort = new URLSearchParams('c=3&a=1&b=2&a=4'); 205 + spSort.sort(); 206 + test('sort first key', [...spSort.keys()][0], 'a'); 207 + test('sort second key', [...spSort.keys()][1], 'a'); 208 + test('sort third key', [...spSort.keys()][2], 'b'); 209 + test('sort fourth key', [...spSort.keys()][3], 'c'); 210 + test('sort stable: first a value', spSort.getAll('a')[0], '1'); 211 + test('sort stable: second a value', spSort.getAll('a')[1], '4'); 212 + 213 + test('toString serializes', new URLSearchParams('a=1&b=2').toString(), 'a=1&b=2'); 214 + test('toString empty', new URLSearchParams().toString(), ''); 215 + 216 + const spFE = new URLSearchParams('a=1&b=2'); 217 + const feResults = []; 218 + spFE.forEach((value, name) => feResults.push(`${name}=${value}`)); 219 + test('forEach visits all', feResults.length, 2); 220 + test('forEach first', feResults[0], 'a=1'); 221 + test('forEach second', feResults[1], 'b=2'); 222 + 223 + test('size getter', new URLSearchParams('a=1&b=2&c=3').size, 3); 224 + test( 225 + 'size after append', 226 + (() => { 227 + const s = new URLSearchParams('a=1'); 228 + s.append('b', '2'); 229 + return s.size; 230 + })(), 231 + 2 232 + ); 233 + 234 + console.log('\nURLSearchParams encoding\n'); 235 + 236 + test('space encoded as +', new URLSearchParams([['k', 'hello world']]).toString(), 'k=hello+world'); 237 + test('+ in value encoded as %2B', new URLSearchParams([['k', 'a+b']]).toString(), 'k=a%2Bb'); 238 + test('= in value encoded', new URLSearchParams([['k', 'a=b']]).toString(), 'k=a%3Db'); 239 + test('& in value encoded', new URLSearchParams([['k', 'a&b']]).toString(), 'k=a%26b'); 240 + 241 + test('* passes through', new URLSearchParams([['k', '*']]).toString(), 'k=*'); 242 + test('- passes through', new URLSearchParams([['k', '-']]).toString(), 'k=-'); 243 + test('. passes through', new URLSearchParams([['k', '.']]).toString(), 'k=.'); 244 + test('_ passes through', new URLSearchParams([['k', '_']]).toString(), 'k=_'); 245 + 246 + test('~ is percent-encoded', new URLSearchParams([['k', '~']]).toString(), 'k=%7E'); 247 + 248 + test('parsing: + becomes space', new URLSearchParams('k=hello+world').get('k'), 'hello world'); 249 + test('parsing: %20 becomes space', new URLSearchParams('k=hello%20world').get('k'), 'hello world'); 250 + test('parsing: %2B becomes +', new URLSearchParams('k=a%2Bb').get('k'), 'a+b'); 25 251 26 - const params = new URLSearchParams('a=1&b=2&a=3'); 27 - test('URLSearchParams get', params.get('a'), '1'); 28 - test('URLSearchParams getAll', params.getAll('a').length, 2); 29 - test('URLSearchParams has', params.has('b'), true); 30 - test('URLSearchParams has missing', params.has('c'), false); 252 + console.log('\nURLSearchParams iterator protocol\n'); 31 253 32 - params.set('c', '4'); 33 - test('URLSearchParams set', params.get('c'), '4'); 254 + const spi = new URLSearchParams('a=1&b=2'); 34 255 35 - params.append('d', '5'); 36 - test('URLSearchParams append', params.get('d'), '5'); 256 + const entries = [...spi.entries()]; 257 + test('entries length', entries.length, 2); 258 + test('entries first', entries[0][0], 'a'); 259 + test('entries first value', entries[0][1], '1'); 37 260 38 - params.delete('b'); 39 - test('URLSearchParams delete', params.has('b'), false); 261 + const keys = [...spi.keys()]; 262 + test('keys length', keys.length, 2); 263 + test('keys first', keys[0], 'a'); 264 + test('keys second', keys[1], 'b'); 40 265 41 - test('URLSearchParams toString', params.toString().includes('a=1'), true); 266 + const vals = [...spi.values()]; 267 + test('values length', vals.length, 2); 268 + test('values first', vals[0], '1'); 269 + test('values second', vals[1], '2'); 42 270 43 - const url4 = new URL('https://example.com?x=1'); 44 - url4.searchParams.set('y', '2'); 45 - test('URL searchParams', url4.search, '?x=1&y=2'); 271 + test('Symbol.iterator is entries', spi[Symbol.iterator] === spi.entries, true); 272 + 273 + const forOfResults = []; 274 + for (const [name, value] of new URLSearchParams('x=10&y=20')) { 275 + forOfResults.push(`${name}=${value}`); 276 + } 277 + test('for...of first', forOfResults[0], 'x=10'); 278 + test('for...of second', forOfResults[1], 'y=20'); 279 + 280 + const spread = [...new URLSearchParams('p=1&q=2')]; 281 + test('spread length', spread.length, 2); 282 + test('spread first pair', spread[0][0], 'p'); 283 + test('spread first value', spread[0][1], '1'); 284 + 285 + console.log('\nURL-URLSearchParams bidirectional sync\n'); 286 + 287 + const syncUrl = new URL('https://example.com/?a=1'); 288 + syncUrl.searchParams.set('b', '2'); 289 + test('searchParams mutation updates search', syncUrl.search, '?a=1&b=2'); 290 + 291 + syncUrl.searchParams.delete('a'); 292 + test('searchParams delete updates search', syncUrl.search, '?b=2'); 293 + 294 + syncUrl.searchParams.append('c', '3'); 295 + test('searchParams append updates search', syncUrl.search, '?b=2&c=3'); 296 + 297 + const syncUrl2 = new URL('https://example.com/?x=1'); 298 + syncUrl2.search = '?y=2&z=3'; 299 + test('set search updates searchParams get y', syncUrl2.searchParams.get('y'), '2'); 300 + test('set search updates searchParams get z', syncUrl2.searchParams.get('z'), '3'); 301 + test('set search removes old param', syncUrl2.searchParams.has('x'), false); 302 + 303 + const syncUrl3 = new URL('https://example.com/?a=1'); 304 + const paramsRef1 = syncUrl3.searchParams; 305 + syncUrl3.search = '?b=2'; 306 + const paramsRef2 = syncUrl3.searchParams; 307 + test('searchParams identity preserved', paramsRef1 === paramsRef2, true); 308 + 309 + console.log('\ntoStringTag\n'); 310 + 311 + test('URL toStringTag', Object.prototype.toString.call(new URL('https://example.com')), '[object URL]'); 312 + test('URLSearchParams toStringTag', Object.prototype.toString.call(new URLSearchParams()), '[object URLSearchParams]'); 46 313 47 314 summary();
+1
vendor/google-brotli.wrap
··· 7 7 patch_filename = google-brotli_1.1.0-3_patch.zip 8 8 patch_url = https://wrapdb.mesonbuild.com/v2/google-brotli_1.1.0-3/get_patch 9 9 patch_hash = 77e75a3bb019a4b653195a15af17cc65c56fb8cced2519154fce4e6bb43c74e2 10 + diff_files = patches/google-brotli-static-link.patch 10 11 wrapdb_version = 1.1.0-3 11 12 12 13 [provide]
+67
vendor/packagefiles/patches/google-brotli-static-link.patch
··· 1 + --- a/meson.build 2 + +++ b/meson.build 3 + @@ -65,16 +65,6 @@ 4 + bcs = [] 5 + bds = [] 6 + bes = [] 7 + -install = false 8 + -if get_option('default_library') == 'shared' 9 + - c_args += ['-DBROTLI_SHARED_COMPILATION'] 10 + - install = true 11 + - bcs = '-DBROTLICOMMON_SHARED_COMPILATION' 12 + - bds = '-DBROTLIDEC_SHARED_COMPILATION' 13 + - bes = '-DBROTLIENC_SHARED_COMPILATION' 14 + -elif get_option('default_library') == 'both' 15 + - error('both not yet supported.') 16 + -endif 17 + 18 + common_src = files( 19 + 'c/common/constants.c', 20 + @@ -85,14 +75,12 @@ 21 + 'c/common/transform.c', 22 + ) 23 + 24 + -libbrotli_common = library( 25 + +libbrotli_common = static_library( 26 + 'brotli_common', 27 + common_src, 28 + gnu_symbol_visibility: 'hidden', 29 + c_args: [c_args, bcs], 30 + include_directories: inc, 31 + - version: meson.project_version(), 32 + - install: install, 33 + ) 34 + 35 + brotli_common_dep = declare_dependency( 36 + @@ -107,14 +95,12 @@ 37 + 'c/dec/state.c', 38 + ) 39 + 40 + -libbrotli_decoder = library( 41 + +libbrotli_decoder = static_library( 42 + 'brotli_decoder', 43 + dec_src, 44 + gnu_symbol_visibility: 'hidden', 45 + c_args: [c_args, bds], 46 + dependencies: brotli_common_dep, 47 + - version: meson.project_version(), 48 + - install: install, 49 + ) 50 + 51 + enc_src = files( 52 + @@ -141,14 +127,12 @@ 53 + 'c/enc/utf8_util.c', 54 + ) 55 + 56 + -libbrotli_encoder = library( 57 + +libbrotli_encoder = static_library( 58 + 'brotli_encoder', 59 + enc_src, 60 + c_args: [c_args, bes], 61 + gnu_symbol_visibility: 'hidden', 62 + dependencies: [dep_m, brotli_common_dep], 63 + - version: meson.project_version(), 64 + - install: install, 65 + ) 66 + 67 + meson.override_dependency('libbrotlicommon', brotli_common_dep)